@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.
Files changed (191) hide show
  1. package/.github/workflows/build-and-prettify.yaml +187 -1
  2. package/.github/workflows/promote-js-recon.yml +116 -0
  3. package/.github/workflows/publish-js-recon.yml +7 -114
  4. package/.github/workflows/rules-smoke-test.yaml +79 -0
  5. package/CHANGELOG.md +46 -0
  6. package/CLAUDE.md +208 -14
  7. package/Dockerfile.release +29 -0
  8. package/README.md +18 -17
  9. package/build/analyze/engine/csMastSEngine.js +129 -0
  10. package/build/analyze/engine/csMastSEngine.js.map +1 -0
  11. package/build/analyze/engine/index.js +15 -0
  12. package/build/analyze/engine/index.js.map +1 -1
  13. package/build/analyze/helpers/engineHelpers/findDirectAssignment.js +2 -1
  14. package/build/analyze/helpers/engineHelpers/findDirectAssignment.js.map +1 -1
  15. package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js +2 -1
  16. package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js.map +1 -1
  17. package/build/analyze/helpers/engineHelpers/resolveFunctionIdentifier.js +2 -1
  18. package/build/analyze/helpers/engineHelpers/resolveFunctionIdentifier.js.map +1 -1
  19. package/build/analyze/helpers/engineHelpers/taintFlow.js +11 -2
  20. package/build/analyze/helpers/engineHelpers/taintFlow.js.map +1 -1
  21. package/build/analyze/helpers/schemas.js +5 -1
  22. package/build/analyze/helpers/schemas.js.map +1 -1
  23. package/build/analyze/helpers/validate.js +3 -3
  24. package/build/analyze/helpers/validate.js.map +1 -1
  25. package/build/completion/index.js +432 -0
  26. package/build/completion/index.js.map +1 -0
  27. package/build/cs_mast/index.js +94 -3
  28. package/build/cs_mast/index.js.map +1 -1
  29. package/build/endpoints/next_js/client_jsFilesHref.js +2 -1
  30. package/build/endpoints/next_js/client_jsFilesHref.js.map +1 -1
  31. package/build/endpoints/next_js/client_jsonParse.js +2 -1
  32. package/build/endpoints/next_js/client_jsonParse.js.map +1 -1
  33. package/build/endpoints/next_js/client_mappedJsonFile.js +2 -1
  34. package/build/endpoints/next_js/client_mappedJsonFile.js.map +1 -1
  35. package/build/endpoints/next_js/client_subsequentRequests.js +2 -1
  36. package/build/endpoints/next_js/client_subsequentRequests.js.map +1 -1
  37. package/build/fingerprint/index.js +56 -33
  38. package/build/fingerprint/index.js.map +1 -1
  39. package/build/globalConfig.js +1 -1
  40. package/build/index.js +67 -6
  41. package/build/index.js.map +1 -1
  42. package/build/lazyLoad/angular/angular_getFromMainJs.js +2 -1
  43. package/build/lazyLoad/angular/angular_getFromMainJs.js.map +1 -1
  44. package/build/lazyLoad/downloadFilesUtil.js +6 -5
  45. package/build/lazyLoad/downloadFilesUtil.js.map +1 -1
  46. package/build/lazyLoad/downloadLoadedJsUtil.js +56 -7
  47. package/build/lazyLoad/downloadLoadedJsUtil.js.map +1 -1
  48. package/build/lazyLoad/downloadQueue.js +9 -8
  49. package/build/lazyLoad/downloadQueue.js.map +1 -1
  50. package/build/lazyLoad/index.js +28 -1
  51. package/build/lazyLoad/index.js.map +1 -1
  52. package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js +36 -34
  53. package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js.map +1 -1
  54. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js +63 -15
  55. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js.map +1 -1
  56. package/build/lazyLoad/next_js/next_parseLayoutJs.js +80 -68
  57. package/build/lazyLoad/next_js/next_parseLayoutJs.js.map +1 -1
  58. package/build/lazyLoad/next_js/next_promiseResolve.js +22 -16
  59. package/build/lazyLoad/next_js/next_promiseResolve.js.map +1 -1
  60. package/build/lazyLoad/nuxt_js/nuxt_astParse.js +49 -47
  61. package/build/lazyLoad/nuxt_js/nuxt_astParse.js.map +1 -1
  62. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +3 -1
  63. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js.map +1 -1
  64. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +3 -2
  65. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js.map +1 -1
  66. package/build/lazyLoad/react/react_followImports.js +12 -9
  67. package/build/lazyLoad/react/react_followImports.js.map +1 -1
  68. package/build/lazyLoad/react/react_webpackChunkPaths.js +175 -123
  69. package/build/lazyLoad/react/react_webpackChunkPaths.js.map +1 -1
  70. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +3 -2
  71. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -1
  72. package/build/lazyLoad/techDetect/checkAngularJS.js +27 -6
  73. package/build/lazyLoad/techDetect/checkAngularJS.js.map +1 -1
  74. package/build/lazyLoad/techDetect/checkReact.js +8 -0
  75. package/build/lazyLoad/techDetect/checkReact.js.map +1 -1
  76. package/build/lazyLoad/techDetect/index.js +23 -2
  77. package/build/lazyLoad/techDetect/index.js.map +1 -1
  78. package/build/lazyLoad/vue/vue_RuntimeJs.js +2 -1
  79. package/build/lazyLoad/vue/vue_RuntimeJs.js.map +1 -1
  80. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js +2 -1
  81. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js.map +1 -1
  82. package/build/lazyLoad/vue/vue_discoverJsFiles.js +22 -10
  83. package/build/lazyLoad/vue/vue_discoverJsFiles.js.map +1 -1
  84. package/build/lazyLoad/vue/vue_getClientSidePaths.js +2 -1
  85. package/build/lazyLoad/vue/vue_getClientSidePaths.js.map +1 -1
  86. package/build/lazyLoad/vue/vue_jsImports.js +2 -1
  87. package/build/lazyLoad/vue/vue_jsImports.js.map +1 -1
  88. package/build/lazyLoad/vue/vue_viteMapDeps.js +62 -54
  89. package/build/lazyLoad/vue/vue_viteMapDeps.js.map +1 -1
  90. package/build/map/angular_js/getAngularConnections.js +1 -1
  91. package/build/map/angular_js/getAngularConnections.js.map +1 -1
  92. package/build/map/graphql/resolveGraphql.js +2 -1
  93. package/build/map/graphql/resolveGraphql.js.map +1 -1
  94. package/build/map/next_js/getExports.js +2 -1
  95. package/build/map/next_js/getExports.js.map +1 -1
  96. package/build/map/next_js/getFetchInstances.js +2 -1
  97. package/build/map/next_js/getFetchInstances.js.map +1 -1
  98. package/build/map/next_js/getTurbopackConnections.js +2 -1
  99. package/build/map/next_js/getTurbopackConnections.js.map +1 -1
  100. package/build/map/next_js/getWebpackConnections.js +2 -1
  101. package/build/map/next_js/getWebpackConnections.js.map +1 -1
  102. package/build/map/next_js/resolveAxios.js +2 -1
  103. package/build/map/next_js/resolveAxios.js.map +1 -1
  104. package/build/map/next_js/resolveAxiosHelpers/directCallsWithoutAssignment.js +2 -1
  105. package/build/map/next_js/resolveAxiosHelpers/directCallsWithoutAssignment.js.map +1 -1
  106. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js +2 -1
  107. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js.map +1 -1
  108. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js +2 -1
  109. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js.map +1 -1
  110. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js +2 -1
  111. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js.map +1 -1
  112. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js +2 -1
  113. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js.map +1 -1
  114. package/build/map/next_js/resolveAxiosHelpers/interceptorHeaders.js +2 -1
  115. package/build/map/next_js/resolveAxiosHelpers/interceptorHeaders.js.map +1 -1
  116. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js +2 -1
  117. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js.map +1 -1
  118. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js +2 -1
  119. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js.map +1 -1
  120. package/build/map/next_js/resolveAxiosHelpers/traceBody.js +2 -1
  121. package/build/map/next_js/resolveAxiosHelpers/traceBody.js.map +1 -1
  122. package/build/map/next_js/resolveFetch.js +2 -1
  123. package/build/map/next_js/resolveFetch.js.map +1 -1
  124. package/build/map/next_js/resolveNewRequest.js +2 -1
  125. package/build/map/next_js/resolveNewRequest.js.map +1 -1
  126. package/build/map/next_js/resolveServerActions.js +2 -1
  127. package/build/map/next_js/resolveServerActions.js.map +1 -1
  128. package/build/map/next_js/utils.js +2 -1
  129. package/build/map/next_js/utils.js.map +1 -1
  130. package/build/map/react_js/getReactConnections.js +5 -4
  131. package/build/map/react_js/getReactConnections.js.map +1 -1
  132. package/build/map/vue_js/crossFileResolver.js +3 -2
  133. package/build/map/vue_js/crossFileResolver.js.map +1 -1
  134. package/build/map/vue_js/getViteConnections.js +5 -4
  135. package/build/map/vue_js/getViteConnections.js.map +1 -1
  136. package/build/map/vue_js/taint_utils.js +2 -1
  137. package/build/map/vue_js/taint_utils.js.map +1 -1
  138. package/build/map/vue_js/vue_resolveFetch.js +3 -2
  139. package/build/map/vue_js/vue_resolveFetch.js.map +1 -1
  140. package/build/map/vue_js/vue_resolveHttpClient.js +3 -2
  141. package/build/map/vue_js/vue_resolveHttpClient.js.map +1 -1
  142. package/build/map/vue_js/vue_resolveXhr.js +3 -2
  143. package/build/map/vue_js/vue_resolveXhr.js.map +1 -1
  144. package/build/refactor/index.js +399 -60
  145. package/build/refactor/index.js.map +1 -1
  146. package/build/refactor/next/helpers.js +194 -13
  147. package/build/refactor/next/helpers.js.map +1 -1
  148. package/build/refactor/next/index.js +223 -36
  149. package/build/refactor/next/index.js.map +1 -1
  150. package/build/refactor/next/transform.js +905 -55
  151. package/build/refactor/next/transform.js.map +1 -1
  152. package/build/refactor/react/index.js +3 -3
  153. package/build/refactor/react/index.js.map +1 -1
  154. package/build/refactor/react/transform.js +2 -1
  155. package/build/refactor/react/transform.js.map +1 -1
  156. package/build/refactor/react/validator.js +2 -1
  157. package/build/refactor/react/validator.js.map +1 -1
  158. package/build/refactor/react-vite/index.js +39 -5
  159. package/build/refactor/react-vite/index.js.map +1 -1
  160. package/build/refactor/react-vite/vendor-analyze.js +3 -3
  161. package/build/refactor/react-vite/vendor-analyze.js.map +1 -1
  162. package/build/refactor/remote/config.js +17 -1
  163. package/build/refactor/remote/config.js.map +1 -1
  164. package/build/refactor/remote/hf-client.js +27 -2
  165. package/build/refactor/remote/hf-client.js.map +1 -1
  166. package/build/refactor/remote/version-detect.js +355 -0
  167. package/build/refactor/remote/version-detect.js.map +1 -0
  168. package/build/refactor/vue/index.js +176 -0
  169. package/build/refactor/vue/index.js.map +1 -0
  170. package/build/refactor/vue/vendor-analyze-vue.js +271 -0
  171. package/build/refactor/vue/vendor-analyze-vue.js.map +1 -0
  172. package/build/refactor/vue/vite.js +216 -0
  173. package/build/refactor/vue/vite.js.map +1 -0
  174. package/build/report/utility/genHtml.js +14 -3
  175. package/build/report/utility/genHtml.js.map +1 -1
  176. package/build/run/bundler-detect.js +140 -0
  177. package/build/run/bundler-detect.js.map +1 -0
  178. package/build/run/index.js +91 -5
  179. package/build/run/index.js.map +1 -1
  180. package/build/strings/index.js +6 -2
  181. package/build/strings/index.js.map +1 -1
  182. package/build/strings/trufflehog.js +71 -0
  183. package/build/strings/trufflehog.js.map +1 -0
  184. package/build/utility/makeReq.js +10 -9
  185. package/build/utility/makeReq.js.map +1 -1
  186. package/build/utility/postmanGenerator.js +2 -2
  187. package/build/utility/postmanGenerator.js.map +1 -1
  188. package/build/utility/puppeteerInstance.js +7 -1
  189. package/build/utility/puppeteerInstance.js.map +1 -1
  190. package/package.json +9 -5
  191. package/scripts/smoke-test.js +74 -0
package/CLAUDE.md CHANGED
@@ -77,9 +77,9 @@ npm run start -- <subcommand> [options]
77
77
  1. **Lazyload** — downloads initial JS chunks via Puppeteer; detects framework; sets `globalsUtil.getTech()` to `"next"`
78
78
  2. **Strings** — scans downloaded JS for strings, extracts URL paths → `extracted_urls.json`
79
79
  3. **Lazyload (subsequent requests)** — re-crawls using the extracted paths to fetch dynamically loaded chunks; also fetches `buildId`
80
- 4. **Strings (pass 2)** — re-runs strings on the expanded chunk set; generates `extracted_urls.txt` (permuted) and `extracted_urls-openapi.json`; optionally scans secrets (`--secrets`)
80
+ 4. **Strings (pass 2)** — re-runs strings on the expanded chunk set; generates `extracted_urls.txt` (permuted) and `extracted_urls-openapi.json`; optionally scans secrets (`--secrets`); optionally runs TruffleHog (`--trufflehog`)
81
81
  5. **Lazyload re-pass (step 4.5)** — a second subsequent-requests crawl to pick up chunks for dynamic routes discovered in pass 2
82
- 6. **Strings re-pass (step 4.6)** — strings pass over the re-pass chunks
82
+ 6. **Strings re-pass (step 4.6)** — strings pass over the re-pass chunks; also runs `--secrets` / `--trufflehog` if those flags are set
83
83
  7. **Map** — parses webpack/turbopack bundles; resolves `fetch()` calls and axios usage; generates `mapped.json` and `mapped-openapi.json`; CDN-aware: if JS was served from a different host, `getCdnDir` finds the CDN output dir and passes that to map instead of `outputDir/host`
84
84
  8. **Endpoints** — extracts client-side route paths; uses `___subsequent_requests` directory presence to decide whether to pass a JS directory
85
85
  9. **Analyze** — loads YAML rules (from `-r/--rules` if provided, otherwise default rules cache); runs AST engine and request engine; writes `analyze.json`
@@ -107,7 +107,7 @@ npm run start -- <subcommand> [options]
107
107
 
108
108
  **SvelteKit `adapter-static` (SSG/SPA) boot pattern**: The static builds produce a shell HTML file (`404.html` for SSG, `index.html` for SPA) that contains both `<link rel="modulepreload">` tags for all initial chunks AND the same inline `import()` boot script as adapter-node. `svelte_getFromPageSource` picks up 17+ JS URLs from the modulepreload links plus 2 from the inline script, giving a much larger seed set than the adapter-node case.
109
109
 
110
- **`__vite_mapDeps` path formats**: SvelteKit emits `m.f = ["../nodes/0.js", "../chunks/x.js", ...]` (file-relative paths) inside entry chunks at `_app/immutable/entry/`. Vue and React emit `m.f = ["/assets/chunk.js", ...]` (root-relative paths). `react_followImports` differentiates by checking `p.startsWith("/")` absolute paths resolve against the origin (`baseUrl`), relative paths resolve against the chunk's own URL (`fileUrl`). See `src/lazyload/react/CLAUDE.md` for details.
110
+ **`__vite_mapDeps` path formats**: SvelteKit emits `m.f = ["../nodes/0.js", "../chunks/x.js", ...]` (explicit file-relative paths) inside entry chunks at `_app/immutable/entry/`. Vue and React can emit either `m.f = ["/assets/chunk.js", ...]` (absolute root-relative) or `m.f = ["assets/chunk.js", ...]` (bare root-relative, no leading `/`). `react_followImports` differentiates by checking for a `./` or `../` prefix: only explicitly relative paths resolve against the chunk's own URL (`fileUrl`); all others (absolute `/` or bare names) resolve against the origin (`baseUrl`). Bare names like `assets/x.js` must NOT be resolved against `fileUrl` — when the chunk is inside `assets/`, that would produce a double-directory path. See `src/lazyload/react/CLAUDE.md` for details.
111
111
 
112
112
  ### Batch mode
113
113
 
@@ -200,6 +200,7 @@ Rule categories:
200
200
 
201
201
  - `ast/` — AST-based pattern matching against chunk code (uses `@babel/parser` + `esquery`)
202
202
  - `request/` — OpenAPI/request-level checks against the resolved endpoint list
203
+ - `cs-mast-s/` — CS-MAST-S structural signature matching; each step embeds a PHC string and fires if that node-level hash is found anywhere in the chunk AST. Suitable for regression detection after a vulnerability is confirmed via AST rules. See `src/analyze/engine/csMastSEngine.ts` and `src/analyze/CLAUDE.md` for details.
203
204
 
204
205
  When `-r` points to a single file, only that rule is loaded. When it points to a directory, all `.yml`/`.yaml` files are loaded recursively.
205
206
 
@@ -207,11 +208,137 @@ When `-r` points to a single file, only that rule is loaded. When it points to a
207
208
 
208
209
  **Testing is mandatory for every change.** Before reporting a task complete:
209
210
 
210
- 1. Run `npm run cleanup` to rebuild TypeScript.
211
- 2. Run the `run` subcommand against the target the user provides. Do not use `analyze` or other individual subcommands as a substitute — the `run` subcommand must be used to validate end-to-end behavior.
212
- 3. If the user has not provided a target, ask for one before proceeding.
211
+ 1. Run `npm test` to execute the unit test suite (Vitest).
212
+ 2. Run `npm run cleanup` to rebuild TypeScript.
213
+ 3. Run the `run` subcommand against the target the user provides. Do not use `analyze` or other individual subcommands as a substitute the `run` subcommand must be used to validate end-to-end behavior.
214
+ 4. If the user has not provided a target, ask for one before proceeding.
213
215
 
214
- Typical test invocation:
216
+ ### Rules smoke test (CI)
217
+
218
+ The `rules-smoke-test` GitHub Actions workflow (`.github/workflows/rules-smoke-test.yaml`) runs on every non-main push. It:
219
+
220
+ 1. Checks out `shriyanss/js-recon-labs` and `shriyanss/js-recon-rules` alongside js-recon.
221
+ 2. Builds js-recon and the `next_js/vuln-all-rules` lab app.
222
+ 3. Starts the lab app on port 3001.
223
+ 4. Runs `node build/index.js run -u http://localhost:3001 -r ./js-recon-rules --no-sandbox -y -k`.
224
+ 5. Runs `node scripts/smoke-test.js` which reads `output/localhost:3001/analyze.json` and asserts that all 22 expected rule IDs are present.
225
+
226
+ **`scripts/smoke-test.js`** maintains the `EXPECTED_RULES` list. When a new rule is added to js-recon-rules:
227
+
228
+ - The `next_js/vuln-all-rules` app in js-recon-labs must be updated to seed the new vulnerability.
229
+ - The new rule ID must be appended to `EXPECTED_RULES` in `scripts/smoke-test.js`.
230
+
231
+ The lab app seeds:
232
+
233
+ - 19 AST rules for the `next` tech stack
234
+ - 3 request rules (`api_path`, `admin_api`, `missing_authorization_header`)
235
+ - The Angular-only rule (`detect_angular_bypass_security_trust`) is intentionally excluded.
236
+
237
+ ### Unit tests
238
+
239
+ Unit tests live in `src/__tests__/` and cover pure-logic components. Test framework is **Vitest** (ESM-native, TypeScript-native — no compilation step needed).
240
+
241
+ ```bash
242
+ npm test # run all unit tests once
243
+ npm run test:watch # watch mode
244
+ npm run test:build # legacy build smoke test (node build/index.js -h)
245
+ ```
246
+
247
+ Test files follow the pattern `src/__tests__/<component>/<name>.test.ts`.
248
+
249
+ Covered components:
250
+
251
+ | File | Tests in |
252
+ | ---------------------------------------------------------------------------------------- | ------------------------------------------------------ |
253
+ | `utility/urlUtils.ts` — `getURLDirectory` | `src/__tests__/utility/urlUtils.test.ts` |
254
+ | `utility/replaceUrlPlaceholders.ts` — `replacePlaceholders` | `src/__tests__/utility/replaceUrlPlaceholders.test.ts` |
255
+ | `utility/resolvePath.ts` — `resolvePath` | `src/__tests__/utility/resolvePath.test.ts` |
256
+ | `strings/index.ts` — `extractStrings` | `src/__tests__/strings/extractStrings.test.ts` |
257
+ | `analyze/helpers/validate.ts` — `parseVersion`, `compareVersions`, `isVersionCompatible` | `src/__tests__/analyze/versionCompat.test.ts` |
258
+ | `map/next_js/utils.ts` — `memberChainToString` | `src/__tests__/map/memberChainToString.test.ts` |
259
+ | `fingerprint/index.ts` — `deriveOutputPath` | `src/__tests__/fingerprint/deriveOutputPath.test.ts` |
260
+
261
+ When adding new pure-logic helpers, add a corresponding test file. Components that require Puppeteer, network I/O, or the full pipeline are still validated through the `run` subcommand.
262
+
263
+ ### Writing unit tests
264
+
265
+ **What to test.** Test pure functions: anything that takes plain inputs and returns a value without I/O. The standard pattern for I/O-bound modules is to extract the parse/transform step into an exported pure function and test that. Leave the orchestrator (Puppeteer, `makeRequest`, file writes) untested at the unit level.
266
+
267
+ **Extracting testable functions.** When a function mixes I/O with logic, split it:
268
+
269
+ ```typescript
270
+ // Exported pure function — testable
271
+ export const parseThings = (content: string, baseUrl: string): string[] => { ... };
272
+
273
+ // Orchestrator — not unit-tested
274
+ const myModule = async (url: string): Promise<string[]> => {
275
+ const resp = await makeRequest(url);
276
+ const content = await resp.text();
277
+ return parseThings(content, url);
278
+ };
279
+ ```
280
+
281
+ **Test file structure.** Use `describe` + `it` blocks. Group by function name. Cover: happy path, edge cases (empty input, malformed input), and threshold boundaries (e.g. "fewer than N entries returns []").
282
+
283
+ ```typescript
284
+ import { describe, it, expect } from "vitest";
285
+ import { myPureFunction } from "../../path/to/module.js"; // .js extension required
286
+
287
+ describe("myPureFunction", () => {
288
+ it("extracts X from valid input", () => {
289
+ const result = myPureFunction("...");
290
+ expect(result).toContain("expected");
291
+ });
292
+
293
+ it("returns [] for empty input", () => {
294
+ expect(myPureFunction("")).toEqual([]);
295
+ });
296
+
297
+ it("returns [] for invalid JS", () => {
298
+ expect(myPureFunction("{{{{ not valid")).toEqual([]);
299
+ });
300
+ });
301
+ ```
302
+
303
+ **Imports always use `.js` extension** for local files (ESM project with `"module": "node16"`):
304
+
305
+ ```typescript
306
+ import { fn } from "../../lazyLoad/next_js/myModule.js";
307
+ ```
308
+
309
+ **Constructing Babel AST nodes for tests.** When a function under test requires real Babel AST nodes (with `scope`, `path`, correct `start`/`end` offsets), parse a code snippet in the test and capture the node via a traverse visitor — do not construct AST nodes by hand. Wrap the expression in a `const _x = <expr>;` declaration so `start`/`end` offsets are preserved for any `code.slice()` calls inside the function:
310
+
311
+ ```typescript
312
+ import parser from "@babel/parser";
313
+ import _traverse from "@babel/traverse";
314
+ const traverse = (_traverse.default ?? _traverse) as typeof _traverse.default;
315
+
316
+ function parseExpr(code: string) {
317
+ const src = `const _x = ${code};`;
318
+ const ast = parser.parse(src, { sourceType: "unambiguous", plugins: ["jsx", "typescript"] });
319
+ let node: any;
320
+ traverse(ast, {
321
+ VariableDeclarator(p) {
322
+ node = p.node.init;
323
+ p.stop();
324
+ },
325
+ });
326
+ return { node, src };
327
+ }
328
+ ```
329
+
330
+ **Avoiding GitHub secret scanning.** Strings that look like real secrets (Slack webhook URLs, Stripe keys, etc.) will be blocked by GitHub push protection even in test files. Construct them at runtime from parts arrays:
331
+
332
+ ```typescript
333
+ // BAD — blocked by secret scanner
334
+ const url = "https://hooks.slack.com/services/TABCDEF/BABCDEF/xxxxxxxxxxxx";
335
+
336
+ // GOOD — assembled at runtime
337
+ const parts = ["https://hooks.slack.com/services/T", "ABCDEF/B", "ABCDEF/xxxx"];
338
+ const url = parts.join("");
339
+ ```
340
+
341
+ Typical full test invocation:
215
342
 
216
343
  ```bash
217
344
  npm run cleanup && npm run start -- run -u <target-url> -y -k
@@ -274,26 +401,44 @@ Before writing any files, gather the current state:
274
401
 
275
402
  Previous tag is left to GitHub's automatic detection (do not set `--target` or `--tag` beyond the tag name itself).
276
403
 
277
- 9. **Wait for npm publish** — monitor the release pipeline: `gh run list --repo shriyanss/js-recon --workflow release`. Confirm the npm package is live at the new version before proceeding to Phase 2.
404
+ 9. **Wait for npm stage publish** — monitor the release pipeline: `gh run list --repo shriyanss/js-recon --workflow "Publish JS Recon"`. `publish-npm` uses OIDC trusted publishing (`npm stage publish`, no token) to _stage_ the release this is NOT the same as it being live.
405
+
406
+ 10. **Approve the staged release** — npm's staged-publish approval always requires interactive 2FA, so this step can never be automated or scripted:
278
407
 
279
- ### Homebrew tap (automatic, runs in parallel with Phase 2)
408
+ - Find the stage id: `npm stage list @shriyanss/js-recon` (or the "Staged Packages" tab on npmjs.com)
409
+ - Approve it: `npm stage approve <stage-id>` (prompts for 2FA), or click "Approve" on npmjs.com
410
+ - Confirm it's live: `npm view @shriyanss/js-recon@<version>`
280
411
 
281
- After `publish-npm` succeeds, the `update-homebrew-tap` job in `publish-js-recon.yml` runs automatically. It:
412
+ 11. **Manually trigger the promote workflow** once the release is live, run `promote-js-recon.yml` to update Homebrew and publish the Docker/GHCR images:
282
413
 
283
- 1. Computes the SHA256 of the published npm tarball from the public npmjs.org URL (no auth)
414
+ ```bash
415
+ gh workflow run promote-js-recon.yml --repo shriyanss/js-recon -f version=<version>
416
+ ```
417
+
418
+ This workflow installs js-recon from the published npm registry artifact (`npm pack`/`npm install <pkg>@<version>`) rather than building from git source — an additional supply-chain check that the shipped images/formula match exactly what was approved on npm. Monitor: `gh run list --repo shriyanss/js-recon --workflow "Promote JS Recon Release"`.
419
+
420
+ ### Homebrew tap (manual, part of `promote-js-recon.yml`)
421
+
422
+ The `update-homebrew-tap` job (now in `promote-js-recon.yml`, triggered per step 11 above):
423
+
424
+ 1. `npm pack @shriyanss/js-recon@<version>` — downloads the exact published tarball from the registry and computes its SHA256 locally (no dependency on a public tarball URL being reachable yet)
284
425
  2. Checks out `shriyanss/homebrew-tap` using `HOMEBREW_TAP_TOKEN` (a fine-grained PAT stored in `shriyanss/js-recon` secrets, scoped to `homebrew-tap` repo `Contents: Read and write` only — automatically masked in all log output, never echoed)
285
- 3. Updates `version`, `url`, and `sha256` in `Formula/js-recon.rb` via anchored `sed`
426
+ 3. Updates `url` and `sha256` in `Formula/js-recon.rb` via anchored `sed` — the formula has no explicit `version` field; Homebrew derives it from the `url`
286
427
  4. Commits `chore: update js-recon formula to <version>` and pushes
287
428
 
288
429
  Monitor: `gh run list --repo shriyanss/homebrew-tap --workflow ci.yml`
289
430
 
290
- **If the job fails:** The npm package is already live. Manually update: compute `curl -fsSL <tarball-url> | sha256sum`, edit `Formula/js-recon.rb`, commit, and push to `shriyanss/homebrew-tap`.
431
+ **If the job fails:** manually update: `npm pack @shriyanss/js-recon@<version> && sha256sum shriyanss-js-recon-<version>.tgz`, edit `Formula/js-recon.rb`, commit, and push to `shriyanss/homebrew-tap`.
291
432
 
292
433
  **One-time setup** (must be done before the first release, already completed):
293
434
 
294
435
  - `shriyanss/homebrew-tap` is a public GitHub repo with the formula at `Formula/js-recon.rb`
295
436
  - `HOMEBREW_TAP_TOKEN` is a fine-grained PAT stored in `shriyanss/js-recon` → Settings → Secrets → Actions, scoped exclusively to the `homebrew-tap` repo
296
437
 
438
+ ### Docker / GHCR images (manual, part of `promote-js-recon.yml`)
439
+
440
+ `publish-docker` and `publish-ghcr` (now in `promote-js-recon.yml`) build from `Dockerfile.release` instead of the default `Dockerfile`. `Dockerfile.release` runs `npm install -g @shriyanss/js-recon@<version>` against the live registry rather than copying local source and building — the published images are provably built from the approved npm artifact. The default `Dockerfile` (source build) is unchanged and still used for local/dev builds.
441
+
297
442
  ### Phase 2 — js-recon-docs (after npm is live)
298
443
 
299
444
  10. **Fix doc gaps** — cross-check `docs/docs/modules/*.md` against `src/index.ts` and the new CHANGELOG entries. Add or update any missing flags, options, or command descriptions.
@@ -384,6 +529,11 @@ When a user asks to fix or implement a GitHub issue, follow these steps:
384
529
  - `--min-collisions <n>` — minimum occurrences to report (default: 2)
385
530
  - `--co / --collision-output <file>` — write collision data to a file (independent of `--ct`)
386
531
  - `--cf / --collision-format json|csv` — output format (default: csv)
532
+ - `--scat <categories>` — comma-separated scat categories to use (default: `lit,decl,loop,cond`). Overrides the fixed config for this run.
533
+ - `--sinc <nodes>` — comma-separated exact node types to include via sinc (e.g. `IfStatement`).
534
+ - `--all-scat-permutations` — run all 511 non-empty scat subsets and write one collision file per subset to `--perm-output`.
535
+ - `--perm-output <dir>` — output directory for per-permutation files (required with `--all-scat-permutations`).
536
+ - `--perm-concurrency <n>` — parallel permutation workers (default: half of CPU count).
387
537
 
388
538
  **`--co` path resolution:** if the given path is a directory or has no extension, the file is written as `collisions.<fmt>` in the current working directory.
389
539
 
@@ -395,15 +545,28 @@ When a user asks to fix or implement a GitHub issue, follow these steps:
395
545
  npm run build
396
546
  node build/index.js cs-mast -o output --ct --min-collisions 2
397
547
  node build/index.js cs-mast -o output --co output --cf csv # writes ./collisions.csv
548
+ node build/index.js cs-mast -o output --all-scat-permutations --perm-output ./perm-out --cf json
398
549
  ```
399
550
 
400
551
  ## refactor
401
552
 
402
- The `refactor` command supports three techs:
553
+ The `refactor` command supports the following techs:
403
554
 
404
555
  - **`react-webpack`** — webpack 5 React bundles. Splits a numeric module map into per-module ES files, rewrites require→import, recovers JSX. See `src/refactor/react/CLAUDE.md`.
405
556
  - **`react-vite`** — Vite (rolldown) React bundles. Removes CJS interop wrappers, rewrites vendor imports to canonical library imports (`react`, `react/jsx-runtime`, etc.), recovers JSX. Runs a Vite build check after writing output. See `src/refactor/react-vite/CLAUDE.md`.
406
557
  - **`next`** — Next.js bundles (legacy).
558
+ - **`next-turbopack`** — Next.js Turbopack chunks. Handles both turbopack 3-param `func_NNN=(runtime,module,exports)=>{}` and 1-param `func_NNN=(runtime)=>{}` formats plus webpack-style coexisting chunks. See `src/refactor/next/CLAUDE.md`.
559
+ - **`next-webpack`** — Next.js webpack chunks. Input format from `mapped.json`: `NNN:(module,exports,require)=>{}`. Recovers named exports (ODP, require.d), default exports (module.exports=V), re-exports (module.exports=require(N)→export*), and require hoisting. 277/280 modules recovered on a real bundle. Param order: params[0]=module, params[1]=exports, params[2]=require. See `src/refactor/next/CLAUDE.md`.
560
+ - **`vue-webpack`** — Vue.js webpack 4/5 chunks. Container format: `(window.webpackJsonp||[]).push([[chunkIds],{moduleId:function(t,e,r){...}}])`. Each chunk file may contain multiple module functions; each is extracted and transformed. Reuses the Next.js webpack transform (same module param semantics: params[0]=module, params[1]=exports, params[2]=require). See `src/refactor/vue/index.ts`.
561
+ - **`vue-vite`** — Vue 3 + Vite page chunks. The main index chunk (contains `__vccOpts`, all of Vue runtime) is analysed to build an export-alias→canonical-name map. Lazy page chunks then have their index imports rewritten to canonical `import {...} from 'vue'` statements. The `_export_sfc` compiler helper is inlined as a local const. See `src/refactor/vue/vite.ts` and `src/refactor/vue/vendor-analyze-vue.ts`.
562
+
563
+ ### Known react-vite bugs (discovered 2026-07-01, test against js-recon-research/react/20-cve-app)
564
+
565
+ **Multi-chunk file overwrite** — `map` segments each Vite chunk into multiple sub-chunks (one per top-level function). The refactor write path processes sub-chunks sequentially, each overwriting the previous output file. Only the last sub-chunk survives. For chunks with inlined library code followed by the component function (e.g. `ApiProxy`, `Editor`, `Search`), this means the component is the survivor (last in the map order), which is the correct and useful result — but any app-specific helper functions in the same chunk are also lost.
566
+
567
+ **Rename race** — When JSX is detected in a sub-chunk, the write path renames the output file `.js` → `.jsx`. When the same file is written by multiple sub-chunks, the rename is attempted on each JSX-containing chunk; all attempts after the first throw `ENOENT` because the `.js` file was already renamed. The `.jsx` file is correct; the unhandled rejection is noise. Fix: track which output files have already been renamed.
568
+
569
+ **Remote signatures** — The `react/vite/large` HuggingFace bucket is currently empty. The tool falls back gracefully with a warning but remote library stripping is disabled. Symptom: `[!] No remote collisions files found for scat "lit-decl-loop-cond" in branch "react/vite/large"`. Fix: populate the bucket by running CS-MAST-S generation against a corpus of large Vite apps.
407
570
 
408
571
  ### refactor `--collisions <file>` (react-webpack only)
409
572
 
@@ -413,6 +576,37 @@ Plumbing: `src/index.ts` (CLI) → `src/refactor/index.ts` (resolves the path vi
413
576
 
414
577
  The baseline files live in the sibling `js-recon-cs-mast-s/` repo (`baselines/<tech>/<scat>/collisions.json`). See its `README.md` for layout and provenance.
415
578
 
579
+ ### refactor `--detect-version` (react-webpack, react-vite)
580
+
581
+ `refactor -t react-webpack` and `refactor -t react-vite` accept a `--detect-version` flag that uses CS-MAST signatures to detect the React version used in the bundle.
582
+
583
+ **Related flags:**
584
+
585
+ - `--detect-version-config <config>` — `"dynamic"` (default) or comma-separated scat categories (e.g. `lit,decl,loop,cond`).
586
+ - `--detect-version-dynamic-threshold <n>` — number of scat configs to use in dynamic mode (default: 3).
587
+ - `--detect-version-dynamic-conf-purge` — clears the cached dynamic scat config and recomputes.
588
+
589
+ **How it works:**
590
+
591
+ 1. **Scat config resolution** (`resolveVersionDetectionScatDirs()` in `src/refactor/index.ts`):
592
+ - `dynamic` mode: reads cached scat configs from `~/.js-recon/refactor/config.json`. If absent (or purged), calls `selectDynamicScatConfigs()` which lists scat dirs from the HF bucket for a reference version, then validates that each scat dir has non-empty `reliable_signatures.json` for ALL versions. Saves the result to `config.json`.
593
+ - Static mode: parses the user's comma-separated categories, converts to a bucket dir name via `scatToDir()`, validates against all versions, and exits with code 26 if any version's file is empty.
594
+ 2. `generateBundleSignatures()` in `src/refactor/remote/version-detect.ts` runs `cs_mast_init` on every chunk + optional extra code snippets for each selected scat config. This produces a separate signature set per scat.
595
+ 3. For each available React version, `fetchReliableSignatures()` downloads (or loads from cache) the `reliable_signatures.json` per scat config. Match counts are **summed across all scat configs** per version.
596
+ 4. The version with the highest total match count is returned as the detected version.
597
+ 5. The detected version's npm semver is used to pin `react` and `react-dom` in the refactored output's `package.json`.
598
+
599
+ **Caches:**
600
+
601
+ - Signature cache: `~/.js-recon/refactor/version_sigs_cache/<bundler>/<version>/<scatDir>/reliable_signatures.json` + `.cached_at` (7-day TTL).
602
+ - Dynamic config cache: `~/.js-recon/refactor/config.json` (`dynamicVersionDetectionScatConfig` field).
603
+
604
+ **Dataset coverage:** webpack (react-0.12 through react-19), vite (react-16 through react-19).
605
+
606
+ **Important:** the version detection data in the HF bucket was generated with `@shriyanss/cs-mast` v0.1.8. The tool requires cs-mast 0.1.8 or later to produce matching signatures. Using an older cs-mast version will result in zero matches.
607
+
608
+ **Important:** the version detection data in the HF bucket was generated with `@shriyanss/cs-mast` v0.1.8. The tool requires cs-mast 0.1.8 or later to produce matching signatures. Using an older cs-mast version will result in zero matches.
609
+
416
610
  ## Security / confidentiality
417
611
 
418
612
  When a change is informed by behavior observed on a real target (URLs, endpoint names, response shapes, finding details, etc.):
@@ -0,0 +1,29 @@
1
+ FROM ghcr.io/puppeteer/puppeteer:25.3.0
2
+
3
+ WORKDIR /home/pptruser
4
+
5
+ USER root
6
+ ENV PUPPETEER_SKIP_DOWNLOAD=true
7
+ RUN apt-get update && apt-get install -y --no-install-recommends \
8
+ unzip \
9
+ libnspr4 libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 \
10
+ libxcomposite1 libxdamage1 libxrandr2 libgbm1 libxkbcommon0 \
11
+ libasound2 libpangocairo-1.0-0 libxfixes3 libxi6 libxinerama1 \
12
+ libxcursor1 libdrm2 && \
13
+ rm -rf /var/lib/apt/lists/*
14
+
15
+ ARG JS_RECON_VERSION
16
+ RUN npm install -g @shriyanss/js-recon@${JS_RECON_VERSION}
17
+
18
+ USER pptruser
19
+ RUN "$(npm root -g)/@shriyanss/js-recon/node_modules/.bin/puppeteer" browsers install chrome && \
20
+ for zip in /home/pptruser/.cache/puppeteer/chrome/*-chrome-linux64.zip; do \
21
+ [ -f "$zip" ] || break; \
22
+ version="${zip%-chrome-linux64.zip}"; version="${version##*/}"; \
23
+ dest="/home/pptruser/.cache/puppeteer/chrome/linux-${version}"; \
24
+ unzip -o "$zip" -d "${dest}/" && chmod +x "${dest}/chrome-linux64/chrome"; \
25
+ done
26
+
27
+ ENV IS_DOCKER=true
28
+ ENV NODE_OPTIONS="--max-http-header-size=99999999"
29
+ ENTRYPOINT ["js-recon"]
package/README.md CHANGED
@@ -69,28 +69,29 @@ js-recon run -u https://app.example.com
69
69
 
70
70
  `js-recon` provides a suite of commands for comprehensive JavaScript analysis. For detailed usage and examples, please refer to its full documentation.
71
71
 
72
- | Command | Description | Documentation |
73
- | ------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------- |
74
- | `lazyload` | Downloads dynamically loaded JavaScript files from a target. | [Read Docs](https://js-recon.io/docs/docs/modules/lazyload) |
75
- | `endpoints` | Extracts API endpoints and client-side paths from JS files. | [Read Docs](https://js-recon.io/docs/docs/modules/endpoints) |
76
- | `strings` | Extracts strings, URLs, and potential secrets from JS files. | [Read Docs](https://js-recon.io/docs/docs/modules/strings) |
77
- | `map` | Maps function calls and analyzes code, with optional AI-powered descriptions. | [Read Docs](https://js-recon.io/docs/docs/modules/map) |
78
- | `api-gateway` | Manages AWS API Gateway for IP rotation to bypass rate limits. | [Read Docs](https://js-recon.io/docs/docs/modules/api-gateway) |
79
- | `run` | Runs all analysis modules automatically on a target. | [Read Docs](https://js-recon.io/docs/docs/modules/run) |
80
- | `analyze` | Analyzes the code. | [Read Docs](https://js-recon.io/docs/docs/modules/analyze) |
81
- | `report` | Generates a report from the analysis modules. | [Read Docs](https://js-recon.io/docs/docs/modules/report) |
82
- | `mcp` | AI-powered interactive CLI, one-shot chat, and MCP stdio server. | [Read Docs](https://js-recon.io/docs/docs/modules/mcp) |
83
- | `fingerprint` | Detects the JavaScript framework used by a target URL (JSON/JSONL output). | [Read Docs](https://js-recon.io/docs/docs/modules/fingerprint) |
84
- | `refactor` | Refactors and deobfuscates webpack modules from a mapped JSON file. | [Read Docs](https://js-recon.io/docs/docs/modules/refactor) |
85
- | `load` | Populates the response cache from a Caido or Burp Suite export. | [Read Docs](https://js-recon.io/docs/docs/modules/load) |
86
- | `cs-mast` | Computes CS-MAST structural hashes for JS files and finds hash collisions. | [Read Docs](https://js-recon.io/docs/docs/modules/cs-mast) |
87
- | `sourcemaps` | Extracts original source files from `.map` sourcemap files. | [Read Docs](https://js-recon.io/docs/docs/modules/sourcemaps) |
72
+ | Command | Description | Documentation |
73
+ | ------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------- |
74
+ | `lazyload` | Downloads dynamically loaded JavaScript files from a target. | [Read Docs](https://js-recon.io/docs/docs/modules/lazyload) |
75
+ | `endpoints` | Extracts API endpoints and client-side paths from JS files. | [Read Docs](https://js-recon.io/docs/docs/modules/endpoints) |
76
+ | `strings` | Extracts strings, URLs, and potential secrets from JS files. | [Read Docs](https://js-recon.io/docs/docs/modules/strings) |
77
+ | `map` | Maps function calls and analyzes code, with optional AI-powered descriptions. | [Read Docs](https://js-recon.io/docs/docs/modules/map) |
78
+ | `api-gateway` | Manages AWS API Gateway for IP rotation to bypass rate limits. | [Read Docs](https://js-recon.io/docs/docs/modules/api-gateway) |
79
+ | `run` | Runs all analysis modules automatically on a target. | [Read Docs](https://js-recon.io/docs/docs/modules/run) |
80
+ | `analyze` | Analyzes the code. | [Read Docs](https://js-recon.io/docs/docs/modules/analyze) |
81
+ | `report` | Generates a report from the analysis modules. | [Read Docs](https://js-recon.io/docs/docs/modules/report) |
82
+ | `mcp` | AI-powered interactive CLI, one-shot chat, and MCP stdio server. | [Read Docs](https://js-recon.io/docs/docs/modules/mcp) |
83
+ | `fingerprint` | Detects the JavaScript framework used by a target URL (JSON/JSONL output). | [Read Docs](https://js-recon.io/docs/docs/modules/fingerprint) |
84
+ | `refactor` | Recovers readable JSX and strips library code from React (webpack/Vite) bundles. | [Read Docs](https://js-recon.io/docs/docs/modules/refactor) |
85
+ | `load` | Populates the response cache from a Caido or Burp Suite export. | [Read Docs](https://js-recon.io/docs/docs/modules/load) |
86
+ | `cs-mast` | Computes CS-MAST structural hashes for JS files and finds hash collisions. | [Read Docs](https://js-recon.io/docs/docs/modules/cs-mast) |
87
+ | `sourcemaps` | Extracts original source files from `.map` sourcemap files. | [Read Docs](https://js-recon.io/docs/docs/modules/sourcemaps) |
88
+ | `completion` | Generates shell completion scripts for bash, zsh, or fish. | [Read Docs](https://js-recon.io/docs/docs/modules/completion) |
88
89
 
89
90
  ## Key Features
90
91
 
91
92
  - Downloads all dynamically loaded JS files (refered as `lazyload`) from website with supported frameworks
92
93
  - Use API gateway to rotate IP addresses to bypass firewall
93
- - Extract strings from the discovered JS files, and extract potential secrets, endpoints, etc. from them
94
+ - Extract strings from the discovered JS files, and extract potential secrets, endpoints, etc. from them (built-in scanner via `--secrets`; TruffleHog integration via `--trufflehog`)
94
95
  - Endpoints modules extracts client-side paths from the app
95
96
  - Map feature analyzes the JS files and outputs it to a JSON file. An interactive mode can be then used to analyze it
96
97
  - Reconstruct HTTP requests that the app makes to the server, and output them to the OpenAPI spec
@@ -0,0 +1,129 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import chalk from "chalk";
11
+ import { cs_mast_init, parseSignature, ParseError } from "@shriyanss/cs-mast";
12
+ /**
13
+ * Walk all AdapterNode descendants post-order and check if any node's
14
+ * computedHash equals the target hex hash. The _signatureMap built by
15
+ * cs_mast_init only stores leaf-level node signatures; to match the
16
+ * compound (internal-node) signatures produced by the experiment scripts
17
+ * (buildSignatureFromConfig on a specific subtree), we must walk the tree
18
+ * and compare computedHash directly.
19
+ */
20
+ function treeContainsHash(node, targetHashHex) {
21
+ var _a;
22
+ if (node.computedHash === targetHashHex)
23
+ return true;
24
+ for (const child of (_a = node.children) !== null && _a !== void 0 ? _a : []) {
25
+ if (treeContainsHash(child, targetHashHex))
26
+ return true;
27
+ }
28
+ return false;
29
+ }
30
+ /**
31
+ * CS-MAST-S analysis engine. Checks whether a CS-MAST-S signature (PHC string)
32
+ * exists anywhere in a chunk's AST. Suitable for regression detection: once a
33
+ * vulnerability is confirmed via the AST engine, its signature can be embedded
34
+ * in a cs-mast-s rule to track whether the same code reappears in future builds.
35
+ *
36
+ * Each step must contain a `csMastS.signature` (PHC string). The scat config is
37
+ * derived automatically from the signature — no separate config field is needed.
38
+ * All steps must match in the same chunk for a finding to fire.
39
+ *
40
+ * @param rule - The cs-mast-s rule with signature steps
41
+ * @param mappedJsonData - Code chunks from mapped.json
42
+ * @returns Array of findings
43
+ */
44
+ const csMastSEngine = (rule, mappedJsonData) => __awaiter(void 0, void 0, void 0, function* () {
45
+ const findings = [];
46
+ for (const chunk of Object.values(mappedJsonData)) {
47
+ // Cache cs_mast trees by config fingerprint to avoid redundant parses when
48
+ // multiple steps share the same scat config.
49
+ const treeCache = new Map();
50
+ const completedSteps = new Set();
51
+ for (const step of rule.steps) {
52
+ // Honor requires: skip if any prerequisite step didn't match.
53
+ if (step.requires && step.requires.length > 0) {
54
+ const allMet = step.requires.every((r) => completedSteps.has(r));
55
+ if (!allMet)
56
+ continue;
57
+ }
58
+ if (!step.csMastS)
59
+ continue;
60
+ const { signature } = step.csMastS;
61
+ const parsed = parseSignature(signature);
62
+ if (!parsed) {
63
+ console.log(chalk.yellow(`[!] cs-mast-s step "${step.name}" in rule "${rule.id}" has an invalid signature — skipping`));
64
+ continue;
65
+ }
66
+ const config = {
67
+ hash: parsed.hash,
68
+ lang: parsed.lang,
69
+ prsr: parsed.prsr,
70
+ scat: parsed.scat,
71
+ sinc: parsed.sinc,
72
+ sourceType: "unambiguous",
73
+ };
74
+ // Build a stable cache key from the config fields that affect the hash tree.
75
+ const configKey = `${config.hash}:${config.lang}:${config.prsr}:${config.scat.join("_")}:${config.sinc.join("_")}`;
76
+ let tree;
77
+ if (treeCache.has(configKey)) {
78
+ tree = treeCache.get(configKey);
79
+ }
80
+ else {
81
+ try {
82
+ tree = cs_mast_init(chunk.code, config);
83
+ treeCache.set(configKey, tree);
84
+ }
85
+ catch (e) {
86
+ if (e instanceof ParseError) {
87
+ // Chunk is unparseable — skip silently (mirrors astEngine behavior).
88
+ break;
89
+ }
90
+ throw e;
91
+ }
92
+ }
93
+ if (treeContainsHash(tree.root, parsed.hashHex)) {
94
+ completedSteps.add(step.name);
95
+ }
96
+ }
97
+ // Fire only if every step in the rule completed (matched).
98
+ if (completedSteps.size === rule.steps.length) {
99
+ const matchedSigs = rule.steps.filter((s) => s.csMastS).map((s) => s.csMastS.signature);
100
+ const message = `[+] "${rule.name}" found in chunk ${chunk.id}`;
101
+ if (rule.severity === "info") {
102
+ console.log(chalk.cyan(message));
103
+ }
104
+ else if (rule.severity === "low") {
105
+ console.log(chalk.yellow(message));
106
+ }
107
+ else if (rule.severity === "medium") {
108
+ console.log(chalk.magenta(message));
109
+ }
110
+ else if (rule.severity === "high") {
111
+ console.error(chalk.red(message));
112
+ }
113
+ findings.push({
114
+ ruleId: rule.id,
115
+ ruleName: rule.name,
116
+ ruleType: rule.type,
117
+ ruleDescription: rule.description,
118
+ ruleAuthor: rule.author,
119
+ ruleTech: rule.tech,
120
+ severity: rule.severity,
121
+ message,
122
+ findingLocation: `// chunk: ${chunk.id}\n// CS-MAST-S signature: ${matchedSigs.join(", ")}`,
123
+ });
124
+ }
125
+ }
126
+ return findings;
127
+ });
128
+ export default csMastSEngine;
129
+ //# sourceMappingURL=csMastSEngine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csMastSEngine.js","sourceRoot":"","sources":["../../../src/analyze/engine/csMastSEngine.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import requestEngine from "./requestEngine.js";
11
11
  import astEngine from "./astEngine.js";
12
+ import csMastSEngine from "./csMastSEngine.js";
12
13
  /**
13
14
  * Main analysis engine that routes rules to appropriate sub-engines based on rule type.
14
15
  *
@@ -53,6 +54,20 @@ export const engine = (rule, mappedJsonData, openapiData, tech) => __awaiter(voi
53
54
  findings.push(...(yield astEngine(rule, mappedJsonData)));
54
55
  }
55
56
  }
57
+ else if (rule.type === "cs-mast-s") {
58
+ if (!mappedJsonData) {
59
+ return;
60
+ }
61
+ let techValid = true;
62
+ for (const t of rule.tech) {
63
+ if (!rule.tech.includes(tech)) {
64
+ techValid = false;
65
+ }
66
+ }
67
+ if (techValid || tech === "all" || rule.tech.includes("all")) {
68
+ findings.push(...(yield csMastSEngine(rule, mappedJsonData)));
69
+ }
70
+ }
56
71
  return findings;
57
72
  });
58
73
  export default engine;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyze/engine/index.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAC/C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AAGvC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAClB,IAAU,EACV,cAAkC,EAClC,WAAoC,EACpC,IAA6D,EAC1B,EAAE;IACrC,yGAAyG;IAEzG,IAAI,QAAQ,GAAmB,EAAE,CAAC;IAElC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;YACf,OAAO;QACX,CAAC;QAED,IAAI,SAAS,GAAG,IAAI,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,SAAS,GAAG,KAAK,CAAC;YACtB,CAAC;QACL,CAAC;QAED,IAAI,SAAS,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC;IACL,CAAC;SAAM,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,cAAc,EAAE,CAAC;YAClB,OAAO;QACX,CAAC;QAED,IAAI,SAAS,GAAG,IAAI,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,SAAS,GAAG,KAAK,CAAC;YACtB,CAAC;QACL,CAAC;QAED,IAAI,SAAS,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC,CAAA,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyze/engine/index.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAC/C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAG/C;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAClB,IAAU,EACV,cAAkC,EAClC,WAAoC,EACpC,IAA6D,EAC1B,EAAE;IACrC,yGAAyG;IAEzG,IAAI,QAAQ,GAAmB,EAAE,CAAC;IAElC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;YACf,OAAO;QACX,CAAC;QAED,IAAI,SAAS,GAAG,IAAI,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,SAAS,GAAG,KAAK,CAAC;YACtB,CAAC;QACL,CAAC;QAED,IAAI,SAAS,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC;IACL,CAAC;SAAM,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,cAAc,EAAE,CAAC;YAClB,OAAO;QACX,CAAC;QAED,IAAI,SAAS,GAAG,IAAI,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,SAAS,GAAG,KAAK,CAAC;YACtB,CAAC;QACL,CAAC;QAED,IAAI,SAAS,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;IACL,CAAC;SAAM,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QACnC,IAAI,CAAC,cAAc,EAAE,CAAC;YAClB,OAAO;QACX,CAAC;QAED,IAAI,SAAS,GAAG,IAAI,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,SAAS,GAAG,KAAK,CAAC;YACtB,CAAC;QACL,CAAC;QAED,IAAI,SAAS,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;QAClE,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC,CAAA,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -1,5 +1,6 @@
1
+ var _a;
1
2
  import _traverse from "@babel/traverse";
2
- const traverse = _traverse.default;
3
+ const traverse = ((_a = _traverse.default) !== null && _a !== void 0 ? _a : _traverse);
3
4
  /**
4
5
  * Finds direct assignment expressions or variable declarations for a given identifier node.
5
6
  *
@@ -1 +1 @@
1
- {"version":3,"file":"findDirectAssignment.js","sourceRoot":"","sources":["../../../../src/analyze/helpers/engineHelpers/findDirectAssignment.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AAGxC,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC;AAEnC;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAgB,EAAE,KAAW;IAC9D,IAAI,cAAc,GAAgB,IAAI,CAAC;IAEvC,QAAQ,CAAC,KAAK,EAAE;QACZ,oBAAoB,CAAC,IAAI;YACrB,uEAAuE;YACvE,IACI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY;gBACpC,UAAU,CAAC,IAAI,KAAK,YAAY;gBAChC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,EACzC,CAAC;gBACC,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC3B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,4BAA4B;YAC7C,CAAC;QACL,CAAC;QACD,kBAAkB,CAAC,IAAI;YACnB,8DAA8D;YAC9D,IACI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,YAAY;gBAClC,UAAU,CAAC,IAAI,KAAK,YAAY;gBAChC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,EACvC,CAAC;gBACC,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC3B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,4BAA4B;YAC7C,CAAC;QACL,CAAC;KACJ,CAAC,CAAC;IAEH,OAAO,cAAc,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"findDirectAssignment.js","sourceRoot":"","sources":["../../../../src/analyze/helpers/engineHelpers/findDirectAssignment.ts"],"names":[],"mappings":";AAAA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AAGxC,MAAM,QAAQ,GAAG,CAAC,MAAA,SAAS,CAAC,OAAO,mCAAI,SAAS,CAA6B,CAAC;AAE9E;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAgB,EAAE,KAAW;IAC9D,IAAI,cAAc,GAAgB,IAAI,CAAC;IAEvC,QAAQ,CAAC,KAAK,EAAE;QACZ,oBAAoB,CAAC,IAAI;YACrB,uEAAuE;YACvE,IACI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY;gBACpC,UAAU,CAAC,IAAI,KAAK,YAAY;gBAChC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,EACzC,CAAC;gBACC,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC3B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,4BAA4B;YAC7C,CAAC;QACL,CAAC;QACD,kBAAkB,CAAC,IAAI;YACnB,8DAA8D;YAC9D,IACI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,YAAY;gBAClC,UAAU,CAAC,IAAI,KAAK,YAAY;gBAChC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,EACvC,CAAC;gBACC,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC3B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,4BAA4B;YAC7C,CAAC;QACL,CAAC;KACJ,CAAC,CAAC;IAEH,OAAO,cAAc,CAAC;AAC1B,CAAC"}
@@ -1,5 +1,6 @@
1
+ var _a;
1
2
  import _traverse from "@babel/traverse";
2
- const traverse = _traverse.default;
3
+ const traverse = ((_a = _traverse.default) !== null && _a !== void 0 ? _a : _traverse);
3
4
  /**
4
5
  * Finds an assignment expression where the left side is a member expression with a property that matches the given name.
5
6
  * Traverses the given node and its children to find a match.
@@ -1 +1 @@
1
- {"version":3,"file":"findMemberExpressionAssignment.js","sourceRoot":"","sources":["../../../../src/analyze/helpers/engineHelpers/findMemberExpressionAssignment.ts"],"names":[],"mappings":"AACA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AACxC,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC;AAEnC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,IAAU,EAAE,OAAe,EAAE,KAAU,EAAoB,EAAE;IACxG,IAAI,SAA2B,CAAC;IAEhC,QAAQ,CACJ,IAAI,EACJ;QACI,oBAAoB,CAAC,IAAI;;YACrB,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC;YAEjC,IACI,CAAA,MAAA,cAAc,CAAC,IAAI,0CAAE,IAAI,MAAK,kBAAkB;gBAChD,CAAA,MAAA,cAAc,CAAC,KAAK,0CAAE,IAAI,MAAK,kBAAkB;gBACjD,CAAA,MAAC,cAAc,CAAC,IAAY,CAAC,QAAQ,0CAAE,IAAI,MAAK,YAAY;gBAC5D,CAAA,MAAC,cAAc,CAAC,IAAY,CAAC,QAAQ,0CAAE,IAAI,MAAK,OAAO,EACzD,CAAC;gBACC,SAAS,GAAG,cAAc,CAAC;gBAC3B,+CAA+C;gBAC/C,IAAI,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC;QACL,CAAC;KACJ,EACD,KAAK,CACR,CAAC;IAEF,OAAO,SAAS,CAAC;AACrB,CAAC,CAAC"}
1
+ {"version":3,"file":"findMemberExpressionAssignment.js","sourceRoot":"","sources":["../../../../src/analyze/helpers/engineHelpers/findMemberExpressionAssignment.ts"],"names":[],"mappings":";AACA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AACxC,MAAM,QAAQ,GAAG,CAAC,MAAA,SAAS,CAAC,OAAO,mCAAI,SAAS,CAA6B,CAAC;AAE9E;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,IAAU,EAAE,OAAe,EAAE,KAAU,EAAoB,EAAE;IACxG,IAAI,SAA2B,CAAC;IAEhC,QAAQ,CACJ,IAAI,EACJ;QACI,oBAAoB,CAAC,IAAI;;YACrB,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC;YAEjC,IACI,CAAA,MAAA,cAAc,CAAC,IAAI,0CAAE,IAAI,MAAK,kBAAkB;gBAChD,CAAA,MAAA,cAAc,CAAC,KAAK,0CAAE,IAAI,MAAK,kBAAkB;gBACjD,CAAA,MAAC,cAAc,CAAC,IAAY,CAAC,QAAQ,0CAAE,IAAI,MAAK,YAAY;gBAC5D,CAAA,MAAC,cAAc,CAAC,IAAY,CAAC,QAAQ,0CAAE,IAAI,MAAK,OAAO,EACzD,CAAC;gBACC,SAAS,GAAG,cAAc,CAAC;gBAC3B,+CAA+C;gBAC/C,IAAI,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC;QACL,CAAC;KACJ,EACD,KAAK,CACR,CAAC;IAEF,OAAO,SAAS,CAAC;AACrB,CAAC,CAAC"}
@@ -1,5 +1,6 @@
1
+ var _a;
1
2
  import _traverse from "@babel/traverse";
2
- const traverse = _traverse.default;
3
+ const traverse = ((_a = _traverse.default) !== null && _a !== void 0 ? _a : _traverse);
3
4
  /**
4
5
  * Resolves a function identifier to its declaration node in the given AST.
5
6
  *
@@ -1 +1 @@
1
- {"version":3,"file":"resolveFunctionIdentifier.js","sourceRoot":"","sources":["../../../../src/analyze/helpers/engineHelpers/resolveFunctionIdentifier.ts"],"names":[],"mappings":"AACA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AACxC,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC;AAEnC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,yBAAyB,CAAC,UAAgB,EAAE,GAAS;IACjE,IAAI,eAAiC,CAAC;IAEtC,IAAI,UAAU,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACnC,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,QAAQ,CAAC,GAAG,EAAE;QACV,mBAAmB,CAAC,IAAI;YACpB,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,EAAE,CAAC;gBACxD,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC;QACL,CAAC;QACD,kBAAkB,CAAC,IAAI;YACnB,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,EAAE,CAAC;gBAC9E,IACI,IAAI,CAAC,IAAI,CAAC,IAAI;oBACd,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,yBAAyB,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,oBAAoB,CAAC,EACrG,CAAC;oBACC,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;oBACjC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAChB,CAAC;YACL,CAAC;QACL,CAAC;KACJ,CAAC,CAAC;IAEH,OAAO,eAAe,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"resolveFunctionIdentifier.js","sourceRoot":"","sources":["../../../../src/analyze/helpers/engineHelpers/resolveFunctionIdentifier.ts"],"names":[],"mappings":";AACA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AACxC,MAAM,QAAQ,GAAG,CAAC,MAAA,SAAS,CAAC,OAAO,mCAAI,SAAS,CAA6B,CAAC;AAE9E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,yBAAyB,CAAC,UAAgB,EAAE,GAAS;IACjE,IAAI,eAAiC,CAAC;IAEtC,IAAI,UAAU,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACnC,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,QAAQ,CAAC,GAAG,EAAE;QACV,mBAAmB,CAAC,IAAI;YACpB,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,EAAE,CAAC;gBACxD,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC;QACL,CAAC;QACD,kBAAkB,CAAC,IAAI;YACnB,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,EAAE,CAAC;gBAC9E,IACI,IAAI,CAAC,IAAI,CAAC,IAAI;oBACd,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,yBAAyB,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,oBAAoB,CAAC,EACrG,CAAC;oBACC,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;oBACjC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAChB,CAAC;YACL,CAAC;QACL,CAAC;KACJ,CAAC,CAAC;IAEH,OAAO,eAAe,CAAC;AAC3B,CAAC"}