@shriyanss/js-recon 1.4.1-alpha.4 → 1.4.1-alpha.6
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/.github/workflows/build-and-prettify.yaml +187 -1
- package/.github/workflows/promote-js-recon.yml +116 -0
- package/.github/workflows/publish-js-recon.yml +7 -114
- package/.github/workflows/rules-smoke-test.yaml +79 -0
- package/CHANGELOG.md +46 -0
- package/CLAUDE.md +208 -14
- package/Dockerfile.release +29 -0
- package/README.md +18 -17
- package/build/analyze/engine/csMastSEngine.js +129 -0
- package/build/analyze/engine/csMastSEngine.js.map +1 -0
- package/build/analyze/engine/index.js +15 -0
- package/build/analyze/engine/index.js.map +1 -1
- package/build/analyze/helpers/engineHelpers/findDirectAssignment.js +2 -1
- package/build/analyze/helpers/engineHelpers/findDirectAssignment.js.map +1 -1
- package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js +2 -1
- package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js.map +1 -1
- package/build/analyze/helpers/engineHelpers/resolveFunctionIdentifier.js +2 -1
- package/build/analyze/helpers/engineHelpers/resolveFunctionIdentifier.js.map +1 -1
- package/build/analyze/helpers/engineHelpers/taintFlow.js +11 -2
- package/build/analyze/helpers/engineHelpers/taintFlow.js.map +1 -1
- package/build/analyze/helpers/schemas.js +5 -1
- package/build/analyze/helpers/schemas.js.map +1 -1
- package/build/analyze/helpers/validate.js +3 -3
- package/build/analyze/helpers/validate.js.map +1 -1
- package/build/completion/index.js +432 -0
- package/build/completion/index.js.map +1 -0
- package/build/cs_mast/index.js +94 -3
- package/build/cs_mast/index.js.map +1 -1
- package/build/endpoints/next_js/client_jsFilesHref.js +2 -1
- package/build/endpoints/next_js/client_jsFilesHref.js.map +1 -1
- package/build/endpoints/next_js/client_jsonParse.js +2 -1
- package/build/endpoints/next_js/client_jsonParse.js.map +1 -1
- package/build/endpoints/next_js/client_mappedJsonFile.js +2 -1
- package/build/endpoints/next_js/client_mappedJsonFile.js.map +1 -1
- package/build/endpoints/next_js/client_subsequentRequests.js +2 -1
- package/build/endpoints/next_js/client_subsequentRequests.js.map +1 -1
- package/build/fingerprint/index.js +56 -33
- package/build/fingerprint/index.js.map +1 -1
- package/build/globalConfig.js +1 -1
- package/build/index.js +67 -6
- package/build/index.js.map +1 -1
- package/build/lazyLoad/angular/angular_getFromMainJs.js +2 -1
- package/build/lazyLoad/angular/angular_getFromMainJs.js.map +1 -1
- package/build/lazyLoad/downloadFilesUtil.js +6 -5
- package/build/lazyLoad/downloadFilesUtil.js.map +1 -1
- package/build/lazyLoad/downloadLoadedJsUtil.js +56 -7
- package/build/lazyLoad/downloadLoadedJsUtil.js.map +1 -1
- package/build/lazyLoad/downloadQueue.js +9 -8
- package/build/lazyLoad/downloadQueue.js.map +1 -1
- package/build/lazyLoad/index.js +28 -1
- package/build/lazyLoad/index.js.map +1 -1
- package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js +36 -34
- package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js.map +1 -1
- package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js +63 -15
- package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js.map +1 -1
- package/build/lazyLoad/next_js/next_parseLayoutJs.js +80 -68
- package/build/lazyLoad/next_js/next_parseLayoutJs.js.map +1 -1
- package/build/lazyLoad/next_js/next_promiseResolve.js +22 -16
- package/build/lazyLoad/next_js/next_promiseResolve.js.map +1 -1
- package/build/lazyLoad/nuxt_js/nuxt_astParse.js +49 -47
- package/build/lazyLoad/nuxt_js/nuxt_astParse.js.map +1 -1
- package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +3 -1
- package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js.map +1 -1
- package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +3 -2
- package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js.map +1 -1
- package/build/lazyLoad/react/react_followImports.js +12 -9
- package/build/lazyLoad/react/react_followImports.js.map +1 -1
- package/build/lazyLoad/react/react_webpackChunkPaths.js +175 -123
- package/build/lazyLoad/react/react_webpackChunkPaths.js.map +1 -1
- package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +3 -2
- package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -1
- package/build/lazyLoad/techDetect/checkAngularJS.js +27 -6
- package/build/lazyLoad/techDetect/checkAngularJS.js.map +1 -1
- package/build/lazyLoad/techDetect/checkReact.js +8 -0
- package/build/lazyLoad/techDetect/checkReact.js.map +1 -1
- package/build/lazyLoad/techDetect/index.js +23 -2
- package/build/lazyLoad/techDetect/index.js.map +1 -1
- package/build/lazyLoad/vue/vue_RuntimeJs.js +2 -1
- package/build/lazyLoad/vue/vue_RuntimeJs.js.map +1 -1
- package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js +2 -1
- package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js.map +1 -1
- package/build/lazyLoad/vue/vue_discoverJsFiles.js +22 -10
- package/build/lazyLoad/vue/vue_discoverJsFiles.js.map +1 -1
- package/build/lazyLoad/vue/vue_getClientSidePaths.js +2 -1
- package/build/lazyLoad/vue/vue_getClientSidePaths.js.map +1 -1
- package/build/lazyLoad/vue/vue_jsImports.js +2 -1
- package/build/lazyLoad/vue/vue_jsImports.js.map +1 -1
- package/build/lazyLoad/vue/vue_viteMapDeps.js +62 -54
- package/build/lazyLoad/vue/vue_viteMapDeps.js.map +1 -1
- package/build/map/angular_js/getAngularConnections.js +1 -1
- package/build/map/angular_js/getAngularConnections.js.map +1 -1
- package/build/map/graphql/resolveGraphql.js +2 -1
- package/build/map/graphql/resolveGraphql.js.map +1 -1
- package/build/map/next_js/getExports.js +2 -1
- package/build/map/next_js/getExports.js.map +1 -1
- package/build/map/next_js/getFetchInstances.js +2 -1
- package/build/map/next_js/getFetchInstances.js.map +1 -1
- package/build/map/next_js/getTurbopackConnections.js +2 -1
- package/build/map/next_js/getTurbopackConnections.js.map +1 -1
- package/build/map/next_js/getWebpackConnections.js +2 -1
- package/build/map/next_js/getWebpackConnections.js.map +1 -1
- package/build/map/next_js/resolveAxios.js +2 -1
- package/build/map/next_js/resolveAxios.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/directCallsWithoutAssignment.js +2 -1
- package/build/map/next_js/resolveAxiosHelpers/directCallsWithoutAssignment.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js +2 -1
- package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js +2 -1
- package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js +2 -1
- package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js +2 -1
- package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/interceptorHeaders.js +2 -1
- package/build/map/next_js/resolveAxiosHelpers/interceptorHeaders.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js +2 -1
- package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js +2 -1
- package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js.map +1 -1
- package/build/map/next_js/resolveAxiosHelpers/traceBody.js +2 -1
- package/build/map/next_js/resolveAxiosHelpers/traceBody.js.map +1 -1
- package/build/map/next_js/resolveFetch.js +2 -1
- package/build/map/next_js/resolveFetch.js.map +1 -1
- package/build/map/next_js/resolveNewRequest.js +2 -1
- package/build/map/next_js/resolveNewRequest.js.map +1 -1
- package/build/map/next_js/resolveServerActions.js +2 -1
- package/build/map/next_js/resolveServerActions.js.map +1 -1
- package/build/map/next_js/utils.js +2 -1
- package/build/map/next_js/utils.js.map +1 -1
- package/build/map/react_js/getReactConnections.js +5 -4
- package/build/map/react_js/getReactConnections.js.map +1 -1
- package/build/map/vue_js/crossFileResolver.js +3 -2
- package/build/map/vue_js/crossFileResolver.js.map +1 -1
- package/build/map/vue_js/getViteConnections.js +5 -4
- package/build/map/vue_js/getViteConnections.js.map +1 -1
- package/build/map/vue_js/taint_utils.js +2 -1
- package/build/map/vue_js/taint_utils.js.map +1 -1
- package/build/map/vue_js/vue_resolveFetch.js +3 -2
- package/build/map/vue_js/vue_resolveFetch.js.map +1 -1
- package/build/map/vue_js/vue_resolveHttpClient.js +3 -2
- package/build/map/vue_js/vue_resolveHttpClient.js.map +1 -1
- package/build/map/vue_js/vue_resolveXhr.js +3 -2
- package/build/map/vue_js/vue_resolveXhr.js.map +1 -1
- package/build/refactor/index.js +399 -60
- package/build/refactor/index.js.map +1 -1
- package/build/refactor/next/helpers.js +194 -13
- package/build/refactor/next/helpers.js.map +1 -1
- package/build/refactor/next/index.js +223 -36
- package/build/refactor/next/index.js.map +1 -1
- package/build/refactor/next/transform.js +905 -55
- package/build/refactor/next/transform.js.map +1 -1
- package/build/refactor/react/index.js +3 -3
- package/build/refactor/react/index.js.map +1 -1
- package/build/refactor/react/transform.js +2 -1
- package/build/refactor/react/transform.js.map +1 -1
- package/build/refactor/react/validator.js +2 -1
- package/build/refactor/react/validator.js.map +1 -1
- package/build/refactor/react-vite/index.js +39 -5
- package/build/refactor/react-vite/index.js.map +1 -1
- package/build/refactor/react-vite/vendor-analyze.js +3 -3
- package/build/refactor/react-vite/vendor-analyze.js.map +1 -1
- package/build/refactor/remote/config.js +17 -1
- package/build/refactor/remote/config.js.map +1 -1
- package/build/refactor/remote/hf-client.js +27 -2
- package/build/refactor/remote/hf-client.js.map +1 -1
- package/build/refactor/remote/version-detect.js +355 -0
- package/build/refactor/remote/version-detect.js.map +1 -0
- package/build/refactor/vue/index.js +176 -0
- package/build/refactor/vue/index.js.map +1 -0
- package/build/refactor/vue/vendor-analyze-vue.js +271 -0
- package/build/refactor/vue/vendor-analyze-vue.js.map +1 -0
- package/build/refactor/vue/vite.js +216 -0
- package/build/refactor/vue/vite.js.map +1 -0
- package/build/report/utility/genHtml.js +14 -3
- package/build/report/utility/genHtml.js.map +1 -1
- package/build/run/bundler-detect.js +140 -0
- package/build/run/bundler-detect.js.map +1 -0
- package/build/run/index.js +91 -5
- package/build/run/index.js.map +1 -1
- package/build/strings/index.js +6 -2
- package/build/strings/index.js.map +1 -1
- package/build/strings/trufflehog.js +71 -0
- package/build/strings/trufflehog.js.map +1 -0
- package/build/utility/makeReq.js +10 -9
- package/build/utility/makeReq.js.map +1 -1
- package/build/utility/postmanGenerator.js +2 -2
- package/build/utility/postmanGenerator.js.map +1 -1
- package/build/utility/puppeteerInstance.js +7 -1
- package/build/utility/puppeteerInstance.js.map +1 -1
- package/package.json +9 -5
- package/scripts/smoke-test.js +74 -0
|
@@ -89,9 +89,30 @@ jobs:
|
|
|
89
89
|
git commit -m "chore: prettify code" || echo "No changes to commit"
|
|
90
90
|
git push
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
test:
|
|
93
93
|
needs: prettier
|
|
94
94
|
runs-on: ubuntu-latest
|
|
95
|
+
steps:
|
|
96
|
+
- name: Checkout
|
|
97
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
98
|
+
with:
|
|
99
|
+
ref: ${{ github.ref_name }}
|
|
100
|
+
|
|
101
|
+
- name: Set up Node.js
|
|
102
|
+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
103
|
+
with:
|
|
104
|
+
node-version: "22"
|
|
105
|
+
cache: "npm"
|
|
106
|
+
|
|
107
|
+
- name: Install dependencies
|
|
108
|
+
run: npm ci
|
|
109
|
+
|
|
110
|
+
- name: Run unit tests
|
|
111
|
+
run: npm test
|
|
112
|
+
|
|
113
|
+
build:
|
|
114
|
+
needs: test
|
|
115
|
+
runs-on: ubuntu-latest
|
|
95
116
|
steps:
|
|
96
117
|
- name: Checkout
|
|
97
118
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
@@ -119,3 +140,168 @@ jobs:
|
|
|
119
140
|
ref: ${{ github.ref_name }}
|
|
120
141
|
- name: Build docker container
|
|
121
142
|
run: docker build -t shriyanss/js-recon .
|
|
143
|
+
|
|
144
|
+
integration-test-docker:
|
|
145
|
+
needs: build-docker
|
|
146
|
+
runs-on: ubuntu-latest
|
|
147
|
+
timeout-minutes: 30
|
|
148
|
+
steps:
|
|
149
|
+
- name: Checkout js-recon
|
|
150
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
151
|
+
with:
|
|
152
|
+
ref: ${{ github.ref_name }}
|
|
153
|
+
|
|
154
|
+
- name: Checkout js-recon-labs
|
|
155
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
156
|
+
with:
|
|
157
|
+
repository: shriyanss/js-recon-labs
|
|
158
|
+
path: js-recon-labs
|
|
159
|
+
|
|
160
|
+
- name: Checkout js-recon-rules
|
|
161
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
162
|
+
with:
|
|
163
|
+
repository: shriyanss/js-recon-rules
|
|
164
|
+
path: js-recon-rules
|
|
165
|
+
|
|
166
|
+
- name: Set up Node.js
|
|
167
|
+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
168
|
+
with:
|
|
169
|
+
node-version: "22"
|
|
170
|
+
cache: "npm"
|
|
171
|
+
|
|
172
|
+
- name: Build js-recon Docker image
|
|
173
|
+
run: docker build -t shriyanss/js-recon .
|
|
174
|
+
|
|
175
|
+
- name: Install vuln-all-rules app dependencies
|
|
176
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
177
|
+
run: npm ci
|
|
178
|
+
|
|
179
|
+
- name: Build vuln-all-rules app
|
|
180
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
181
|
+
run: npm run build
|
|
182
|
+
|
|
183
|
+
- name: Start vuln-all-rules app
|
|
184
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
185
|
+
run: npm start &
|
|
186
|
+
|
|
187
|
+
- name: Wait for lab app to be ready
|
|
188
|
+
run: |
|
|
189
|
+
echo "Waiting for lab app on port 3001..."
|
|
190
|
+
n=0
|
|
191
|
+
until curl -sf http://localhost:3001 > /dev/null; do
|
|
192
|
+
n=$((n+1))
|
|
193
|
+
[ $n -ge 30 ] && echo "Timed out waiting for lab app" && exit 1
|
|
194
|
+
sleep 2
|
|
195
|
+
done
|
|
196
|
+
echo "Lab app is ready."
|
|
197
|
+
|
|
198
|
+
- name: Run js-recon via Docker against lab app
|
|
199
|
+
run: |
|
|
200
|
+
docker run --name js-recon-run \
|
|
201
|
+
--network host \
|
|
202
|
+
-v "$(pwd)/js-recon-rules:/home/pptruser/js-recon-rules" \
|
|
203
|
+
--entrypoint /bin/bash \
|
|
204
|
+
shriyanss/js-recon \
|
|
205
|
+
-c 'mkdir -p ~/.js-recon && ln -sf /home/pptruser/js-recon-rules ~/.js-recon/rules && printf "http://localhost:3001\n" > /tmp/urls.txt && node build/index.js run -u /tmp/urls.txt -r ./js-recon-rules --no-sandbox -y -k'
|
|
206
|
+
mkdir -p output
|
|
207
|
+
docker cp js-recon-run:/home/pptruser/output/. ./output/ 2>/dev/null || true
|
|
208
|
+
docker rm js-recon-run
|
|
209
|
+
|
|
210
|
+
- name: Verify all rules fired
|
|
211
|
+
run: node scripts/smoke-test.js
|
|
212
|
+
|
|
213
|
+
- name: Upload analyze.json on failure
|
|
214
|
+
if: failure()
|
|
215
|
+
uses: actions/upload-artifact@v4
|
|
216
|
+
with:
|
|
217
|
+
name: analyze-json-docker
|
|
218
|
+
path: output/localhost_3001/analyze.json
|
|
219
|
+
if-no-files-found: ignore
|
|
220
|
+
|
|
221
|
+
integration-test-macos:
|
|
222
|
+
needs: build
|
|
223
|
+
runs-on: macos-latest
|
|
224
|
+
timeout-minutes: 30
|
|
225
|
+
steps:
|
|
226
|
+
- name: Checkout js-recon
|
|
227
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
228
|
+
with:
|
|
229
|
+
ref: ${{ github.ref_name }}
|
|
230
|
+
|
|
231
|
+
- name: Checkout js-recon-labs
|
|
232
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
233
|
+
with:
|
|
234
|
+
repository: shriyanss/js-recon-labs
|
|
235
|
+
path: js-recon-labs
|
|
236
|
+
|
|
237
|
+
- name: Checkout js-recon-rules
|
|
238
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
239
|
+
with:
|
|
240
|
+
repository: shriyanss/js-recon-rules
|
|
241
|
+
path: js-recon-rules
|
|
242
|
+
|
|
243
|
+
- name: Set up Node.js
|
|
244
|
+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
245
|
+
with:
|
|
246
|
+
node-version: "22"
|
|
247
|
+
cache: "npm"
|
|
248
|
+
|
|
249
|
+
- name: Install Chrome
|
|
250
|
+
run: brew install --cask google-chrome
|
|
251
|
+
|
|
252
|
+
- name: Install js-recon dependencies
|
|
253
|
+
run: npm ci
|
|
254
|
+
env:
|
|
255
|
+
PUPPETEER_SKIP_DOWNLOAD: "true"
|
|
256
|
+
|
|
257
|
+
- name: Build js-recon
|
|
258
|
+
run: npm run build
|
|
259
|
+
|
|
260
|
+
- name: Install vuln-all-rules app dependencies
|
|
261
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
262
|
+
run: npm ci
|
|
263
|
+
|
|
264
|
+
- name: Build vuln-all-rules app
|
|
265
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
266
|
+
run: npm run build
|
|
267
|
+
|
|
268
|
+
- name: Start vuln-all-rules app
|
|
269
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
270
|
+
run: npm start &
|
|
271
|
+
|
|
272
|
+
- name: Wait for lab app to be ready
|
|
273
|
+
run: |
|
|
274
|
+
echo "Waiting for lab app on port 3001..."
|
|
275
|
+
n=0
|
|
276
|
+
until curl -sf http://localhost:3001 > /dev/null; do
|
|
277
|
+
n=$((n+1))
|
|
278
|
+
[ $n -ge 30 ] && echo "Timed out waiting for lab app" && exit 1
|
|
279
|
+
sleep 2
|
|
280
|
+
done
|
|
281
|
+
echo "Lab app is ready."
|
|
282
|
+
|
|
283
|
+
- name: Pre-populate js-recon rules cache
|
|
284
|
+
run: |
|
|
285
|
+
mkdir -p ~/.js-recon
|
|
286
|
+
ln -sf "$GITHUB_WORKSPACE/js-recon-rules" ~/.js-recon/rules
|
|
287
|
+
|
|
288
|
+
- name: Run js-recon natively against lab app
|
|
289
|
+
run: |
|
|
290
|
+
echo "http://localhost:3001" > /tmp/smoke-urls.txt
|
|
291
|
+
node --max-old-space-size=4096 build/index.js run \
|
|
292
|
+
-u /tmp/smoke-urls.txt \
|
|
293
|
+
-r ./js-recon-rules \
|
|
294
|
+
-y -k
|
|
295
|
+
env:
|
|
296
|
+
PUPPETEER_EXECUTABLE_PATH: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
|
|
297
|
+
|
|
298
|
+
- name: Verify all rules fired
|
|
299
|
+
run: node scripts/smoke-test.js
|
|
300
|
+
|
|
301
|
+
- name: Upload analyze.json on failure
|
|
302
|
+
if: failure()
|
|
303
|
+
uses: actions/upload-artifact@v4
|
|
304
|
+
with:
|
|
305
|
+
name: analyze-json-macos
|
|
306
|
+
path: output/localhost_3001/analyze.json
|
|
307
|
+
if-no-files-found: ignore
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Manually-triggered second phase of a release, run after a staged npm publish
|
|
2
|
+
# (see publish-js-recon.yml) has been approved by a human with 2FA on npmjs.com.
|
|
3
|
+
# Installs js-recon from the published npm registry artifact rather than
|
|
4
|
+
# building from git source, so the Homebrew/Docker/GHCR outputs are provably
|
|
5
|
+
# the same bits that were reviewed and approved on npm.
|
|
6
|
+
|
|
7
|
+
name: Promote JS Recon Release
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
inputs:
|
|
12
|
+
version:
|
|
13
|
+
description: "Published npm version to promote (e.g. 1.4.1-alpha.6, no leading v)"
|
|
14
|
+
required: true
|
|
15
|
+
type: string
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
update-homebrew-tap:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- name: Fetch published tarball and compute SHA256
|
|
22
|
+
id: sha256
|
|
23
|
+
run: |
|
|
24
|
+
npm pack "@shriyanss/js-recon@${VERSION}"
|
|
25
|
+
SHA=$(sha256sum "shriyanss-js-recon-${VERSION}.tgz" | awk '{print $1}')
|
|
26
|
+
echo "sha256=${SHA}" >> "$GITHUB_OUTPUT"
|
|
27
|
+
env:
|
|
28
|
+
VERSION: ${{ inputs.version }}
|
|
29
|
+
|
|
30
|
+
- name: Check out homebrew-tap
|
|
31
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
32
|
+
with:
|
|
33
|
+
repository: shriyanss/homebrew-tap
|
|
34
|
+
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
|
35
|
+
path: homebrew-tap
|
|
36
|
+
|
|
37
|
+
- name: Update formula fields
|
|
38
|
+
working-directory: homebrew-tap
|
|
39
|
+
run: |
|
|
40
|
+
F="Formula/js-recon.rb"
|
|
41
|
+
sed -i "s|^ url \"https://registry\.npmjs\.org/@shriyanss/js-recon/-/js-recon-[^\"]*\"| url \"https://registry.npmjs.org/@shriyanss/js-recon/-/js-recon-${VERSION}.tgz\"|" "${F}"
|
|
42
|
+
sed -i "s|^ sha256 \"[a-f0-9]*\"| sha256 \"${SHA}\"|" "${F}"
|
|
43
|
+
env:
|
|
44
|
+
VERSION: ${{ inputs.version }}
|
|
45
|
+
SHA: ${{ steps.sha256.outputs.sha256 }}
|
|
46
|
+
|
|
47
|
+
- name: Commit and push
|
|
48
|
+
working-directory: homebrew-tap
|
|
49
|
+
run: |
|
|
50
|
+
git config user.name "github-actions[bot]"
|
|
51
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
52
|
+
git add Formula/js-recon.rb
|
|
53
|
+
git commit -m "chore: update js-recon formula to ${VERSION}"
|
|
54
|
+
git push
|
|
55
|
+
env:
|
|
56
|
+
VERSION: ${{ inputs.version }}
|
|
57
|
+
|
|
58
|
+
publish-docker:
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
62
|
+
- name: Build and push to dockerhub
|
|
63
|
+
run: |
|
|
64
|
+
# login to docker
|
|
65
|
+
echo $DOCKER_SECRET | docker login -u shriyanss --password-stdin
|
|
66
|
+
|
|
67
|
+
# build the image from the published npm artifact
|
|
68
|
+
docker build -f Dockerfile.release --build-arg JS_RECON_VERSION=$VERSION -t shriyanss/js-recon:$VERSION .
|
|
69
|
+
|
|
70
|
+
# check if it is alpha or beta. default to latest
|
|
71
|
+
TAG="latest"
|
|
72
|
+
[[ "$VERSION" == *"beta"* ]] && TAG="beta"
|
|
73
|
+
[[ "$VERSION" == *"alpha"* ]] && TAG="alpha"
|
|
74
|
+
|
|
75
|
+
# tag again with whatever has been set
|
|
76
|
+
docker tag shriyanss/js-recon:$VERSION shriyanss/js-recon:$TAG
|
|
77
|
+
|
|
78
|
+
# push images with both tags
|
|
79
|
+
docker push shriyanss/js-recon:$VERSION
|
|
80
|
+
docker push shriyanss/js-recon:$TAG
|
|
81
|
+
|
|
82
|
+
env:
|
|
83
|
+
DOCKER_SECRET: ${{ secrets.DOCKER_SECRET }}
|
|
84
|
+
VERSION: ${{ inputs.version }}
|
|
85
|
+
|
|
86
|
+
publish-ghcr:
|
|
87
|
+
runs-on: ubuntu-latest
|
|
88
|
+
permissions:
|
|
89
|
+
contents: read
|
|
90
|
+
packages: write
|
|
91
|
+
steps:
|
|
92
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
93
|
+
- uses: docker/login-action@v3
|
|
94
|
+
with:
|
|
95
|
+
registry: ghcr.io
|
|
96
|
+
username: ${{ github.actor }}
|
|
97
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
98
|
+
- name: Build and push to github container registry
|
|
99
|
+
run: |
|
|
100
|
+
# build the image from the published npm artifact
|
|
101
|
+
docker build -f Dockerfile.release --build-arg JS_RECON_VERSION=$VERSION -t ghcr.io/shriyanss/js-recon:$VERSION .
|
|
102
|
+
|
|
103
|
+
# check if it is alpha or beta. default to latest
|
|
104
|
+
TAG="latest"
|
|
105
|
+
[[ "$VERSION" == *"beta"* ]] && TAG="beta"
|
|
106
|
+
[[ "$VERSION" == *"alpha"* ]] && TAG="alpha"
|
|
107
|
+
|
|
108
|
+
# tag again with whatever has been set
|
|
109
|
+
docker tag ghcr.io/shriyanss/js-recon:$VERSION ghcr.io/shriyanss/js-recon:$TAG
|
|
110
|
+
|
|
111
|
+
# push images with both tags
|
|
112
|
+
docker push ghcr.io/shriyanss/js-recon:$VERSION
|
|
113
|
+
docker push ghcr.io/shriyanss/js-recon:$TAG
|
|
114
|
+
|
|
115
|
+
env:
|
|
116
|
+
VERSION: ${{ inputs.version }}
|
|
@@ -63,6 +63,9 @@ jobs:
|
|
|
63
63
|
publish-npm:
|
|
64
64
|
needs: build
|
|
65
65
|
runs-on: ubuntu-latest
|
|
66
|
+
permissions:
|
|
67
|
+
id-token: write
|
|
68
|
+
contents: read
|
|
66
69
|
steps:
|
|
67
70
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
68
71
|
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
@@ -71,130 +74,20 @@ jobs:
|
|
|
71
74
|
registry-url: https://registry.npmjs.org/
|
|
72
75
|
- run: npm ci
|
|
73
76
|
- run: npm run build
|
|
74
|
-
- name:
|
|
75
|
-
run:
|
|
76
|
-
|
|
77
|
-
[[ "$VERSION" == *"beta"* ]] && TAG="beta"
|
|
78
|
-
[[ "$VERSION" == *"alpha"* ]] && TAG="alpha"
|
|
79
|
-
npm publish --tag $TAG
|
|
80
|
-
env:
|
|
81
|
-
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
|
82
|
-
VERSION: ${{ github.event.release.tag_name }}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
update-homebrew-tap:
|
|
86
|
-
needs: publish-npm
|
|
87
|
-
runs-on: ubuntu-latest
|
|
88
|
-
steps:
|
|
89
|
-
- name: Get release version
|
|
90
|
-
id: version
|
|
91
|
-
run: |
|
|
92
|
-
RAW="${{ github.event.release.tag_name }}"
|
|
93
|
-
echo "version=${RAW#v}" >> "$GITHUB_OUTPUT"
|
|
94
|
-
|
|
95
|
-
- name: Compute npm tarball SHA256
|
|
96
|
-
id: sha256
|
|
97
|
-
run: |
|
|
98
|
-
VERSION="${{ steps.version.outputs.version }}"
|
|
99
|
-
URL="https://registry.npmjs.org/@shriyanss/js-recon/-/js-recon-${VERSION}.tgz"
|
|
100
|
-
SHA=$(curl -fsSL "${URL}" | sha256sum | awk '{print $1}')
|
|
101
|
-
echo "sha256=${SHA}" >> "$GITHUB_OUTPUT"
|
|
102
|
-
|
|
103
|
-
- name: Check out homebrew-tap
|
|
104
|
-
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
105
|
-
with:
|
|
106
|
-
repository: shriyanss/homebrew-tap
|
|
107
|
-
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
|
108
|
-
path: homebrew-tap
|
|
109
|
-
|
|
110
|
-
- name: Update formula fields
|
|
111
|
-
working-directory: homebrew-tap
|
|
112
|
-
run: |
|
|
113
|
-
VERSION="${{ steps.version.outputs.version }}"
|
|
114
|
-
SHA="${{ steps.sha256.outputs.sha256 }}"
|
|
115
|
-
F="Formula/js-recon.rb"
|
|
116
|
-
sed -i "s|^ version \".*\"| version \"${VERSION}\"|" "${F}"
|
|
117
|
-
sed -i "s|^ url \"https://registry\.npmjs\.org/@shriyanss/js-recon/-/js-recon-[^\"]*\"| url \"https://registry.npmjs.org/@shriyanss/js-recon/-/js-recon-${VERSION}.tgz\"|" "${F}"
|
|
118
|
-
sed -i "s|^ sha256 \"[a-f0-9]*\"| sha256 \"${SHA}\"|" "${F}"
|
|
119
|
-
|
|
120
|
-
- name: Commit and push
|
|
121
|
-
working-directory: homebrew-tap
|
|
122
|
-
run: |
|
|
123
|
-
git config user.name "github-actions[bot]"
|
|
124
|
-
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
125
|
-
git add Formula/js-recon.rb
|
|
126
|
-
git commit -m "chore: update js-recon formula to ${{ steps.version.outputs.version }}"
|
|
127
|
-
git push
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
publish-docker:
|
|
131
|
-
needs: build
|
|
132
|
-
runs-on: ubuntu-latest
|
|
133
|
-
steps:
|
|
134
|
-
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
135
|
-
- name: Build and push to dockerhub
|
|
77
|
+
- name: Ensure npm CLI supports OIDC trusted publishing
|
|
78
|
+
run: npm install -g npm@latest
|
|
79
|
+
- name: Stage release to npm via OIDC
|
|
136
80
|
run: |
|
|
137
|
-
# login to docker
|
|
138
|
-
echo $DOCKER_SECRET | docker login -u shriyanss --password-stdin
|
|
139
|
-
|
|
140
|
-
# build the image
|
|
141
|
-
docker build -t shriyanss/js-recon:$VERSION .
|
|
142
|
-
|
|
143
|
-
# check if it is alpha or beta. default to latest
|
|
144
81
|
TAG="latest"
|
|
145
82
|
[[ "$VERSION" == *"beta"* ]] && TAG="beta"
|
|
146
83
|
[[ "$VERSION" == *"alpha"* ]] && TAG="alpha"
|
|
147
|
-
|
|
148
|
-
# tag again with whatever has been set
|
|
149
|
-
docker tag shriyanss/js-recon:$VERSION shriyanss/js-recon:$TAG
|
|
150
|
-
|
|
151
|
-
# push images with both tags
|
|
152
|
-
docker push shriyanss/js-recon:$VERSION
|
|
153
|
-
docker push shriyanss/js-recon:$TAG
|
|
154
|
-
|
|
84
|
+
npm stage publish --tag $TAG
|
|
155
85
|
env:
|
|
156
|
-
DOCKER_SECRET: ${{ secrets.DOCKER_SECRET }}
|
|
157
86
|
VERSION: ${{ github.event.release.tag_name }}
|
|
158
87
|
|
|
159
|
-
|
|
160
|
-
publish-ghcr:
|
|
161
|
-
needs: build
|
|
162
|
-
runs-on: ubuntu-latest
|
|
163
|
-
permissions:
|
|
164
|
-
contents: read
|
|
165
|
-
packages: write
|
|
166
|
-
steps:
|
|
167
|
-
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
168
|
-
- uses: docker/login-action@v3
|
|
169
|
-
with:
|
|
170
|
-
registry: ghcr.io
|
|
171
|
-
username: ${{ github.actor }}
|
|
172
|
-
password: ${{ secrets.GITHUB_TOKEN }}
|
|
173
|
-
- name: Build and push to github container registry
|
|
174
|
-
run: |
|
|
175
|
-
# build the image
|
|
176
|
-
docker build -t ghcr.io/shriyanss/js-recon:$VERSION .
|
|
177
|
-
|
|
178
|
-
# check if it is alpha or beta. default to latest
|
|
179
|
-
TAG="latest"
|
|
180
|
-
[[ "$VERSION" == *"beta"* ]] && TAG="beta"
|
|
181
|
-
[[ "$VERSION" == *"alpha"* ]] && TAG="alpha"
|
|
182
|
-
|
|
183
|
-
# tag again with whatever has been set
|
|
184
|
-
docker tag ghcr.io/shriyanss/js-recon:$VERSION ghcr.io/shriyanss/js-recon:$TAG
|
|
185
|
-
|
|
186
|
-
# push images with both tags
|
|
187
|
-
docker push ghcr.io/shriyanss/js-recon:$VERSION
|
|
188
|
-
docker push ghcr.io/shriyanss/js-recon:$TAG
|
|
189
|
-
|
|
190
|
-
env:
|
|
191
|
-
VERSION: ${{ github.event.release.tag_name }}
|
|
192
|
-
|
|
193
88
|
merge_main_and_dev:
|
|
194
89
|
needs:
|
|
195
90
|
- publish-npm
|
|
196
|
-
- publish-docker
|
|
197
|
-
- publish-ghcr
|
|
198
91
|
runs-on: ubuntu-latest
|
|
199
92
|
steps:
|
|
200
93
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
name: Rules Smoke Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches-ignore:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
rules-smoke-test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
timeout-minutes: 30
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout js-recon
|
|
15
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
16
|
+
|
|
17
|
+
- name: Checkout js-recon-labs
|
|
18
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
19
|
+
with:
|
|
20
|
+
repository: shriyanss/js-recon-labs
|
|
21
|
+
path: js-recon-labs
|
|
22
|
+
|
|
23
|
+
- name: Checkout js-recon-rules
|
|
24
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
25
|
+
with:
|
|
26
|
+
repository: shriyanss/js-recon-rules
|
|
27
|
+
path: js-recon-rules
|
|
28
|
+
|
|
29
|
+
- name: Set up Node.js
|
|
30
|
+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
31
|
+
with:
|
|
32
|
+
node-version: "22"
|
|
33
|
+
cache: "npm"
|
|
34
|
+
|
|
35
|
+
- name: Install js-recon dependencies
|
|
36
|
+
run: npm ci
|
|
37
|
+
|
|
38
|
+
- name: Build js-recon
|
|
39
|
+
run: npm run build
|
|
40
|
+
|
|
41
|
+
- name: Install vulnerable app dependencies
|
|
42
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
43
|
+
run: npm ci
|
|
44
|
+
|
|
45
|
+
- name: Build vulnerable app
|
|
46
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
47
|
+
run: npm run build
|
|
48
|
+
|
|
49
|
+
- name: Start vulnerable app
|
|
50
|
+
working-directory: js-recon-labs/next_js/vuln-all-rules
|
|
51
|
+
run: npm start &
|
|
52
|
+
|
|
53
|
+
- name: Wait for app to be ready
|
|
54
|
+
run: |
|
|
55
|
+
echo "Waiting for app on port 3001..."
|
|
56
|
+
timeout 60 bash -c 'until curl -sf http://localhost:3001 > /dev/null; do sleep 2; done'
|
|
57
|
+
echo "App is ready."
|
|
58
|
+
|
|
59
|
+
- name: Run js-recon against vulnerable app
|
|
60
|
+
run: |
|
|
61
|
+
echo "http://localhost:3001" > /tmp/smoke-urls.txt
|
|
62
|
+
node --max-old-space-size=4096 build/index.js run \
|
|
63
|
+
-u /tmp/smoke-urls.txt \
|
|
64
|
+
-r ./js-recon-rules \
|
|
65
|
+
--no-sandbox \
|
|
66
|
+
-y -k
|
|
67
|
+
env:
|
|
68
|
+
PUPPETEER_EXECUTABLE_PATH: /usr/bin/google-chrome-stable
|
|
69
|
+
|
|
70
|
+
- name: Verify all rules fired
|
|
71
|
+
run: node scripts/smoke-test.js
|
|
72
|
+
|
|
73
|
+
- name: Upload analyze.json on failure
|
|
74
|
+
if: failure()
|
|
75
|
+
uses: actions/upload-artifact@v4
|
|
76
|
+
with:
|
|
77
|
+
name: analyze-json
|
|
78
|
+
path: output/localhost_3001/analyze.json
|
|
79
|
+
if-no-files-found: ignore
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 1.4.1-alpha.6 - 2026-07-13
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- CI: npm publishing now uses OIDC trusted publishing with staged releases (`npm stage publish`) instead of a classic auth token, since NPM is restricting tokens that bypass MFA. Promoting a staged release to live still requires a manual, 2FA-gated `npm stage approve` — this cannot be automated. The Homebrew tap update and Docker/GHCR image publishing have moved out of `publish-js-recon.yml` into a new manually-triggered workflow, `promote-js-recon.yml`, run after the staged release is approved. That workflow installs js-recon from the published npm registry artifact (`npm pack`/`npm install <pkg>@<version>`) rather than building from git source, as an additional supply-chain safeguard — what ships in the Docker/GHCR images and what Homebrew hashes is provably the same bits that were reviewed and approved on npm. (`ci`)
|
|
8
|
+
|
|
9
|
+
## 1.4.1-alpha.5 - 2026-07-13
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Homebrew install: `puppeteer-extra` now receives the ESM `puppeteer` instance directly via `addExtra()` instead of relying on its internal `require('puppeteer')` call. On newer Node.js versions (22+, as shipped by Homebrew), a synchronous `require()` of an ESM module triggers `ExperimentalWarning` on every run. Using `addExtra()` bypasses the `require()` entirely and silences the warning. (`all`)
|
|
14
|
+
- `lazyload` (tech detect, react): React framework detection now works for Vite dev-mode servers. Vite's `@vitejs/plugin-react` and `@vitejs/plugin-react-swc` inject an inline `<script>` block containing `import { injectIntoGlobalHook } from "/@react-refresh"` into every dev-served page. Previously, none of the `REACT_MARKERS` matched this content, so dev-mode targets returned `unknown`. Two fixes: (1) `@react-refresh` and `injectIntoGlobalHook` are now included in `REACT_MARKERS` so the inline-script branch of `checkReact` fires immediately; (2) `/@react-refresh` is now a fast-path match in `fetchAndCheck` so any script src pointing at the HMR endpoint is also caught; (3) the intercepted-URL fallback in `frameworkDetect` now recognises `/@react-refresh` as a React signal alongside the existing Next.js / Nuxt / Svelte URL patterns. (`lazyload`, `fingerprint`, `run`)
|
|
15
|
+
- `lazyload` (tech detect, angular): Angular framework detection is now more robust. Three HTML-level signals are checked before fetching `main.js` — `data-beasties-container` (Angular's Beasties SSR/prerendering marker), `ng-version` (set by the Angular runtime on the root component element after bootstrapping, visible in Puppeteer-rendered DOM), and `_nghost-*` view-encapsulation attributes. These checks require no extra HTTP request and work even for zoneless Angular apps (Angular 16+) that omit Zone.js and therefore lack the previous `isAngularZone`/`this.ngZone` patterns. The `main.js` src pattern was also broadened from `main-` (hashed production builds only) to also match `main.js` (unhashed development builds). (`lazyload`, `fingerprint`, `run`)
|
|
16
|
+
- `lazyload`, `map`, `strings`: `.mjs` (ES module) files are now fully supported across all framework pipelines. Previously, extension filters in `downloadQueue.ts`, `downloadFilesUtil.ts`, `downloadLoadedJsUtil.ts`, `react_followImports.ts`, `getReactConnections.ts`, `getViteConnections.ts`, `getAngularConnections.ts`, `vue_resolveHttpClient.ts`, `vue_resolveFetch.ts`, `vue_resolveXhr.ts`, `crossFileResolver.ts`, and `strings/index.ts` only matched `.js` files. Sites that bundle all application code as `.mjs` (e.g. Framer/Rolldown) were silently ignored — all chunks were downloaded but zero files were scanned for connections, strings, or secrets. All affected paths now match both `.js` and `.mjs`. (`run`, `lazyload`, `map`, `strings`)
|
|
17
|
+
- `run` (react): The map step now receives the full `outputDir` (all downloaded hosts) rather than only the target host's subdirectory. Previously, when a React site served all its JS from a CDN host, the map step was pointed at an empty target-host directory and reported zero chunks. Now mirrors the Vue pipeline's directory-passing behaviour so CDN-hosted chunks are analysed correctly. (`run`, `map`)
|
|
18
|
+
- `lazyload` (react): `react_followImports` now discovers dynamic imports written as template literals (``import(`./chunk.mjs`)``) in addition to single/double-quoted strings. Bundlers that use Rolldown (e.g. Framer) emit all dynamic import paths as template literals; the previous regex only matched quoted strings, silently missing all lazily-loaded page and collection chunks. (`lazyload`, `run`)
|
|
19
|
+
- `lazyload`: `.mjs.map` sourcemap files are now handled correctly. The filename extraction regex now prefers the `.mjs.map` suffix over the shorter `.mjs` match, preventing sourcemap JSON content from being written with a `.mjs` extension (which caused Prettier's Babel parser to throw a `SyntaxError` and discard the file). The sourcemap write path now uses the JSON parser for both `.js.map` and `.mjs.map` files. (`lazyload`, `run`)
|
|
20
|
+
- `lazyload` (Puppeteer): `downloadLoadedJsUtil` now uses `waitUntil: "networkidle0"` with a 10 s timeout on `page.goto()`. Previously the call had no timeout and no error handling, so pages whose `load` event never fires (deferred JS, service workers, some SPA patterns) caused the lazyload step to hang indefinitely. Navigation errors and timeouts are now caught and the URLs collected up to that point are returned normally. (`lazyload`, `run`)
|
|
21
|
+
- `lazyload` (Puppeteer): `browser.close()` in `downloadLoadedJsUtil` is now wrapped in a try/catch; if it hangs, the Chrome process is force-killed via `SIGKILL`. Previously a stuck `browser.close()` caused the process to hang after download was otherwise complete. (`lazyload`, `run`)
|
|
22
|
+
- `lazyload` (Puppeteer): All three Puppeteer-using modules (`downloadLoadedJsUtil`, `next_GetLazyResourcesWebpackJs`, `techDetect/index`) now abort non-http/s requests (e.g. `mailto:`, `data:`, `blob:`, `chrome-extension:`, `tel:`) in the request interceptor instead of calling `request.continue()`. Calling `continue()` on these schemes throws an unhandled error and can trigger OS protocol handlers. (`lazyload`, `run`)
|
|
23
|
+
- `lazyload` (Puppeteer): `downloadLoadedJsUtil` and `next_GetLazyResourcesWebpackJs` now pass `--disable-external-protocol-dialog` to Chrome at launch and install an `evaluateOnNewDocument` guard that overrides `window.open` and suppresses clicks on non-http/s anchors. This provides a three-layer defence (Chrome flag + JS intercept + request interceptor abort) ensuring that non-http protocol links on target pages never invoke OS handlers (mail client, phone, etc.). (`lazyload`, `run`)
|
|
24
|
+
- `lazyload` (Puppeteer): All three Puppeteer-using modules now issue a `Page.setDownloadBehavior({ behavior: "deny" })` CDP command immediately after page creation. This prevents accidental file downloads triggered by download-link clicks or JavaScript during crawl, which could block the browser and fill the output directory with unexpected files. (`lazyload`, `run`)
|
|
25
|
+
- `lazyload` (tech detect): After `waitUntil: "load"` resolves, if no framework URL has been captured in `interceptedUrls` yet, a conditional `page.waitForNavigation({ timeout: 5000 })` is now issued to wait for a second navigation event. This catches sites that serve a JS proof-of-work bot challenge (e.g. Vercel's `challenge.v2.min.js`) that fires its own `load` event before calling `window.location` to redirect to the real app. Previously, Puppeteer exited on the challenge page's `load` event and tech detection returned null (exit 10). On sites with no redirect the navigation wait times out after 5 s and detection continues normally. (`lazyload`, `run`)
|
|
26
|
+
- `lazyload`: When `frameworkDetect` returns null and `downloadLoadedJs` is used as a fallback, the downloaded file URL paths are now scanned for `/_next/`, `/_nuxt/`, and `/_app/immutable/` signatures as a second-chance tech detection pass. Previously, sites that serve their framework app at a non-root `basePath` (e.g. Next.js at `/app` instead of `/`) caused the initial Puppeteer-based detection to miss the framework because the intercepted JS paths didn't match any framework pattern, resulting in exit 10. (`lazyload`, `run`)
|
|
27
|
+
- `lazyload` (next_js): `next_parseLayoutJs` now applies a 1.5 MB per-file size guard — checked from both the `Content-Length` response header and the fetched content body — before passing layout files to the AST parser. Files exceeding the limit are skipped with a yellow warning. Previously, Next.js App Router sites with 50+ nested pages each loading a large `layout.js` caused cumulative AST memory of ~2 GB, exhausting the V8 heap and crashing with SIGSEGV (exit 139). (`lazyload`, `run`)
|
|
28
|
+
- `cs-mast`: `--scat`, `--sinc`, `--all-scat-permutations`, `--perm-output`, and `--perm-concurrency` flags were declared in the CLI but not wired to the underlying function, causing a TypeScript compile error (`TS2554: Expected 5 arguments, but got 10`). The function now accepts all five additional parameters: `--scat`/`--sinc` override the active CS-MAST config, and `--all-scat-permutations` runs all 511 non-empty scat subsets in parallel batches and writes one collision file per subset to `--perm-output`. (`cs-mast`)
|
|
29
|
+
|
|
30
|
+
- `refactor -t react-vite`: vendor chunks (`vendor-react-*.js`, `rolldown-runtime-*.js`) that are absent from `mapped.json` are now automatically located in the downloaded assets directory and injected before the refactor pass. Previously, `mapped.json` typically contained only app chunks — vendor chunks are excluded from mapping because they hold only third-party code. This left `vendorExportMaps` empty, so the `rewriteVendorImports` pass had nothing to match against and vendor import statements like `import { d as t } from './vendor-react-CLFLfR9F.js'` survived into the output, causing the Vite build check to fail with "Could not resolve". The fix uses the existing `findAssetsDir`/`findVendorChunkFiles` helpers (already used by the webpack branch) to discover the assets directory from `// File Source:` headers in chunk code.
|
|
31
|
+
- `lazyload` (nuxt): `nuxt_getFromPageSource` now prints the number of new JS files discovered (delta from the global URL set) instead of the running total. Previously the count included every URL already known from earlier in the session.
|
|
32
|
+
- `lazyload` (vue): Each discovery method in `vue_discoverJsFiles` now prints only the count of URL that are genuinely new — URLs already known from earlier methods are excluded. Previously `fromImports.length`, `fromStringRefs.length`, etc. could include URLs already in the accumulator and over-count.
|
|
33
|
+
- Error messages emitted by `makeReq` (fetch failures, cache errors, timeout notices, firewall detection) now use `progressError`/`progressLog` instead of `console.error`/`console.log`, so they are routed through the active progress bar's logger and no longer clutter the bar line when errors occur during a scan.
|
|
34
|
+
- `refactor` (`react-webpack`, `react-vite`): new `--detect-version` flag. When set, the tool fetches per-version `reliable_signatures.json` files from the `shriyanss/cs-mast-s-dataset` HuggingFace bucket (path: `version/react/<bundler>/<version>/<scat>/reliable_signatures.json`) and matches them against CS-MAST signatures generated from the target bundle's chunks. The best-matching React version is used to set `react` and `react-dom` version pins in the refactored output's `package.json` instead of the default `^18.3.1`. Signatures are cached under `~/.js-recon/refactor/version_sigs_cache/` with a 7-day TTL. Supports all webpack versions (react-0.12 through react-19) and all Vite versions (react-16 through react-19) available in the dataset. (`refactor`)
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- `fingerprint`: output files are now written incrementally — each result is flushed to disk immediately after detection rather than buffered and written at the end. For text, csv, and jsonl formats the result is appended; for json the full array is rewritten. Output files are also created (and csv headers written) before the worker pool starts, so a partial file always exists if the scan is interrupted. (`fingerprint`)
|
|
39
|
+
- CLI: help output is now colorized. Section titles (`Usage:`, `Options:`, `Commands:`) are bold cyan; flag names are yellow; `<required>` argument placeholders are magenta; `[optional]` argument placeholders are cyan; descriptions are dimmed; and `(default: …)` suffixes are dim italic. Applies to every subcommand.
|
|
40
|
+
- `run`: the pipeline now runs an optional `refactor` pass after the report step for React, Vue, Nuxt, and Next.js targets. The bundler (webpack vs vite) is detected automatically using CS-MAST-S signatures sampled from the `shriyanss/cs-mast-s-dataset` HuggingFace bucket — the same bucket and caching layer used by `refactor --remote-collisions`. If the detected match count meets `--cs-mast-tech-detect-threshold` (default `50`), `refactor` is called with the full tech identifier (e.g. `react-webpack`); otherwise the step is silently skipped. Refactored output is written to `refactored/` (single-URL mode) or `<workingDir>/refactored/` (batch mode). Currently only React bundles have bucket entries; Vue, Nuxt, and Next.js gracefully skip until their signatures are added to the bucket. (`run`, `refactor`)
|
|
41
|
+
- `run`: new `--cs-mast-tech-detect-threshold <n>` flag (default `50`). Sets the minimum number of CS-MAST-S signature matches required to consider a bundler detected for the refactor step. Pass `0` to disable refactor entirely. (`run`)
|
|
42
|
+
- `refactor` (`react-vite`, `react-webpack`): new `--remote-collisions <path>` flag. Accepts a HuggingFace bucket path (e.g. `react/vite/large-0.1.8`) and uses it as the signature source instead of the automatic `TECH_TO_BRANCH` mapping. When the path does not exist in the `shriyanss/cs-mast-s-dataset` bucket the tool exits with code 25. The existing caching layer is fully reused — signatures are cached under `~/.js-recon/refactor/signature_cache/` and the file list is cached in `~/.js-recon/refactor/cs-mast-s-list-cache.json`. Feature directories that contain no collision records in the dataset are skipped during intersection rather than collapsing the result to zero.
|
|
43
|
+
- `refactor` (`react-webpack`, `react-vite`): `--detect-version` now uses multiple scat configurations for improved accuracy. Three new flags control the behaviour: `--detect-version-config` (default `dynamic`), `--detect-version-dynamic-threshold` (default `3`), and `--detect-version-dynamic-conf-purge`. In `dynamic` mode the tool automatically selects up to `--detect-version-dynamic-threshold` scat configs that have non-empty reliable signatures across all known React versions, caches the selection in `~/.js-recon/refactor/config.json`, and aggregates match counts across all configs per version for a stronger detection signal. Alternatively, passing comma-separated scat categories (e.g. `lit,decl,loop,cond`) to `--detect-version-config` fixes the config; the tool validates signatures are non-empty for every version and exits with code 26 if not. Use `--detect-version-dynamic-conf-purge` to force recomputation of the cached config.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- Set `react/webpack/large-0.1.8` as default cs-mast-s dataset for react + webpack refactoring
|
|
48
|
+
|
|
3
49
|
## 1.4.1-alpha.4 - 2026-06-29
|
|
4
50
|
|
|
5
51
|
### Added
|