@js-recon/js-recon 1.4.1-beta.1 → 1.4.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-sync/capture-new.sh +61 -0
- package/.claude-sync/capture-scan.sh +55 -0
- package/.claude-sync/hooks/post-checkout +16 -0
- package/.claude-sync/hooks/pre-commit +3 -0
- package/.claude-sync/setup.sh +17 -0
- package/.claude-sync/sync.sh +64 -0
- package/.claude-sync/watch.sh +17 -0
- package/.github/workflows/build-and-prettify.yaml +40 -0
- package/.github/workflows/promote-js-recon.yml +129 -8
- package/.vscode/tasks.json +42 -0
- package/CHANGELOG.md +17 -0
- package/Dockerfile.w-rules +13 -0
- package/README.md +1 -1
- package/build/analyze/helpers/initRules.js +27 -5
- package/build/analyze/helpers/initRules.js.map +1 -1
- package/build/analyze/index.js +3 -2
- package/build/analyze/index.js.map +1 -1
- package/build/completion/index.js +17 -11
- package/build/completion/index.js.map +1 -1
- package/build/globalConfig.js +1 -1
- package/build/index.js +55 -23
- package/build/index.js.map +1 -1
- package/build/lazyLoad/generic/generic_jsMimeTypes.js +19 -0
- package/build/lazyLoad/generic/generic_jsMimeTypes.js.map +1 -0
- package/build/lazyLoad/index.js +1 -0
- package/build/lazyLoad/index.js.map +1 -1
- package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js +8 -2
- package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js.map +1 -1
- package/build/lazyLoad/techDetect/checkInterceptedEvidence.js +18 -0
- package/build/lazyLoad/techDetect/checkInterceptedEvidence.js.map +1 -0
- package/build/lazyLoad/techDetect/index.js +58 -13
- package/build/lazyLoad/techDetect/index.js.map +1 -1
- package/build/mcp/mcpServer.js +1 -2
- package/build/mcp/mcpServer.js.map +1 -1
- package/build/mcp/tools.js +1 -2
- package/build/mcp/tools.js.map +1 -1
- package/build/proxy/awsConfig.js +45 -0
- package/build/proxy/awsConfig.js.map +1 -0
- package/build/proxy/checkFeasibility.js.map +1 -0
- package/build/proxy/checkFireWallBlocking.js.map +1 -0
- package/build/proxy/configFile.js +31 -0
- package/build/proxy/configFile.js.map +1 -0
- package/build/{api_gateway → proxy}/genReq.js +4 -5
- package/build/proxy/genReq.js.map +1 -0
- package/build/proxy/genericProxy.js +21 -0
- package/build/proxy/genericProxy.js.map +1 -0
- package/build/proxy/index.js +421 -0
- package/build/proxy/index.js.map +1 -0
- package/build/proxy/oxylabsProxy.js +34 -0
- package/build/proxy/oxylabsProxy.js.map +1 -0
- package/build/proxy/resolveProxyConfig.js +38 -0
- package/build/proxy/resolveProxyConfig.js.map +1 -0
- package/build/report/utility/initGlobalReportDb.js +111 -0
- package/build/report/utility/initGlobalReportDb.js.map +1 -0
- package/build/report/utility/mergeDomainIntoGlobalDb.js +39 -0
- package/build/report/utility/mergeDomainIntoGlobalDb.js.map +1 -0
- package/build/run/index.js +110 -74
- package/build/run/index.js.map +1 -1
- package/build/run/interruptHandler.js +17 -1
- package/build/run/interruptHandler.js.map +1 -1
- package/build/utility/configureProxy.js +60 -0
- package/build/utility/configureProxy.js.map +1 -0
- package/build/utility/globals.js +108 -13
- package/build/utility/globals.js.map +1 -1
- package/build/utility/makeReq.js +103 -10
- package/build/utility/makeReq.js.map +1 -1
- package/package.json +5 -1
- package/CLAUDE.md +0 -641
- package/build/api_gateway/checkFeasibility.js.map +0 -1
- package/build/api_gateway/checkFireWallBlocking.js.map +0 -1
- package/build/api_gateway/genReq.js.map +0 -1
- package/build/api_gateway/index.js +0 -291
- package/build/api_gateway/index.js.map +0 -1
- /package/build/{api_gateway → proxy}/checkFeasibility.js +0 -0
- /package/build/{api_gateway → proxy}/checkFireWallBlocking.js +0 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Intercepts newly-added real CLAUDE.md files at commit time, redirects their
|
|
3
|
+
# content into the sibling js-recon-agentic-files repo on the current branch,
|
|
4
|
+
# and replaces them with a symlink — so they never land in this repo's history.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
JS_RECON_ROOT="$(git rev-parse --show-toplevel)"
|
|
8
|
+
AGENTIC_REPO_PATH="${JSR_AGENTIC_FILES_PATH:-$JS_RECON_ROOT/../js-recon-agentic-files}"
|
|
9
|
+
CURRENT_BRANCH="$(git -C "$JS_RECON_ROOT" symbolic-ref --short HEAD)"
|
|
10
|
+
|
|
11
|
+
cd "$JS_RECON_ROOT"
|
|
12
|
+
|
|
13
|
+
staged_real_claude_md="$(git diff --cached --name-only --diff-filter=ACM | grep -E '(^|/)CLAUDE\.md$' || true)"
|
|
14
|
+
|
|
15
|
+
if [ -z "$staged_real_claude_md" ]; then
|
|
16
|
+
exit 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
captured=0
|
|
20
|
+
while IFS= read -r f; do
|
|
21
|
+
[ -z "$f" ] && continue
|
|
22
|
+
|
|
23
|
+
if [ -L "$f" ]; then
|
|
24
|
+
continue
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
dest="$AGENTIC_REPO_PATH/$f"
|
|
28
|
+
mkdir -p "$(dirname "$dest")"
|
|
29
|
+
cp "$JS_RECON_ROOT/$f" "$dest"
|
|
30
|
+
|
|
31
|
+
(
|
|
32
|
+
cd "$AGENTIC_REPO_PATH"
|
|
33
|
+
if ! git show-ref --verify --quiet "refs/heads/$CURRENT_BRANCH"; then
|
|
34
|
+
git fetch origin --quiet || true
|
|
35
|
+
if git show-ref --verify --quiet "refs/remotes/origin/$CURRENT_BRANCH"; then
|
|
36
|
+
git checkout -q "$CURRENT_BRANCH"
|
|
37
|
+
else
|
|
38
|
+
git checkout -q -b "$CURRENT_BRANCH"
|
|
39
|
+
fi
|
|
40
|
+
else
|
|
41
|
+
git checkout -q "$CURRENT_BRANCH"
|
|
42
|
+
fi
|
|
43
|
+
git add "$f"
|
|
44
|
+
git commit -q -m "sync: capture $f from js-recon@$CURRENT_BRANCH"
|
|
45
|
+
git push -q origin "$CURRENT_BRANCH"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
git reset -q HEAD -- "$f" >/dev/null 2>&1 || true
|
|
49
|
+
rm -f "$JS_RECON_ROOT/$f"
|
|
50
|
+
ln -s "$dest" "$JS_RECON_ROOT/$f"
|
|
51
|
+
echo "[claude-sync] captured $f into js-recon-agentic-files (branch $CURRENT_BRANCH), replaced with symlink"
|
|
52
|
+
captured=1
|
|
53
|
+
done <<< "$staged_real_claude_md"
|
|
54
|
+
|
|
55
|
+
if [ "$captured" -eq 1 ]; then
|
|
56
|
+
echo "[claude-sync] commit aborted — CLAUDE.md file(s) were redirected to js-recon-agentic-files."
|
|
57
|
+
echo "[claude-sync] please 'git add' any remaining changes and re-run 'git commit'."
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
exit 0
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Walks the working tree for real (non-symlink) CLAUDE.md / .claude/skills /
|
|
3
|
+
# .claude/agents files and captures each into the sibling js-recon-agentic-files
|
|
4
|
+
# repo on the current branch, replacing it with a symlink. This is the primary
|
|
5
|
+
# "new file" trigger — .gitignore refuses `git add` on these paths outright, so
|
|
6
|
+
# a git-staged-diff-based hook (see capture-new.sh) never sees them; a
|
|
7
|
+
# filesystem scan is required.
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
JS_RECON_ROOT="$(git rev-parse --show-toplevel)"
|
|
11
|
+
AGENTIC_REPO_PATH="${JSR_AGENTIC_FILES_PATH:-$JS_RECON_ROOT/../js-recon-agentic-files}"
|
|
12
|
+
|
|
13
|
+
# Optional $1: attribute captures to this branch instead of the current HEAD.
|
|
14
|
+
# Used by the post-checkout hook, which only runs *after* HEAD has already
|
|
15
|
+
# moved to the new branch — git has no pre-checkout hook, so any real file
|
|
16
|
+
# left over from the branch being switched away from must be attributed to
|
|
17
|
+
# that branch explicitly, or it would be mis-captured onto the new branch.
|
|
18
|
+
CURRENT_BRANCH="${1:-$(git -C "$JS_RECON_ROOT" symbolic-ref --short HEAD 2>/dev/null || echo "")}"
|
|
19
|
+
|
|
20
|
+
if [ -z "$CURRENT_BRANCH" ] || [ ! -d "$AGENTIC_REPO_PATH/.git" ]; then
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
captured=0
|
|
25
|
+
while IFS= read -r f; do
|
|
26
|
+
[ -z "$f" ] && continue
|
|
27
|
+
rel="${f#$JS_RECON_ROOT/}"
|
|
28
|
+
dest="$AGENTIC_REPO_PATH/$rel"
|
|
29
|
+
|
|
30
|
+
mkdir -p "$(dirname "$dest")"
|
|
31
|
+
cp "$f" "$dest"
|
|
32
|
+
|
|
33
|
+
(
|
|
34
|
+
cd "$AGENTIC_REPO_PATH"
|
|
35
|
+
if git show-ref --verify --quiet "refs/heads/$CURRENT_BRANCH"; then
|
|
36
|
+
git checkout -q "$CURRENT_BRANCH"
|
|
37
|
+
elif git show-ref --verify --quiet "refs/remotes/origin/$CURRENT_BRANCH"; then
|
|
38
|
+
git checkout -q "$CURRENT_BRANCH"
|
|
39
|
+
else
|
|
40
|
+
git checkout -q -b "$CURRENT_BRANCH"
|
|
41
|
+
fi
|
|
42
|
+
git add "$rel"
|
|
43
|
+
git commit -q -m "sync: capture $rel from js-recon@$CURRENT_BRANCH"
|
|
44
|
+
git push -q origin "$CURRENT_BRANCH" 2>/dev/null || echo "[claude-sync] WARNING: push failed for $rel (branch may need 'git push -u origin $CURRENT_BRANCH' manually)"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
rm -f "$f"
|
|
48
|
+
ln -s "$dest" "$f"
|
|
49
|
+
echo "[claude-sync] captured $rel into js-recon-agentic-files (branch $CURRENT_BRANCH), replaced with symlink"
|
|
50
|
+
captured=1
|
|
51
|
+
done < <(find "$JS_RECON_ROOT" \( -name "CLAUDE.md" -o -path "*/.claude/skills/*" -o -path "*/.claude/agents/*" \) -not -path "*/.git/*" -not -path "*/node_modules/*" -not -path "*/build/*" -not -path "$AGENTIC_REPO_PATH/*" -type f)
|
|
52
|
+
|
|
53
|
+
if [ "$captured" -eq 0 ]; then
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# git post-checkout hook: re-syncs CLAUDE.md symlinks whenever a branch switch happens.
|
|
3
|
+
prev_head="$1"
|
|
4
|
+
new_head="$2"
|
|
5
|
+
branch_checkout="$3"
|
|
6
|
+
|
|
7
|
+
if [ "$branch_checkout" = "1" ]; then
|
|
8
|
+
ROOT="$(git rev-parse --show-toplevel)"
|
|
9
|
+
# Resolve which branch prev_head belongs to (the branch we're leaving) so any
|
|
10
|
+
# leftover real CLAUDE.md file gets attributed correctly — HEAD has already
|
|
11
|
+
# moved to the new branch by the time this hook runs, and git has no
|
|
12
|
+
# pre-checkout hook to capture beforehand.
|
|
13
|
+
prev_branch="$(git for-each-ref --points-at="$prev_head" --format='%(refname:short)' refs/heads/ 2>/dev/null | head -1)"
|
|
14
|
+
"$ROOT/.claude-sync/capture-scan.sh" "$prev_branch"
|
|
15
|
+
"$ROOT/.claude-sync/sync.sh"
|
|
16
|
+
fi
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# One-time collaborator setup: installs the git hooks and runs an initial sync.
|
|
3
|
+
# Requires js-recon-agentic-files to already be cloned as a sibling directory
|
|
4
|
+
# (../js-recon-agentic-files) or JSR_AGENTIC_FILES_PATH to point at it.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
JS_RECON_ROOT="$(git rev-parse --show-toplevel)"
|
|
8
|
+
|
|
9
|
+
chmod +x "$JS_RECON_ROOT/.claude-sync/sync.sh"
|
|
10
|
+
chmod +x "$JS_RECON_ROOT/.claude-sync/capture-new.sh"
|
|
11
|
+
chmod +x "$JS_RECON_ROOT/.claude-sync/hooks/post-checkout"
|
|
12
|
+
chmod +x "$JS_RECON_ROOT/.claude-sync/hooks/pre-commit"
|
|
13
|
+
|
|
14
|
+
git -C "$JS_RECON_ROOT" config core.hooksPath .claude-sync/hooks
|
|
15
|
+
|
|
16
|
+
echo "[claude-sync] hooksPath configured, running initial sync..."
|
|
17
|
+
"$JS_RECON_ROOT/.claude-sync/sync.sh"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Syncs CLAUDE.md / .claude/skills / .claude/agents symlinks from the sibling
|
|
3
|
+
# js-recon-agentic-files checkout to match the currently checked-out branch of
|
|
4
|
+
# this repo.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
JS_RECON_ROOT="$(git rev-parse --show-toplevel)"
|
|
8
|
+
AGENTIC_REPO_PATH="${JSR_AGENTIC_FILES_PATH:-$JS_RECON_ROOT/../js-recon-agentic-files}"
|
|
9
|
+
FALLBACK_BRANCH="${JSR_AGENTIC_FALLBACK_BRANCH:-dev}"
|
|
10
|
+
|
|
11
|
+
CURRENT_BRANCH="$(git -C "$JS_RECON_ROOT" symbolic-ref --short HEAD 2>/dev/null || echo "")"
|
|
12
|
+
|
|
13
|
+
if [ -z "$CURRENT_BRANCH" ]; then
|
|
14
|
+
echo "[claude-sync] detached HEAD, skipping sync"
|
|
15
|
+
exit 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
if [ ! -d "$AGENTIC_REPO_PATH/.git" ]; then
|
|
19
|
+
echo "[claude-sync] agentic-files repo not found at $AGENTIC_REPO_PATH — see js-recon-agentic-files/README.md for setup"
|
|
20
|
+
exit 0
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
(
|
|
24
|
+
cd "$AGENTIC_REPO_PATH"
|
|
25
|
+
git fetch origin --quiet
|
|
26
|
+
|
|
27
|
+
if git show-ref --verify --quiet "refs/remotes/origin/$CURRENT_BRANCH"; then
|
|
28
|
+
git checkout -B "$CURRENT_BRANCH" "origin/$CURRENT_BRANCH" --quiet
|
|
29
|
+
else
|
|
30
|
+
echo "[claude-sync] WARNING: no 'origin/$CURRENT_BRANCH' branch in agentic-files repo — falling back to 'origin/$FALLBACK_BRANCH'"
|
|
31
|
+
git checkout -B "$CURRENT_BRANCH" "origin/$FALLBACK_BRANCH" --quiet
|
|
32
|
+
fi
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# 1. Remove stale symlinks that point into the agentic checkout but whose target
|
|
36
|
+
# no longer exists on this branch (e.g. switched to a branch with fewer files).
|
|
37
|
+
while IFS= read -r link; do
|
|
38
|
+
target="$(readlink "$link")"
|
|
39
|
+
case "$target" in
|
|
40
|
+
"$AGENTIC_REPO_PATH"/*)
|
|
41
|
+
if [ ! -e "$target" ]; then
|
|
42
|
+
rm "$link"
|
|
43
|
+
echo "[claude-sync] removed stale symlink: ${link#$JS_RECON_ROOT/}"
|
|
44
|
+
fi
|
|
45
|
+
;;
|
|
46
|
+
esac
|
|
47
|
+
done < <(find "$JS_RECON_ROOT" -type l \( -name "CLAUDE.md" -o -path "*/.claude/skills/*" -o -path "*/.claude/agents/*" \) -not -path "*/.git/*" -not -path "*/node_modules/*" -not -path "*/build/*")
|
|
48
|
+
|
|
49
|
+
# 2. Create/update symlinks for every CLAUDE.md (and .claude/skills / .claude/agents
|
|
50
|
+
# entry) present on this branch in the agentic checkout.
|
|
51
|
+
while IFS= read -r src; do
|
|
52
|
+
rel="${src#$AGENTIC_REPO_PATH/}"
|
|
53
|
+
dest="$JS_RECON_ROOT/$rel"
|
|
54
|
+
|
|
55
|
+
if [ -e "$dest" ] && [ ! -L "$dest" ]; then
|
|
56
|
+
echo "[claude-sync] WARNING: $rel exists as a real (non-symlink) file — not overwriting. Stage it to trigger capture, or remove it manually."
|
|
57
|
+
continue
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
mkdir -p "$(dirname "$dest")"
|
|
61
|
+
ln -sf "$src" "$dest"
|
|
62
|
+
done < <(find "$AGENTIC_REPO_PATH" \( -name "CLAUDE.md" -o -path "*/.claude/skills/*" -o -path "*/.claude/agents/*" \) -type f -not -path "*/.git/*")
|
|
63
|
+
|
|
64
|
+
echo "[claude-sync] synced CLAUDE.md files for branch '$CURRENT_BRANCH'"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Background watcher intended to be run as a VS Code task (runOn: folderOpen,
|
|
3
|
+
# isBackground: true). Polls for new real CLAUDE.md files every few seconds and
|
|
4
|
+
# captures them immediately via capture-scan.sh, so a file created interactively
|
|
5
|
+
# (e.g. by an editor or an agent session) gets redirected without waiting for the
|
|
6
|
+
# next branch switch or commit.
|
|
7
|
+
set -uo pipefail
|
|
8
|
+
|
|
9
|
+
ROOT="$(git rev-parse --show-toplevel)"
|
|
10
|
+
INTERVAL="${JSR_WATCH_INTERVAL:-3}"
|
|
11
|
+
|
|
12
|
+
echo "[claude-sync] watching for new CLAUDE.md files (interval: ${INTERVAL}s)"
|
|
13
|
+
|
|
14
|
+
while true; do
|
|
15
|
+
"$ROOT/.claude-sync/capture-scan.sh"
|
|
16
|
+
sleep "$INTERVAL"
|
|
17
|
+
done
|
|
@@ -169,6 +169,9 @@ jobs:
|
|
|
169
169
|
with:
|
|
170
170
|
repository: js-recon/js-recon-rules
|
|
171
171
|
path: js-recon-rules
|
|
172
|
+
# Keep the checkout token out of js-recon-rules/.git/config — this
|
|
173
|
+
# context is consumed by later build/run steps (incl. Dockerfile.w-rules).
|
|
174
|
+
persist-credentials: false
|
|
172
175
|
|
|
173
176
|
- name: Set up Node.js
|
|
174
177
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
@@ -225,6 +228,40 @@ jobs:
|
|
|
225
228
|
path: output/localhost_3001/analyze.json
|
|
226
229
|
if-no-files-found: ignore
|
|
227
230
|
|
|
231
|
+
- name: Build the rules-bundled (-w-rules) image
|
|
232
|
+
run: docker build -f Dockerfile.w-rules --build-arg BASE_IMAGE=js-recon/js-recon -t js-recon/js-recon-w-rules .
|
|
233
|
+
|
|
234
|
+
- name: Run js-recon-w-rules via Docker against lab app (no rules mount, no -r)
|
|
235
|
+
run: |
|
|
236
|
+
set -o pipefail
|
|
237
|
+
mkdir -p output-w-rules
|
|
238
|
+
docker run --name js-recon-w-rules-run \
|
|
239
|
+
--network host \
|
|
240
|
+
--entrypoint /bin/bash \
|
|
241
|
+
js-recon/js-recon-w-rules \
|
|
242
|
+
-c 'printf "http://localhost:3001\n" > /tmp/urls.txt && node build/index.js run -u /tmp/urls.txt --no-sandbox -y -k' \
|
|
243
|
+
| tee docker-w-rules-run.log
|
|
244
|
+
docker cp js-recon-w-rules-run:/home/pptruser/output/. ./output-w-rules/ 2>/dev/null || true
|
|
245
|
+
docker rm js-recon-w-rules-run
|
|
246
|
+
|
|
247
|
+
- name: Verify the version check was actually skipped
|
|
248
|
+
run: |
|
|
249
|
+
grep -q "Rules version check disabled" docker-w-rules-run.log || {
|
|
250
|
+
echo "Expected log line confirming JS_RECON_DISABLE_RULES_VERSION_CHECK was honored not found"
|
|
251
|
+
exit 1
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
- name: Verify all rules fired (w-rules image)
|
|
255
|
+
run: node scripts/smoke-test.js output-w-rules/localhost_3001/analyze.json
|
|
256
|
+
|
|
257
|
+
- name: Upload w-rules analyze.json on failure
|
|
258
|
+
if: failure()
|
|
259
|
+
uses: actions/upload-artifact@v4
|
|
260
|
+
with:
|
|
261
|
+
name: analyze-json-docker-w-rules
|
|
262
|
+
path: output-w-rules/localhost_3001/analyze.json
|
|
263
|
+
if-no-files-found: ignore
|
|
264
|
+
|
|
228
265
|
integration-test-macos:
|
|
229
266
|
needs: build
|
|
230
267
|
runs-on: macos-latest
|
|
@@ -246,6 +283,9 @@ jobs:
|
|
|
246
283
|
with:
|
|
247
284
|
repository: js-recon/js-recon-rules
|
|
248
285
|
path: js-recon-rules
|
|
286
|
+
# Keep the checkout token out of js-recon-rules/.git/config — this
|
|
287
|
+
# context is consumed by later build/run steps (incl. Dockerfile.w-rules).
|
|
288
|
+
persist-credentials: false
|
|
249
289
|
|
|
250
290
|
- name: Set up Node.js
|
|
251
291
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
@@ -78,6 +78,15 @@ jobs:
|
|
|
78
78
|
packages: write
|
|
79
79
|
steps:
|
|
80
80
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
81
|
+
- name: Checkout js-recon-rules
|
|
82
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
83
|
+
with:
|
|
84
|
+
repository: js-recon/js-recon-rules
|
|
85
|
+
path: js-recon-rules
|
|
86
|
+
# Don't persist the checkout token into js-recon-rules/.git/config —
|
|
87
|
+
# Dockerfile.w-rules builds from this context and would otherwise bake
|
|
88
|
+
# the writable GHCR credential into an image layer.
|
|
89
|
+
persist-credentials: false
|
|
81
90
|
- uses: docker/login-action@v3
|
|
82
91
|
with:
|
|
83
92
|
registry: ghcr.io
|
|
@@ -103,6 +112,22 @@ jobs:
|
|
|
103
112
|
env:
|
|
104
113
|
VERSION: ${{ inputs.version }}
|
|
105
114
|
|
|
115
|
+
- name: Build and push the rules-bundled (-w-rules) variant
|
|
116
|
+
run: |
|
|
117
|
+
# layer js-recon-rules on top of the image just built/pushed above
|
|
118
|
+
docker build -f Dockerfile.w-rules --build-arg BASE_IMAGE=ghcr.io/js-recon/js-recon:$VERSION -t ghcr.io/js-recon/js-recon:$VERSION-w-rules .
|
|
119
|
+
|
|
120
|
+
TAG="latest"
|
|
121
|
+
[[ "$VERSION" == *"beta"* ]] && TAG="beta"
|
|
122
|
+
[[ "$VERSION" == *"alpha"* ]] && TAG="alpha"
|
|
123
|
+
|
|
124
|
+
docker tag ghcr.io/js-recon/js-recon:$VERSION-w-rules ghcr.io/js-recon/js-recon:$TAG-w-rules
|
|
125
|
+
|
|
126
|
+
docker push ghcr.io/js-recon/js-recon:$VERSION-w-rules
|
|
127
|
+
docker push ghcr.io/js-recon/js-recon:$TAG-w-rules
|
|
128
|
+
env:
|
|
129
|
+
VERSION: ${{ inputs.version }}
|
|
130
|
+
|
|
106
131
|
verify-npm-install:
|
|
107
132
|
runs-on: ubuntu-latest
|
|
108
133
|
permissions:
|
|
@@ -140,7 +165,7 @@ jobs:
|
|
|
140
165
|
npm start &
|
|
141
166
|
|
|
142
167
|
- name: Wait for app to be ready
|
|
143
|
-
run: timeout 60 bash -c 'until curl -sf http://localhost:3001 > /dev/null; do sleep 2; done'
|
|
168
|
+
run: timeout 60 bash -c 'until curl -sf --max-time 2 http://localhost:3001 > /dev/null; do sleep 2; done'
|
|
144
169
|
|
|
145
170
|
- name: Run installed js-recon against the lab app
|
|
146
171
|
run: |
|
|
@@ -194,17 +219,23 @@ jobs:
|
|
|
194
219
|
npm start &
|
|
195
220
|
|
|
196
221
|
- name: Wait for app to be ready
|
|
197
|
-
run: timeout 60 bash -c 'until curl -sf http://localhost:3001 > /dev/null; do sleep 2; done'
|
|
222
|
+
run: timeout 60 bash -c 'until curl -sf --max-time 2 http://localhost:3001 > /dev/null; do sleep 2; done'
|
|
198
223
|
|
|
199
224
|
- name: Run containerized js-recon against the lab app
|
|
200
225
|
run: |
|
|
226
|
+
# The release image runs as the non-root `pptruser` (see Dockerfile.release),
|
|
227
|
+
# so a bind-mounted host directory landing inside its home dir inherits the
|
|
228
|
+
# host-side owner/perms and can be unwritable to that user. Mount outside
|
|
229
|
+
# $HOME with permissive perms and point js-recon at it explicitly via `-o`
|
|
230
|
+
# rather than relying on its default CWD-relative output path.
|
|
201
231
|
mkdir -p /tmp/docker-output
|
|
232
|
+
chmod 777 /tmp/docker-output
|
|
202
233
|
echo "http://localhost:3001" > /tmp/docker-smoke-urls.txt
|
|
203
234
|
docker run --rm --network host \
|
|
204
|
-
-v /tmp/docker-output:/
|
|
205
|
-
-v /tmp/docker-smoke-urls.txt:/
|
|
235
|
+
-v /tmp/docker-output:/tmp/js-recon-output \
|
|
236
|
+
-v /tmp/docker-smoke-urls.txt:/tmp/urls.txt \
|
|
206
237
|
ghcr.io/js-recon/js-recon:${VERSION} \
|
|
207
|
-
run -u /
|
|
238
|
+
run -u /tmp/urls.txt -o /tmp/js-recon-output --no-sandbox -y -k
|
|
208
239
|
env:
|
|
209
240
|
VERSION: ${{ inputs.version }}
|
|
210
241
|
|
|
@@ -213,6 +244,72 @@ jobs:
|
|
|
213
244
|
test -n "$(find /tmp/docker-output -name analyze.json)" || { echo "analyze.json missing"; exit 1; }
|
|
214
245
|
test -n "$(find /tmp/docker-output -name js-recon.db)" || { echo "js-recon.db missing"; exit 1; }
|
|
215
246
|
|
|
247
|
+
verify-docker-w-rules-install:
|
|
248
|
+
runs-on: ubuntu-latest
|
|
249
|
+
needs: publish-ghcr
|
|
250
|
+
permissions:
|
|
251
|
+
contents: read
|
|
252
|
+
packages: read
|
|
253
|
+
steps:
|
|
254
|
+
- name: Checkout js-recon
|
|
255
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
256
|
+
|
|
257
|
+
- name: Checkout js-recon-labs
|
|
258
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
259
|
+
with:
|
|
260
|
+
repository: js-recon/js-recon-labs
|
|
261
|
+
path: js-recon-labs
|
|
262
|
+
persist-credentials: false
|
|
263
|
+
|
|
264
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
265
|
+
with:
|
|
266
|
+
node-version: "22"
|
|
267
|
+
|
|
268
|
+
- uses: docker/login-action@v3
|
|
269
|
+
with:
|
|
270
|
+
registry: ghcr.io
|
|
271
|
+
username: ${{ github.actor }}
|
|
272
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
273
|
+
|
|
274
|
+
- name: Install and start vulnerable app
|
|
275
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
276
|
+
run: |
|
|
277
|
+
npm ci
|
|
278
|
+
npm run build
|
|
279
|
+
npm start &
|
|
280
|
+
|
|
281
|
+
- name: Wait for app to be ready
|
|
282
|
+
run: timeout 60 bash -c 'until curl -sf --max-time 2 http://localhost:3001 > /dev/null; do sleep 2; done'
|
|
283
|
+
|
|
284
|
+
- name: Run the rules-bundled image against the lab app (no rules mount, no -r)
|
|
285
|
+
run: |
|
|
286
|
+
set -o pipefail
|
|
287
|
+
# Deliberately don't mount any rules directory and don't pass -r — the
|
|
288
|
+
# -w-rules image must be able to analyze using only what's baked in.
|
|
289
|
+
mkdir -p /tmp/docker-w-rules-output
|
|
290
|
+
chmod 777 /tmp/docker-w-rules-output
|
|
291
|
+
echo "http://localhost:3001" > /tmp/docker-w-rules-smoke-urls.txt
|
|
292
|
+
docker run --network host \
|
|
293
|
+
--name js-recon-w-rules-run \
|
|
294
|
+
-v /tmp/docker-w-rules-output:/tmp/js-recon-output \
|
|
295
|
+
-v /tmp/docker-w-rules-smoke-urls.txt:/tmp/urls.txt \
|
|
296
|
+
ghcr.io/js-recon/js-recon:${VERSION}-w-rules \
|
|
297
|
+
run -u /tmp/urls.txt -o /tmp/js-recon-output --no-sandbox -y -k \
|
|
298
|
+
| tee /tmp/docker-w-rules-run.log
|
|
299
|
+
docker rm js-recon-w-rules-run
|
|
300
|
+
env:
|
|
301
|
+
VERSION: ${{ inputs.version }}
|
|
302
|
+
|
|
303
|
+
- name: Verify the version check was actually skipped
|
|
304
|
+
run: |
|
|
305
|
+
grep -q "Rules version check disabled" /tmp/docker-w-rules-run.log || {
|
|
306
|
+
echo "Expected log line confirming JS_RECON_DISABLE_RULES_VERSION_CHECK was honored not found"
|
|
307
|
+
exit 1
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
- name: Verify all rules fired
|
|
311
|
+
run: node scripts/smoke-test.js "$(find /tmp/docker-w-rules-output -name analyze.json | head -n1)"
|
|
312
|
+
|
|
216
313
|
verify-brew-install:
|
|
217
314
|
runs-on: macos-latest
|
|
218
315
|
needs: update-homebrew-tap
|
|
@@ -249,9 +346,22 @@ jobs:
|
|
|
249
346
|
env:
|
|
250
347
|
VERSION: ${{ inputs.version }}
|
|
251
348
|
|
|
349
|
+
- name: Resolve js-recon binary path
|
|
350
|
+
id: bin
|
|
351
|
+
run: |
|
|
352
|
+
# js-recon-alpha/js-recon-beta are keg-only (they share the `js-recon`
|
|
353
|
+
# binary name with the stable formula), so brew never symlinks them
|
|
354
|
+
# into PATH. Resolve the keg path directly instead of relying on PATH.
|
|
355
|
+
KEG_BIN="$(brew --prefix)/opt/${{ matrix.formula }}/bin/js-recon"
|
|
356
|
+
if [[ -x "$KEG_BIN" ]]; then
|
|
357
|
+
echo "bin=$KEG_BIN" >> "$GITHUB_OUTPUT"
|
|
358
|
+
else
|
|
359
|
+
echo "bin=js-recon" >> "$GITHUB_OUTPUT"
|
|
360
|
+
fi
|
|
361
|
+
|
|
252
362
|
- name: Verify installed version
|
|
253
363
|
run: |
|
|
254
|
-
INSTALLED=$(
|
|
364
|
+
INSTALLED=$("$BIN" -V)
|
|
255
365
|
echo "Installed: ${INSTALLED}"
|
|
256
366
|
if [[ "${{ matrix.formula }}" == "${{ steps.expected.outputs.formula }}" ]]; then
|
|
257
367
|
[[ "$INSTALLED" == *"$VERSION"* ]] || { echo "Version mismatch: expected ${VERSION} in ${{ matrix.formula }}"; exit 1; }
|
|
@@ -260,6 +370,7 @@ jobs:
|
|
|
260
370
|
fi
|
|
261
371
|
env:
|
|
262
372
|
VERSION: ${{ inputs.version }}
|
|
373
|
+
BIN: ${{ steps.bin.outputs.bin }}
|
|
263
374
|
|
|
264
375
|
- name: Install and start vulnerable app
|
|
265
376
|
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
@@ -269,12 +380,22 @@ jobs:
|
|
|
269
380
|
npm start &
|
|
270
381
|
|
|
271
382
|
- name: Wait for app to be ready
|
|
272
|
-
run:
|
|
383
|
+
run: |
|
|
384
|
+
SECONDS=0
|
|
385
|
+
until curl -sf --max-time 2 http://localhost:3001 > /dev/null; do
|
|
386
|
+
if (( SECONDS > 60 )); then
|
|
387
|
+
echo "Timed out waiting for app to be ready"
|
|
388
|
+
exit 1
|
|
389
|
+
fi
|
|
390
|
+
sleep 2
|
|
391
|
+
done
|
|
273
392
|
|
|
274
393
|
- name: Run installed js-recon against the lab app
|
|
275
394
|
run: |
|
|
276
395
|
echo "http://localhost:3001" > /tmp/brew-smoke-urls.txt
|
|
277
|
-
|
|
396
|
+
"$BIN" run -u /tmp/brew-smoke-urls.txt -y -k
|
|
397
|
+
env:
|
|
398
|
+
BIN: ${{ steps.bin.outputs.bin }}
|
|
278
399
|
|
|
279
400
|
- name: Verify expected output files exist
|
|
280
401
|
run: |
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "2.0.0",
|
|
3
|
+
"tasks": [
|
|
4
|
+
{
|
|
5
|
+
"label": "claude-sync: sync CLAUDE.md files",
|
|
6
|
+
"type": "shell",
|
|
7
|
+
"command": "${workspaceFolder}/.claude-sync/sync.sh",
|
|
8
|
+
"runOptions": {
|
|
9
|
+
"runOn": "folderOpen"
|
|
10
|
+
},
|
|
11
|
+
"presentation": {
|
|
12
|
+
"reveal": "silent",
|
|
13
|
+
"panel": "dedicated"
|
|
14
|
+
},
|
|
15
|
+
"problemMatcher": []
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"label": "claude-sync: watch for new CLAUDE.md files",
|
|
19
|
+
"type": "shell",
|
|
20
|
+
"command": "${workspaceFolder}/.claude-sync/watch.sh",
|
|
21
|
+
"isBackground": true,
|
|
22
|
+
"runOptions": {
|
|
23
|
+
"runOn": "folderOpen"
|
|
24
|
+
},
|
|
25
|
+
"presentation": {
|
|
26
|
+
"reveal": "silent",
|
|
27
|
+
"panel": "dedicated"
|
|
28
|
+
},
|
|
29
|
+
"problemMatcher": {
|
|
30
|
+
"pattern": {
|
|
31
|
+
"regexp": "^(.*)$",
|
|
32
|
+
"message": 1
|
|
33
|
+
},
|
|
34
|
+
"background": {
|
|
35
|
+
"activeOnStart": true,
|
|
36
|
+
"beginsPattern": "^\\[claude-sync\\] watching",
|
|
37
|
+
"endsPattern": "^\\[claude-sync\\] watching"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 1.4.1-beta.2 - 2026-07-22
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- The `api-gateway` module has been renamed to **`proxy`** and now supports three outbound-proxy methods: AWS API Gateway IP rotation (as before), generic SOCKS5/HTTP proxies, and Oxylabs. Proxy setup is driven by an interactive configuration wizard, and `lazyload`/`run` now consume proxy settings exclusively from the generated config file (`proxy_config.json`). Proxy request logic is centralized in `makeReq.ts`. (`proxy`, `lazyload`, `run`)
|
|
8
|
+
- `analyze`: added a `--disable-rules-version-check` flag (and a corresponding `JS_RECON_DISABLE_RULES_VERSION_CHECK` environment variable) so the rules version-compatibility check can be skipped. A new rules-bundled Docker image variant (`ghcr.io/js-recon/js-recon:<version>-w-rules`) ships with `js-recon-rules` baked in, allowing `analyze` to run without a rules mount or `-r` flag. (`analyze`, `docker`)
|
|
9
|
+
- `run`: added `--disable-refactor` flag to skip the automatic bundler-detection and refactor step that otherwise runs after `report`. (`run`)
|
|
10
|
+
- `run` (batch mode, `-u <file>`): each domain still gets its own `<output>/<host>/js-recon.db`, but a combined `<output>/js-recon.db` is now also maintained across the whole batch, so findings/endpoints/mapped chunks can be queried across every target without opening each per-domain database individually. Every table in the combined database gains a `domain` column (the sanitized host, doubling as a foreign key back to the corresponding output directory), and primary keys that were only unique within a single domain (`mapped`'s chunk `id`, `mapped_openapi`'s `(path, method)`, `endpoints`' `url`) are widened or replaced with an autoincrement `globalId` so rows from different domains never collide. (`run`, `report`)
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Tech detection's intercepted-URL fallback (`techDetect/index.ts`) accepted a framework-shaped URL path (e.g. `/_nuxt/`, `/_next/`) as detection evidence without checking its actual response. A framework-shaped path resolving to a non-JS response (e.g. an error/maintenance page) could mis-fingerprint the whole target and send it down the wrong per-framework pipeline. The fallback now also confirms the captured response is a genuine 2xx JS response (status + `Content-Type` + body shape) before accepting the match. (`lazyload`)
|
|
15
|
+
- `proxy`: corrected the Oxylabs method to use the datacenter proxy scheme (verified against a live account); the module now fails cleanly on a malformed proxy config or URL, warns on a malformed config parse, and exits with an error when AWS credentials are missing for `-l`/`-d`. (`proxy`)
|
|
16
|
+
- `run`: replaced a fragile `@ts-ignore` on the final `analyze()` call with an explicit cast, and the Ctrl-C interrupt menu now waits for user input instead of exiting immediately. (`run`)
|
|
17
|
+
- Suppressed the misleading suggestion to pass `-k` when SSL verification is already disabled. (`run`, `lazyload`)
|
|
18
|
+
- Resolved npm-audit advisories: a path-traversal advisory in `@hono/node-server`, plus `fast-uri`/`hono` and `body-parser`/`brace-expansion` advisories. (`deps`)
|
|
19
|
+
|
|
3
20
|
## 1.4.1-beta.1 - 2026-07-16
|
|
4
21
|
|
|
5
22
|
### Fixed
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
ARG BASE_IMAGE=js-recon/js-recon
|
|
2
|
+
FROM ${BASE_IMAGE}
|
|
3
|
+
|
|
4
|
+
USER root
|
|
5
|
+
COPY js-recon-rules/ /home/pptruser/.js-recon/rules/
|
|
6
|
+
RUN rm -rf /home/pptruser/.js-recon/rules/.github && \
|
|
7
|
+
if [ -d /home/pptruser/.js-recon/rules/skills ]; then \
|
|
8
|
+
mv /home/pptruser/.js-recon/rules/skills /home/pptruser/.js-recon/skills; \
|
|
9
|
+
fi && \
|
|
10
|
+
chown -R pptruser:pptruser /home/pptruser/.js-recon
|
|
11
|
+
USER pptruser
|
|
12
|
+
|
|
13
|
+
ENV JS_RECON_DISABLE_RULES_VERSION_CHECK=true
|
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ js-recon run -u https://app.example.com
|
|
|
84
84
|
| `endpoints` | Extracts API endpoints and client-side paths from JS files. | [Read Docs](https://js-recon.io/docs/docs/modules/endpoints) |
|
|
85
85
|
| `strings` | Extracts strings, URLs, and potential secrets from JS files. | [Read Docs](https://js-recon.io/docs/docs/modules/strings) |
|
|
86
86
|
| `map` | Maps function calls and analyzes code, with optional AI-powered descriptions. | [Read Docs](https://js-recon.io/docs/docs/modules/map) |
|
|
87
|
-
| `
|
|
87
|
+
| `proxy` | Routes requests through AWS API Gateway, SOCKS5/HTTP, or Oxylabs proxies. | [Read Docs](https://js-recon.io/docs/docs/modules/proxy) |
|
|
88
88
|
| `run` | Runs all analysis modules automatically on a target. | [Read Docs](https://js-recon.io/docs/docs/modules/run) |
|
|
89
89
|
| `analyze` | Analyzes the code. | [Read Docs](https://js-recon.io/docs/docs/modules/analyze) |
|
|
90
90
|
| `report` | Generates a report from the analysis modules. | [Read Docs](https://js-recon.io/docs/docs/modules/report) |
|