@clear-capabilities/agentic-security-scanner 0.74.0

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 (331) hide show
  1. package/CHANGELOG.md +1580 -0
  2. package/bin/.agentic-security/findings.json +1577 -0
  3. package/bin/.agentic-security/last-scan.json +1577 -0
  4. package/bin/.agentic-security/last-scan.json.sig +1 -0
  5. package/bin/.agentic-security/scan-history.json +465 -0
  6. package/bin/.agentic-security/streak.json +25 -0
  7. package/bin/agentic-security-audit.js +198 -0
  8. package/bin/agentic-security-consistency.js +80 -0
  9. package/bin/agentic-security-diff.js +136 -0
  10. package/bin/agentic-security-lsp.js +12 -0
  11. package/bin/agentic-security-mcp.js +40 -0
  12. package/bin/agentic-security-rule.js +153 -0
  13. package/bin/agentic-security.js +1683 -0
  14. package/dist/117.index.js +207 -0
  15. package/dist/178.index.js +250 -0
  16. package/dist/218.index.js +793 -0
  17. package/dist/227.index.js +192 -0
  18. package/dist/301.index.js +167 -0
  19. package/dist/384.index.js +18 -0
  20. package/dist/476.index.js +126 -0
  21. package/dist/513.index.js +373 -0
  22. package/dist/520.index.js +13 -0
  23. package/dist/601.index.js +1038 -0
  24. package/dist/634.index.js +1892 -0
  25. package/dist/637.index.js +216 -0
  26. package/dist/660.index.js +131 -0
  27. package/dist/675.index.js +451 -0
  28. package/dist/826.index.js +188 -0
  29. package/dist/830.index.js +133 -0
  30. package/dist/agentic-security.mjs +272 -0
  31. package/dist/agentic-security.mjs.sha256 +1 -0
  32. package/dist/calibration-seed.json +27 -0
  33. package/package.json +77 -0
  34. package/src/.agentic-security/findings.json +80844 -0
  35. package/src/.agentic-security/last-scan.json +80844 -0
  36. package/src/.agentic-security/last-scan.json.sig +1 -0
  37. package/src/.agentic-security/scan-history.json +8408 -0
  38. package/src/.agentic-security/streak.json +26 -0
  39. package/src/badge.js +188 -0
  40. package/src/compare.js +203 -0
  41. package/src/dataflow/.agentic-security/findings.json +3487 -0
  42. package/src/dataflow/.agentic-security/last-scan.json +3487 -0
  43. package/src/dataflow/.agentic-security/last-scan.json.sig +1 -0
  44. package/src/dataflow/.agentic-security/scan-history.json +735 -0
  45. package/src/dataflow/.agentic-security/streak.json +24 -0
  46. package/src/dataflow/CLAUDE.md +38 -0
  47. package/src/dataflow/access-paths.js +172 -0
  48. package/src/dataflow/async-sequencing.js +177 -0
  49. package/src/dataflow/backward.js +201 -0
  50. package/src/dataflow/catalog-expanded.js +485 -0
  51. package/src/dataflow/catalog.js +659 -0
  52. package/src/dataflow/cross-repo.js +219 -0
  53. package/src/dataflow/engine.js +588 -0
  54. package/src/dataflow/exception-flow.js +116 -0
  55. package/src/dataflow/exploit-prover.js +187 -0
  56. package/src/dataflow/higher-order.js +221 -0
  57. package/src/dataflow/ifds.js +347 -0
  58. package/src/dataflow/implicit-flow.js +129 -0
  59. package/src/dataflow/incremental.js +229 -0
  60. package/src/dataflow/index.js +181 -0
  61. package/src/dataflow/numeric-domain.js +192 -0
  62. package/src/dataflow/path-feasibility.js +114 -0
  63. package/src/dataflow/points-to.js +337 -0
  64. package/src/dataflow/polyglot.js +190 -0
  65. package/src/dataflow/proven-clean.js +159 -0
  66. package/src/dataflow/receiver-context.js +76 -0
  67. package/src/dataflow/sanitizer-proof.js +154 -0
  68. package/src/dataflow/soft-taint.js +140 -0
  69. package/src/dataflow/string-domain.js +234 -0
  70. package/src/dataflow/stub-aware-filter.js +100 -0
  71. package/src/dataflow/summaries.js +132 -0
  72. package/src/dataflow/symbolic-exec.js +238 -0
  73. package/src/dataflow/tabulation.js +135 -0
  74. package/src/engine.js +7763 -0
  75. package/src/history-scan.js +229 -0
  76. package/src/index.js +3 -0
  77. package/src/integrations/.agentic-security/findings.json +1504 -0
  78. package/src/integrations/.agentic-security/last-scan.json +1504 -0
  79. package/src/integrations/.agentic-security/scan-history.json +40 -0
  80. package/src/integrations/.agentic-security/streak.json +21 -0
  81. package/src/integrations/index.js +321 -0
  82. package/src/integrations/tickets.js +200 -0
  83. package/src/ir/.agentic-security/findings.json +3036 -0
  84. package/src/ir/.agentic-security/last-scan.json +3036 -0
  85. package/src/ir/.agentic-security/last-scan.json.sig +1 -0
  86. package/src/ir/.agentic-security/scan-history.json +364 -0
  87. package/src/ir/.agentic-security/streak.json +23 -0
  88. package/src/ir/CLAUDE.md +172 -0
  89. package/src/ir/callgraph.js +73 -0
  90. package/src/ir/class-hierarchy.js +195 -0
  91. package/src/ir/index.js +152 -0
  92. package/src/ir/parser-cs.js +260 -0
  93. package/src/ir/parser-java.js +286 -0
  94. package/src/ir/parser-js.js +413 -0
  95. package/src/ir/parser-kt.js +258 -0
  96. package/src/ir/parser-py-cst.js +136 -0
  97. package/src/ir/parser-py.helper.py +501 -0
  98. package/src/ir/parser-py.js +312 -0
  99. package/src/ir/ssa.js +315 -0
  100. package/src/ir/type-stubs.js +288 -0
  101. package/src/leaderboard.js +152 -0
  102. package/src/llm-validator/.agentic-security/findings.json +1891 -0
  103. package/src/llm-validator/.agentic-security/last-scan.json +1891 -0
  104. package/src/llm-validator/.agentic-security/last-scan.json.sig +1 -0
  105. package/src/llm-validator/.agentic-security/scan-history.json +168 -0
  106. package/src/llm-validator/.agentic-security/streak.json +20 -0
  107. package/src/llm-validator/consistency.js +141 -0
  108. package/src/llm-validator/index.js +437 -0
  109. package/src/lsp/.agentic-security/findings.json +28 -0
  110. package/src/lsp/.agentic-security/last-scan.json +28 -0
  111. package/src/lsp/.agentic-security/scan-history.json +79 -0
  112. package/src/lsp/.agentic-security/streak.json +22 -0
  113. package/src/lsp/server.js +275 -0
  114. package/src/mcp/.agentic-security/findings.json +8358 -0
  115. package/src/mcp/.agentic-security/last-scan.json +8358 -0
  116. package/src/mcp/.agentic-security/last-scan.json.sig +1 -0
  117. package/src/mcp/.agentic-security/scan-history.json +1125 -0
  118. package/src/mcp/.agentic-security/streak.json +22 -0
  119. package/src/mcp/CLAUDE.md +54 -0
  120. package/src/mcp/audit.js +136 -0
  121. package/src/mcp/redact.js +75 -0
  122. package/src/mcp/server.js +158 -0
  123. package/src/mcp/stdio.js +83 -0
  124. package/src/mcp/tools.js +940 -0
  125. package/src/mcp/validate.js +49 -0
  126. package/src/personality.js +164 -0
  127. package/src/poc-video.js +239 -0
  128. package/src/posture/.agentic-security/findings.json +51239 -0
  129. package/src/posture/.agentic-security/last-scan.json +51239 -0
  130. package/src/posture/.agentic-security/last-scan.json.sig +1 -0
  131. package/src/posture/.agentic-security/scan-history.json +5557 -0
  132. package/src/posture/.agentic-security/streak.json +24 -0
  133. package/src/posture/CLAUDE.md +42 -0
  134. package/src/posture/adversarial-self-test.js +114 -0
  135. package/src/posture/adversary-agent.js +204 -0
  136. package/src/posture/agents-memory.js +135 -0
  137. package/src/posture/ai-code-fingerprint.js +171 -0
  138. package/src/posture/aibom.js +284 -0
  139. package/src/posture/api-inventory.js +96 -0
  140. package/src/posture/attack-playbooks.js +305 -0
  141. package/src/posture/auditor-agent.js +115 -0
  142. package/src/posture/auth-posture-import.js +135 -0
  143. package/src/posture/baseline-compare.js +114 -0
  144. package/src/posture/blast-radius.js +836 -0
  145. package/src/posture/bounty-prediction.js +141 -0
  146. package/src/posture/business-logic.js +239 -0
  147. package/src/posture/calibration-drift.js +93 -0
  148. package/src/posture/calibration-seed.json +27 -0
  149. package/src/posture/calibration.js +204 -0
  150. package/src/posture/clustering.js +75 -0
  151. package/src/posture/concurrency-checker.js +265 -0
  152. package/src/posture/confidence.js +65 -0
  153. package/src/posture/container-runtime.js +149 -0
  154. package/src/posture/counterfactual.js +109 -0
  155. package/src/posture/cross-lang-graphql.js +165 -0
  156. package/src/posture/cross-lang-grpc.js +166 -0
  157. package/src/posture/cross-lang-meta.js +101 -0
  158. package/src/posture/cross-lang-openapi.js +187 -0
  159. package/src/posture/cross-lang-orm.js +153 -0
  160. package/src/posture/cross-lang-queues.js +210 -0
  161. package/src/posture/crown-jewels.js +110 -0
  162. package/src/posture/custom-rules.js +361 -0
  163. package/src/posture/cve-alert-daemon.js +433 -0
  164. package/src/posture/cve-lookup.js +129 -0
  165. package/src/posture/dead-code.js +430 -0
  166. package/src/posture/defender-agent.js +158 -0
  167. package/src/posture/deploy-platform.js +204 -0
  168. package/src/posture/detector-fuzz.js +61 -0
  169. package/src/posture/deterministic.js +99 -0
  170. package/src/posture/drift.js +165 -0
  171. package/src/posture/epss.js +156 -0
  172. package/src/posture/exploitability-probability.js +212 -0
  173. package/src/posture/exploitability.js +121 -0
  174. package/src/posture/feature-flags.js +110 -0
  175. package/src/posture/finding-defaults.js +132 -0
  176. package/src/posture/fix-history.js +411 -0
  177. package/src/posture/fix-plan.js +121 -0
  178. package/src/posture/fix-verify-loop.js +157 -0
  179. package/src/posture/fix-verify.js +130 -0
  180. package/src/posture/flow-narration.js +105 -0
  181. package/src/posture/grader-calibration.js +156 -0
  182. package/src/posture/harness-discovery.js +113 -0
  183. package/src/posture/holdout-eval.js +144 -0
  184. package/src/posture/iac-reachability.js +163 -0
  185. package/src/posture/iam-policy.js +128 -0
  186. package/src/posture/integrity.js +97 -0
  187. package/src/posture/learning.js +166 -0
  188. package/src/posture/license-policy.js +109 -0
  189. package/src/posture/llm-redteam-prompts.js +418 -0
  190. package/src/posture/llm-redteam.js +303 -0
  191. package/src/posture/material-change.js +163 -0
  192. package/src/posture/mitigation-composite.js +55 -0
  193. package/src/posture/mttr.js +91 -0
  194. package/src/posture/network-policy-import.js +126 -0
  195. package/src/posture/path-predicates.js +99 -0
  196. package/src/posture/persona-prioritization.js +153 -0
  197. package/src/posture/poc-cwe-map.js +51 -0
  198. package/src/posture/poc-generator.js +500 -0
  199. package/src/posture/policy-gate.js +174 -0
  200. package/src/posture/pre-incident-archaeology.js +110 -0
  201. package/src/posture/profile.js +93 -0
  202. package/src/posture/reachability-filter.js +42 -0
  203. package/src/posture/regression-test-gen.js +200 -0
  204. package/src/posture/reverse-blast-radius.js +110 -0
  205. package/src/posture/router.js +109 -0
  206. package/src/posture/rule-overrides.js +198 -0
  207. package/src/posture/rule-pack-signing.js +209 -0
  208. package/src/posture/rule-packs.js +143 -0
  209. package/src/posture/rule-synthesis.js +108 -0
  210. package/src/posture/ruleset-version.js +71 -0
  211. package/src/posture/sbom.js +129 -0
  212. package/src/posture/schema-aware-bridge.js +207 -0
  213. package/src/posture/security-trend.js +87 -0
  214. package/src/posture/semantic-clone.js +114 -0
  215. package/src/posture/specification-mining.js +170 -0
  216. package/src/posture/stable-id.js +75 -0
  217. package/src/posture/stack-playbook.js +229 -0
  218. package/src/posture/streak.js +249 -0
  219. package/src/posture/suppressions.js +135 -0
  220. package/src/posture/telemetry-ingest.js +112 -0
  221. package/src/posture/threat-model.js +145 -0
  222. package/src/posture/three-agent-pipeline.js +74 -0
  223. package/src/posture/triage.js +146 -0
  224. package/src/posture/trust-boundary-diagram.js +115 -0
  225. package/src/posture/type-narrowing.js +129 -0
  226. package/src/posture/validator-metrics.js +179 -0
  227. package/src/posture/verifier-ephemeral.js +118 -0
  228. package/src/posture/verifier-target.js +147 -0
  229. package/src/posture/verifier.js +257 -0
  230. package/src/posture/version.js +75 -0
  231. package/src/posture/waf-ingest.js +200 -0
  232. package/src/posture/why-fired.js +141 -0
  233. package/src/pr-comment.js +172 -0
  234. package/src/pr-delta.js +198 -0
  235. package/src/report/.agentic-security/findings.json +79 -0
  236. package/src/report/.agentic-security/last-scan.json +79 -0
  237. package/src/report/.agentic-security/last-scan.json.sig +1 -0
  238. package/src/report/.agentic-security/scan-history.json +332 -0
  239. package/src/report/.agentic-security/streak.json +23 -0
  240. package/src/report/index.js +1136 -0
  241. package/src/report/mascot.js +42 -0
  242. package/src/runScan.js +141 -0
  243. package/src/sast/.agentic-security/findings.json +5051 -0
  244. package/src/sast/.agentic-security/last-scan.json +5051 -0
  245. package/src/sast/.agentic-security/last-scan.json.sig +1 -0
  246. package/src/sast/.agentic-security/scan-history.json +788 -0
  247. package/src/sast/.agentic-security/streak.json +23 -0
  248. package/src/sast/CLAUDE.md +39 -0
  249. package/src/sast/_comment-strip.js +46 -0
  250. package/src/sast/agent-tool-escalation.js +131 -0
  251. package/src/sast/auth-provider.js +171 -0
  252. package/src/sast/authz.js +236 -0
  253. package/src/sast/bench-shape/.agentic-security/findings.json +28 -0
  254. package/src/sast/bench-shape/.agentic-security/last-scan.json +28 -0
  255. package/src/sast/bench-shape/.agentic-security/scan-history.json +24 -0
  256. package/src/sast/bench-shape/.agentic-security/streak.json +22 -0
  257. package/src/sast/bench-shape/index.js +62 -0
  258. package/src/sast/claude-hook-injection.js +199 -0
  259. package/src/sast/claude-md-prompt-injection.js +170 -0
  260. package/src/sast/claude-settings.js +165 -0
  261. package/src/sast/client-side.js +149 -0
  262. package/src/sast/cpp-bench-extras.js +122 -0
  263. package/src/sast/cpp-dataflow.js +430 -0
  264. package/src/sast/cpp.js +248 -0
  265. package/src/sast/csharp.js +152 -0
  266. package/src/sast/csrf.js +82 -0
  267. package/src/sast/dart-flutter.js +173 -0
  268. package/src/sast/db-rls.js +147 -0
  269. package/src/sast/db-taint.js +215 -0
  270. package/src/sast/defi-deep.js +242 -0
  271. package/src/sast/deserialization-gadgets.js +113 -0
  272. package/src/sast/django-hardening.js +230 -0
  273. package/src/sast/env-hygiene.js +125 -0
  274. package/src/sast/fastapi-hardening.js +145 -0
  275. package/src/sast/go-extended.js +84 -0
  276. package/src/sast/host-header.js +106 -0
  277. package/src/sast/index.js +17 -0
  278. package/src/sast/java-ast-folding.js +561 -0
  279. package/src/sast/java-bench-extras.js +708 -0
  280. package/src/sast/java-collection-passthrough.js +178 -0
  281. package/src/sast/java-constant-fold.js +244 -0
  282. package/src/sast/java-deserialization.js +125 -0
  283. package/src/sast/jndi.js +104 -0
  284. package/src/sast/juliet-shape.js +324 -0
  285. package/src/sast/jwt-exp.js +104 -0
  286. package/src/sast/kotlin.js +82 -0
  287. package/src/sast/laravel-hardening.js +198 -0
  288. package/src/sast/ldap-injection.js +100 -0
  289. package/src/sast/llm-owasp.js +465 -0
  290. package/src/sast/llm-stored-prompt.js +103 -0
  291. package/src/sast/llm-trading-agent.js +161 -0
  292. package/src/sast/llm.js +308 -0
  293. package/src/sast/logic.js +140 -0
  294. package/src/sast/mass-assignment.js +101 -0
  295. package/src/sast/mcp-audit.js +242 -0
  296. package/src/sast/mobile-manifest.js +195 -0
  297. package/src/sast/model-load.js +164 -0
  298. package/src/sast/mutation-xss.js +87 -0
  299. package/src/sast/nosql-injection.js +82 -0
  300. package/src/sast/open-redirect.js +119 -0
  301. package/src/sast/php.js +91 -0
  302. package/src/sast/pipeline.js +122 -0
  303. package/src/sast/primary-cwe-java.js +155 -0
  304. package/src/sast/prompt-firewall.js +151 -0
  305. package/src/sast/prompt-template.js +157 -0
  306. package/src/sast/prototype-pollution.js +112 -0
  307. package/src/sast/python-sinks.js +195 -0
  308. package/src/sast/quarkus-hardening.js +102 -0
  309. package/src/sast/rag-poisoning.js +118 -0
  310. package/src/sast/rate-limit.js +128 -0
  311. package/src/sast/response-splitting.js +138 -0
  312. package/src/sast/ruby.js +108 -0
  313. package/src/sast/rust.js +105 -0
  314. package/src/sast/solidity.js +167 -0
  315. package/src/sast/springboot-hardening.js +186 -0
  316. package/src/sast/ssrf-cloud-metadata.js +80 -0
  317. package/src/sast/ssti.js +116 -0
  318. package/src/sast/swift.js +162 -0
  319. package/src/sast/toctou.js +95 -0
  320. package/src/sast/webhook.js +101 -0
  321. package/src/sast/xpath-injection.js +51 -0
  322. package/src/sast/xxe.js +140 -0
  323. package/src/sast/zip-slip.js +200 -0
  324. package/src/sca/base-images.json +45 -0
  325. package/src/sca/container.js +107 -0
  326. package/src/sca/dep-confusion.js +134 -0
  327. package/src/sca/index.js +6 -0
  328. package/src/sca/popular-packages.json +41 -0
  329. package/src/sca/sarif-ingest.js +187 -0
  330. package/src/sca/vuln-function-hints.json +89 -0
  331. package/src/secrets/index.js +4 -0
@@ -0,0 +1,286 @@
1
+ // Java IR frontend (P2.3).
2
+ //
3
+ // Converts the java-parser AST into our unified IR shape. The dataflow
4
+ // engine consumes the same node kinds as the JS frontend (assign / call /
5
+ // return / if / loop-header / throw / entry / exit / noop).
6
+ //
7
+ // v1 scope:
8
+ // - Method declarations → IR functions with CFG
9
+ // - Field declarations → top-level assigns
10
+ // - Local variable declarations + assignments → assign nodes
11
+ // - Method invocations → call nodes
12
+ // - Return / throw / if-else / while / for → corresponding IR nodes
13
+ // - Try / catch → exception-flow scaffolding (P3.4 will model)
14
+ // - Lambdas → captured as function-value (P1.3 helpers consume)
15
+ //
16
+ // Out of scope for v1: generics resolution, annotation introspection beyond
17
+ // shallow name capture, varargs unpacking, switch expressions.
18
+ //
19
+ // The implementation is line-aware: java-parser produces an exhaustive CST,
20
+ // which we walk to extract just the dataflow-relevant nodes. v1 is
21
+ // conservative — we recover what we can, and fall back to a single noop
22
+ // when the shape is unfamiliar.
23
+
24
+ import { blankComments } from '../sast/_comment-strip.js';
25
+
26
+ let _nodeIdSeq = 0;
27
+ function nextNodeId() { return 'jn' + (++_nodeIdSeq); }
28
+
29
+ let _javaParser = null;
30
+ async function _loadJavaParser() {
31
+ if (_javaParser) return _javaParser;
32
+ try {
33
+ const mod = await import('java-parser');
34
+ _javaParser = mod.parse || mod.default;
35
+ return _javaParser;
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Walk a java-parser CST node and emit our exprDesc shape.
43
+ */
44
+ function exprFromCst(node) {
45
+ if (!node) return { kind: 'unknown' };
46
+ if (Array.isArray(node)) {
47
+ return node.length === 1 ? exprFromCst(node[0]) : { kind: 'unknown' };
48
+ }
49
+ if (node.image) {
50
+ // Token leaf — number, string, ident.
51
+ const img = node.image;
52
+ if (/^['"]/.test(img)) return { kind: 'literal', value: img };
53
+ if (/^-?\d/.test(img)) return { kind: 'literal', value: Number(img) || img };
54
+ if (/^(?:true|false|null)$/.test(img)) return { kind: 'literal', value: img };
55
+ return { kind: 'ident', name: img };
56
+ }
57
+ if (node.children) {
58
+ // CST node with named children — recurse into the most informative one.
59
+ // Method invocation
60
+ if (node.children.methodInvocation) return _methodInvocation(node.children.methodInvocation[0]);
61
+ // FQN ref
62
+ if (node.children.fqnOrRefType) return _fqnExpr(node.children.fqnOrRefType[0]);
63
+ if (node.children.unqualifiedClassInstanceCreationExpression) {
64
+ const ci = node.children.unqualifiedClassInstanceCreationExpression[0];
65
+ const callee = (ci.children?.classOrInterfaceTypeToInstantiate?.[0]?.children?.Identifier?.[0]?.image) || 'new';
66
+ return { kind: 'call', callee, isNew: true, args: [] };
67
+ }
68
+ if (node.children.literal) return exprFromCst(node.children.literal[0]);
69
+ if (node.children.Identifier) return { kind: 'ident', name: node.children.Identifier[0].image };
70
+ // Binary expression
71
+ if (node.children.BinaryOperator || node.children.binaryExpression) {
72
+ // Best-effort: take the two operands.
73
+ const kids = node.children.unaryExpression || node.children.expression || [];
74
+ if (kids.length >= 2) {
75
+ return {
76
+ kind: 'binary',
77
+ op: '?',
78
+ left: exprFromCst(kids[0]),
79
+ right: exprFromCst(kids[1]),
80
+ };
81
+ }
82
+ }
83
+ // Fall through: recurse the first child
84
+ for (const k of Object.keys(node.children)) {
85
+ const arr = node.children[k];
86
+ if (Array.isArray(arr) && arr.length) return exprFromCst(arr[0]);
87
+ }
88
+ }
89
+ return { kind: 'unknown' };
90
+ }
91
+
92
+ function _fqnExpr(node) {
93
+ // java-parser fqnOrRefType has children { Identifier: [...] } sometimes
94
+ // and Dot tokens between them.
95
+ if (!node || !node.children) return { kind: 'unknown' };
96
+ const ids = node.children.Identifier;
97
+ if (!ids || !ids.length) return { kind: 'unknown' };
98
+ let cur = { kind: 'ident', name: ids[0].image };
99
+ for (let i = 1; i < ids.length; i++) {
100
+ cur = { kind: 'member', object: cur, prop: ids[i].image };
101
+ }
102
+ return cur;
103
+ }
104
+
105
+ function _methodInvocation(node) {
106
+ // node.children typically: fqnOrRefType (callee) + argumentList (args).
107
+ const callee = node.children?.fqnOrRefType
108
+ ? _flattenFqnToString(node.children.fqnOrRefType[0])
109
+ : (node.children?.Identifier?.[0]?.image || 'unknown');
110
+ const args = [];
111
+ if (node.children?.argumentList) {
112
+ const al = node.children.argumentList[0];
113
+ if (al && al.children?.expression) {
114
+ for (const e of al.children.expression) args.push(exprFromCst(e));
115
+ }
116
+ }
117
+ return { kind: 'call', callee, args };
118
+ }
119
+
120
+ function _flattenFqnToString(node) {
121
+ if (!node || !node.children) return 'unknown';
122
+ const ids = node.children.Identifier;
123
+ if (!ids) return 'unknown';
124
+ return ids.map(t => t.image).join('.');
125
+ }
126
+
127
+ /**
128
+ * Build a function's CFG from its method-body CST.
129
+ *
130
+ * v1: a simple sequential walk — every statement becomes one IR node,
131
+ * connected linearly. Branches (`if/else`, `while`, `for`) emit an
132
+ * `if` / `loop-header` node and the body falls through linearly. This is
133
+ * coarser than the JS frontend; v2 will branch the succ array.
134
+ */
135
+ function buildCfgFromBody(bodyNode, line) {
136
+ const nodes = {};
137
+ const entry = nextNodeId();
138
+ const exit = nextNodeId();
139
+ nodes[entry] = { id: entry, kind: 'entry', succ: [] };
140
+ nodes[exit] = { id: exit, kind: 'exit', succ: [] };
141
+ let prev = entry;
142
+
143
+ function emit(node) {
144
+ const id = nextNodeId();
145
+ node.id = id;
146
+ nodes[id] = node;
147
+ if (nodes[prev]) {
148
+ nodes[prev].succ = nodes[prev].succ || [];
149
+ nodes[prev].succ.push(id);
150
+ }
151
+ prev = id;
152
+ return id;
153
+ }
154
+
155
+ walkStmts(bodyNode);
156
+
157
+ function walkStmts(stmtNode) {
158
+ if (!stmtNode || !stmtNode.children) return;
159
+ const kids = stmtNode.children;
160
+ // Block statement children
161
+ if (kids.blockStatement) {
162
+ for (const bs of kids.blockStatement) walkStmts(bs);
163
+ }
164
+ if (kids.localVariableDeclarationStatement) {
165
+ for (const lv of kids.localVariableDeclarationStatement) {
166
+ const vdecl = lv.children?.localVariableDeclaration?.[0];
167
+ const declarators = vdecl?.children?.variableDeclaratorList?.[0]?.children?.variableDeclarator;
168
+ if (declarators) {
169
+ for (const d of declarators) {
170
+ const target = d.children?.variableDeclaratorId?.[0]?.children?.Identifier?.[0]?.image;
171
+ const initExpr = d.children?.variableInitializer?.[0]?.children?.expression?.[0];
172
+ if (target) {
173
+ emit({ kind: 'assign', target, source: initExpr ? exprFromCst(initExpr) : { kind: 'unknown' }, line: line || 0, succ: [] });
174
+ }
175
+ }
176
+ }
177
+ }
178
+ }
179
+ if (kids.statement) {
180
+ for (const s of kids.statement) walkStmts(s);
181
+ }
182
+ if (kids.statementWithoutTrailingSubstatement) {
183
+ for (const s of kids.statementWithoutTrailingSubstatement) walkStmts(s);
184
+ }
185
+ if (kids.expressionStatement) {
186
+ const e = kids.expressionStatement[0]?.children?.statementExpression?.[0]?.children?.expression?.[0];
187
+ if (e) {
188
+ const expr = exprFromCst(e);
189
+ if (expr.kind === 'call') emit({ ...expr, line: line || 0, succ: [] });
190
+ else if (expr.kind === 'binary' && expr.op === '=') {
191
+ // assignment expr `x = y;`
192
+ emit({ kind: 'assign', target: expr.left?.name || null, source: expr.right, line: line || 0, succ: [] });
193
+ }
194
+ }
195
+ }
196
+ if (kids.returnStatement) {
197
+ const r = kids.returnStatement[0];
198
+ const expr = r.children?.expression?.[0];
199
+ emit({ kind: 'return', value: expr ? exprFromCst(expr) : null, line: line || 0, succ: [] });
200
+ }
201
+ if (kids.throwStatement) {
202
+ const t = kids.throwStatement[0];
203
+ const expr = t.children?.expression?.[0];
204
+ emit({ kind: 'throw', value: expr ? exprFromCst(expr) : null, line: line || 0, succ: [] });
205
+ }
206
+ if (kids.ifStatement) {
207
+ const i = kids.ifStatement[0];
208
+ const cond = i.children?.expression?.[0];
209
+ emit({ kind: 'if', cond: cond ? exprFromCst(cond) : null, line: line || 0, succ: [] });
210
+ // Then branch body falls through linearly; v1 simplification.
211
+ for (const sub of (i.children?.statement || [])) walkStmts(sub);
212
+ }
213
+ if (kids.whileStatement) {
214
+ const w = kids.whileStatement[0];
215
+ const cond = w.children?.expression?.[0];
216
+ emit({ kind: 'loop-header', cond: cond ? exprFromCst(cond) : null, line: line || 0, succ: [] });
217
+ for (const sub of (w.children?.statement || [])) walkStmts(sub);
218
+ }
219
+ }
220
+
221
+ if (nodes[prev]) {
222
+ nodes[prev].succ = nodes[prev].succ || [];
223
+ nodes[prev].succ.push(exit);
224
+ }
225
+ return { entry, exit, nodes };
226
+ }
227
+
228
+ /**
229
+ * Top-level: parse one .java file. Returns the perFileIR shape (same as
230
+ * parser-js.js). Returns null when java-parser is unavailable OR the
231
+ * file fails to parse.
232
+ *
233
+ * Async because we lazy-import java-parser.
234
+ */
235
+ export async function parseJavaFile(file, raw) {
236
+ if (!file || !raw || typeof raw !== 'string') return null;
237
+ if (!/\.java$/i.test(file)) return null;
238
+ if (raw.length > 1_000_000) return null;
239
+ const parser = await _loadJavaParser();
240
+ if (!parser) return null;
241
+
242
+ let cst;
243
+ try { cst = parser(raw); } catch { return null; }
244
+ if (!cst) return null;
245
+
246
+ const functions = [];
247
+ // Walk the CST for methodDeclaration nodes.
248
+ function walkForMethods(node, className) {
249
+ if (!node || !node.children) return;
250
+ for (const k of Object.keys(node.children)) {
251
+ const arr = node.children[k];
252
+ if (!Array.isArray(arr)) continue;
253
+ for (const child of arr) {
254
+ if (k === 'classDeclaration' || k === 'normalClassDeclaration') {
255
+ const newClassName = child.children?.typeIdentifier?.[0]?.children?.Identifier?.[0]?.image
256
+ || child.children?.Identifier?.[0]?.image
257
+ || className;
258
+ walkForMethods(child, newClassName);
259
+ continue;
260
+ }
261
+ if (k === 'methodDeclaration' || k === 'methodHeader') {
262
+ const md = child;
263
+ const name = md.children?.methodHeader?.[0]?.children?.methodDeclarator?.[0]?.children?.Identifier?.[0]?.image
264
+ || md.children?.methodDeclarator?.[0]?.children?.Identifier?.[0]?.image
265
+ || 'anonymous';
266
+ const params = []; // params extraction deferred
267
+ const body = md.children?.methodBody?.[0]?.children?.block?.[0];
268
+ if (body) {
269
+ functions.push({
270
+ qid: `${file}::${className || 'class'}::${name}`,
271
+ name: className ? `${className}.${name}` : name,
272
+ line: 0,
273
+ params,
274
+ cfg: buildCfgFromBody(body, 0),
275
+ file,
276
+ });
277
+ }
278
+ }
279
+ walkForMethods(child, className);
280
+ }
281
+ }
282
+ }
283
+ walkForMethods(cst, null);
284
+
285
+ return { file, functions, topLevel: null };
286
+ }