@js-recon/js-recon 1.4.1-alpha.9 → 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 +42 -0
- package/.github/workflows/promote-js-recon.yml +299 -0
- package/.vscode/tasks.json +42 -0
- package/CHANGELOG.md +35 -0
- package/Dockerfile.w-rules +13 -0
- package/README.md +4 -2
- package/build/analyze/helpers/initRules.js +28 -6
- 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/globalConfig.js.map +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/settings.local.json +0 -10
- package/CLAUDE.md +0 -629
- 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/urls.txt +0 -5
- /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
|
|
@@ -136,6 +136,8 @@ jobs:
|
|
|
136
136
|
run: npm run build
|
|
137
137
|
build-docker:
|
|
138
138
|
needs: build
|
|
139
|
+
permissions:
|
|
140
|
+
contents: read
|
|
139
141
|
runs-on: ubuntu-latest
|
|
140
142
|
steps:
|
|
141
143
|
- name: Checkout
|
|
@@ -167,6 +169,9 @@ jobs:
|
|
|
167
169
|
with:
|
|
168
170
|
repository: js-recon/js-recon-rules
|
|
169
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
|
|
170
175
|
|
|
171
176
|
- name: Set up Node.js
|
|
172
177
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
@@ -223,6 +228,40 @@ jobs:
|
|
|
223
228
|
path: output/localhost_3001/analyze.json
|
|
224
229
|
if-no-files-found: ignore
|
|
225
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
|
+
|
|
226
265
|
integration-test-macos:
|
|
227
266
|
needs: build
|
|
228
267
|
runs-on: macos-latest
|
|
@@ -244,6 +283,9 @@ jobs:
|
|
|
244
283
|
with:
|
|
245
284
|
repository: js-recon/js-recon-rules
|
|
246
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
|
|
247
289
|
|
|
248
290
|
- name: Set up Node.js
|
|
249
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
|
|
@@ -102,3 +111,293 @@ jobs:
|
|
|
102
111
|
|
|
103
112
|
env:
|
|
104
113
|
VERSION: ${{ inputs.version }}
|
|
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
|
+
|
|
131
|
+
verify-npm-install:
|
|
132
|
+
runs-on: ubuntu-latest
|
|
133
|
+
permissions:
|
|
134
|
+
contents: read
|
|
135
|
+
steps:
|
|
136
|
+
- name: Checkout js-recon-labs
|
|
137
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
138
|
+
with:
|
|
139
|
+
repository: js-recon/js-recon-labs
|
|
140
|
+
path: js-recon-labs
|
|
141
|
+
persist-credentials: false
|
|
142
|
+
|
|
143
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
144
|
+
with:
|
|
145
|
+
node-version: "22"
|
|
146
|
+
|
|
147
|
+
- name: Install js-recon globally from npm
|
|
148
|
+
run: npm install -g "@js-recon/js-recon@${VERSION}"
|
|
149
|
+
env:
|
|
150
|
+
VERSION: ${{ inputs.version }}
|
|
151
|
+
|
|
152
|
+
- name: Verify installed version
|
|
153
|
+
run: |
|
|
154
|
+
INSTALLED=$(js-recon -V)
|
|
155
|
+
echo "Installed: ${INSTALLED}"
|
|
156
|
+
[[ "$INSTALLED" == *"$VERSION"* ]] || { echo "Version mismatch"; exit 1; }
|
|
157
|
+
env:
|
|
158
|
+
VERSION: ${{ inputs.version }}
|
|
159
|
+
|
|
160
|
+
- name: Install and start vulnerable app
|
|
161
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
162
|
+
run: |
|
|
163
|
+
npm ci
|
|
164
|
+
npm run build
|
|
165
|
+
npm start &
|
|
166
|
+
|
|
167
|
+
- name: Wait for app to be ready
|
|
168
|
+
run: timeout 60 bash -c 'until curl -sf --max-time 2 http://localhost:3001 > /dev/null; do sleep 2; done'
|
|
169
|
+
|
|
170
|
+
- name: Run installed js-recon against the lab app
|
|
171
|
+
run: |
|
|
172
|
+
echo "http://localhost:3001" > /tmp/npm-smoke-urls.txt
|
|
173
|
+
js-recon run -u /tmp/npm-smoke-urls.txt --no-sandbox -y -k
|
|
174
|
+
env:
|
|
175
|
+
PUPPETEER_EXECUTABLE_PATH: /usr/bin/google-chrome-stable
|
|
176
|
+
|
|
177
|
+
- name: Verify expected output files exist
|
|
178
|
+
run: |
|
|
179
|
+
test -n "$(find output -name analyze.json)" || { echo "analyze.json missing"; exit 1; }
|
|
180
|
+
test -n "$(find output -name js-recon.db)" || { echo "js-recon.db missing"; exit 1; }
|
|
181
|
+
|
|
182
|
+
verify-docker-install:
|
|
183
|
+
runs-on: ubuntu-latest
|
|
184
|
+
needs: publish-ghcr
|
|
185
|
+
permissions:
|
|
186
|
+
contents: read
|
|
187
|
+
packages: read
|
|
188
|
+
steps:
|
|
189
|
+
- name: Checkout js-recon-labs
|
|
190
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
191
|
+
with:
|
|
192
|
+
repository: js-recon/js-recon-labs
|
|
193
|
+
path: js-recon-labs
|
|
194
|
+
persist-credentials: false
|
|
195
|
+
|
|
196
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
197
|
+
with:
|
|
198
|
+
node-version: "22"
|
|
199
|
+
|
|
200
|
+
- uses: docker/login-action@v3
|
|
201
|
+
with:
|
|
202
|
+
registry: ghcr.io
|
|
203
|
+
username: ${{ github.actor }}
|
|
204
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
205
|
+
|
|
206
|
+
- name: Verify installed version
|
|
207
|
+
run: |
|
|
208
|
+
INSTALLED=$(docker run --rm ghcr.io/js-recon/js-recon:${VERSION} -V)
|
|
209
|
+
echo "Installed: ${INSTALLED}"
|
|
210
|
+
[[ "$INSTALLED" == *"$VERSION"* ]] || { echo "Version mismatch"; exit 1; }
|
|
211
|
+
env:
|
|
212
|
+
VERSION: ${{ inputs.version }}
|
|
213
|
+
|
|
214
|
+
- name: Install and start vulnerable app
|
|
215
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
216
|
+
run: |
|
|
217
|
+
npm ci
|
|
218
|
+
npm run build
|
|
219
|
+
npm start &
|
|
220
|
+
|
|
221
|
+
- name: Wait for app to be ready
|
|
222
|
+
run: timeout 60 bash -c 'until curl -sf --max-time 2 http://localhost:3001 > /dev/null; do sleep 2; done'
|
|
223
|
+
|
|
224
|
+
- name: Run containerized js-recon against the lab app
|
|
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.
|
|
231
|
+
mkdir -p /tmp/docker-output
|
|
232
|
+
chmod 777 /tmp/docker-output
|
|
233
|
+
echo "http://localhost:3001" > /tmp/docker-smoke-urls.txt
|
|
234
|
+
docker run --rm --network host \
|
|
235
|
+
-v /tmp/docker-output:/tmp/js-recon-output \
|
|
236
|
+
-v /tmp/docker-smoke-urls.txt:/tmp/urls.txt \
|
|
237
|
+
ghcr.io/js-recon/js-recon:${VERSION} \
|
|
238
|
+
run -u /tmp/urls.txt -o /tmp/js-recon-output --no-sandbox -y -k
|
|
239
|
+
env:
|
|
240
|
+
VERSION: ${{ inputs.version }}
|
|
241
|
+
|
|
242
|
+
- name: Verify expected output files exist
|
|
243
|
+
run: |
|
|
244
|
+
test -n "$(find /tmp/docker-output -name analyze.json)" || { echo "analyze.json missing"; exit 1; }
|
|
245
|
+
test -n "$(find /tmp/docker-output -name js-recon.db)" || { echo "js-recon.db missing"; exit 1; }
|
|
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
|
+
|
|
313
|
+
verify-brew-install:
|
|
314
|
+
runs-on: macos-latest
|
|
315
|
+
needs: update-homebrew-tap
|
|
316
|
+
permissions:
|
|
317
|
+
contents: read
|
|
318
|
+
strategy:
|
|
319
|
+
fail-fast: false
|
|
320
|
+
matrix:
|
|
321
|
+
formula: [js-recon, js-recon-alpha, js-recon-beta]
|
|
322
|
+
steps:
|
|
323
|
+
- name: Checkout js-recon-labs
|
|
324
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
325
|
+
with:
|
|
326
|
+
repository: js-recon/js-recon-labs
|
|
327
|
+
path: js-recon-labs
|
|
328
|
+
persist-credentials: false
|
|
329
|
+
|
|
330
|
+
- name: Tap and install
|
|
331
|
+
run: |
|
|
332
|
+
brew tap js-recon/tap
|
|
333
|
+
brew update
|
|
334
|
+
brew install "js-recon/tap/${{ matrix.formula }}"
|
|
335
|
+
|
|
336
|
+
- name: Determine expected formula for this version
|
|
337
|
+
id: expected
|
|
338
|
+
run: |
|
|
339
|
+
if [[ "$VERSION" == *"alpha"* ]]; then
|
|
340
|
+
echo "formula=js-recon-alpha" >> "$GITHUB_OUTPUT"
|
|
341
|
+
elif [[ "$VERSION" == *"beta"* ]]; then
|
|
342
|
+
echo "formula=js-recon-beta" >> "$GITHUB_OUTPUT"
|
|
343
|
+
else
|
|
344
|
+
echo "formula=js-recon" >> "$GITHUB_OUTPUT"
|
|
345
|
+
fi
|
|
346
|
+
env:
|
|
347
|
+
VERSION: ${{ inputs.version }}
|
|
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
|
+
|
|
362
|
+
- name: Verify installed version
|
|
363
|
+
run: |
|
|
364
|
+
INSTALLED=$("$BIN" -V)
|
|
365
|
+
echo "Installed: ${INSTALLED}"
|
|
366
|
+
if [[ "${{ matrix.formula }}" == "${{ steps.expected.outputs.formula }}" ]]; then
|
|
367
|
+
[[ "$INSTALLED" == *"$VERSION"* ]] || { echo "Version mismatch: expected ${VERSION} in ${{ matrix.formula }}"; exit 1; }
|
|
368
|
+
else
|
|
369
|
+
echo "Skipping version assertion — ${{ matrix.formula }} is not the channel updated by this promotion"
|
|
370
|
+
fi
|
|
371
|
+
env:
|
|
372
|
+
VERSION: ${{ inputs.version }}
|
|
373
|
+
BIN: ${{ steps.bin.outputs.bin }}
|
|
374
|
+
|
|
375
|
+
- name: Install and start vulnerable app
|
|
376
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
377
|
+
run: |
|
|
378
|
+
npm ci
|
|
379
|
+
npm run build
|
|
380
|
+
npm start &
|
|
381
|
+
|
|
382
|
+
- name: Wait for app to be ready
|
|
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
|
|
392
|
+
|
|
393
|
+
- name: Run installed js-recon against the lab app
|
|
394
|
+
run: |
|
|
395
|
+
echo "http://localhost:3001" > /tmp/brew-smoke-urls.txt
|
|
396
|
+
"$BIN" run -u /tmp/brew-smoke-urls.txt -y -k
|
|
397
|
+
env:
|
|
398
|
+
BIN: ${{ steps.bin.outputs.bin }}
|
|
399
|
+
|
|
400
|
+
- name: Verify expected output files exist
|
|
401
|
+
run: |
|
|
402
|
+
test -n "$(find output -name analyze.json)" || { echo "analyze.json missing"; exit 1; }
|
|
403
|
+
test -n "$(find output -name js-recon.db)" || { echo "js-recon.db missing"; exit 1; }
|
|
@@ -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
|
+
}
|