0sec-cli 0.15.0 → 0.17.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 (209) hide show
  1. package/0sec.js +322 -0
  2. package/README.md +63 -52
  3. package/attacks/data-exfiltration/pii-leakage.yaml +27 -0
  4. package/attacks/encoding-bypass/base64-encoding.yaml +24 -0
  5. package/attacks/jailbreak/dan-roleplay.yaml +27 -0
  6. package/attacks/jailbreak/hypothetical-scenario.yaml +25 -0
  7. package/attacks/jailbreak/multilingual-bypass.yaml +22 -0
  8. package/attacks/output-manipulation/harmful-content.yaml +25 -0
  9. package/attacks/prompt-injection/context-manipulation.yaml +32 -0
  10. package/attacks/prompt-injection/direct-injection.yaml +28 -0
  11. package/attacks/prompt-injection/indirect-injection.yaml +33 -0
  12. package/attacks/system-prompt-extraction/direct-ask.yaml +30 -0
  13. package/attacks/system-prompt-extraction/markdown-exfil.yaml +26 -0
  14. package/attacks/tool-misuse/ssrf-via-tools.yaml +27 -0
  15. package/chunks/adapt-loop-ECQG7454.js +18 -0
  16. package/chunks/adgraph-JLGA6RYI.js +54 -0
  17. package/chunks/agent/skills/frameworks/entra-id.yaml +63 -0
  18. package/chunks/agent/skills/frameworks/graphql-introspection.yaml +116 -0
  19. package/chunks/agent/skills/frameworks/nextjs.yaml +82 -0
  20. package/chunks/agent/skills/frameworks/python-web.yaml +85 -0
  21. package/chunks/agent/skills/frameworks/supabase.yaml +83 -0
  22. package/chunks/agent/skills/frameworks/wordpress-deep.yaml +122 -0
  23. package/chunks/agent/skills/techniques/ad-attack-paths.yaml +57 -0
  24. package/chunks/agent/skills/techniques/advisory-disclosure.yaml +59 -0
  25. package/chunks/agent/skills/techniques/assumption-mining.yaml +53 -0
  26. package/chunks/agent/skills/techniques/blind-exploitation.yaml +143 -0
  27. package/chunks/agent/skills/techniques/crypto-misuse.yaml +88 -0
  28. package/chunks/agent/skills/techniques/cve-poc-adaptation.yaml +82 -0
  29. package/chunks/agent/skills/techniques/entra-attack-paths.yaml +55 -0
  30. package/chunks/agent/skills/techniques/http-conformance-diff.yaml +48 -0
  31. package/chunks/agent/skills/techniques/jwt-attacks.yaml +137 -0
  32. package/chunks/agent/skills/techniques/kernel-weaponization.yaml +53 -0
  33. package/chunks/agent/skills/techniques/llm-excessive-agency.yaml +55 -0
  34. package/chunks/agent/skills/techniques/llm-insecure-output-handling.yaml +56 -0
  35. package/chunks/agent/skills/techniques/llm-prompt-injection.yaml +54 -0
  36. package/chunks/agent/skills/techniques/llm-prompt-layer-write.yaml +68 -0
  37. package/chunks/agent/skills/techniques/llm-rag-poisoning.yaml +57 -0
  38. package/chunks/agent/skills/techniques/llm-safety-eval.yaml +51 -0
  39. package/chunks/agent/skills/techniques/npm-ecosystem.yaml +51 -0
  40. package/chunks/agent/skills/techniques/poc-verification.yaml +55 -0
  41. package/chunks/agent/skills/techniques/race-condition.yaml +122 -0
  42. package/chunks/agent/skills/techniques/scoped-fix.yaml +49 -0
  43. package/chunks/agent/skills/techniques/seedless-depth-review.yaml +59 -0
  44. package/chunks/agent/skills/techniques/spec-differential.yaml +48 -0
  45. package/chunks/agent/skills/techniques/variant-hunting.yaml +55 -0
  46. package/chunks/agent/skills/vulnerabilities/cardano-eutxo-validators.yaml +72 -0
  47. package/chunks/agent/skills/vulnerabilities/command-injection.yaml +99 -0
  48. package/chunks/agent/skills/vulnerabilities/deserialization-chains.yaml +106 -0
  49. package/chunks/agent/skills/vulnerabilities/native-memory-safety.yaml +93 -0
  50. package/chunks/agent/skills/vulnerabilities/path-traversal.yaml +78 -0
  51. package/chunks/agent/skills/vulnerabilities/prototype-pollution.yaml +132 -0
  52. package/chunks/agent/skills/vulnerabilities/request-smuggling.yaml +129 -0
  53. package/chunks/agent/skills/vulnerabilities/sqli-advanced.yaml +102 -0
  54. package/chunks/agent/skills/vulnerabilities/ssrf-bypass.yaml +84 -0
  55. package/chunks/agent/skills/vulnerabilities/ssti-exploitation.yaml +112 -0
  56. package/chunks/agent/skills/vulnerabilities/structural-sqli.yaml +91 -0
  57. package/chunks/appsec-catalog-CBWHGTEL.js +24 -0
  58. package/chunks/artifact-scraper-GJEZMOHF.js +34 -0
  59. package/chunks/assumption-mining-BVMMUZHB.js +79 -0
  60. package/chunks/chunk-2CJ776PV.js +2430 -0
  61. package/chunks/chunk-2RMLOJVB.js +47 -0
  62. package/chunks/chunk-2SANI5RH.js +4728 -0
  63. package/chunks/chunk-3MOLBTLS.js +953 -0
  64. package/chunks/chunk-3QFDYBZQ.js +5108 -0
  65. package/chunks/chunk-47TQJWDH.js +3729 -0
  66. package/chunks/chunk-4Y4KQJXE.js +600 -0
  67. package/chunks/chunk-53G27VPS.js +136 -0
  68. package/chunks/chunk-57ZENEX2.js +169 -0
  69. package/chunks/chunk-5G3ZXFBW.js +182 -0
  70. package/chunks/chunk-6LKRLK2R.js +542 -0
  71. package/chunks/chunk-7DQEV5QI.js +287 -0
  72. package/chunks/chunk-A6CLR72I.js +235 -0
  73. package/chunks/chunk-BKZFDZ23.js +361 -0
  74. package/chunks/chunk-CLHCDHP4.js +471 -0
  75. package/chunks/chunk-D6S3IIPG.js +518 -0
  76. package/chunks/chunk-DN25OQQA.js +1070 -0
  77. package/chunks/chunk-DW5UWPFY.js +275 -0
  78. package/chunks/chunk-F3WBKITT.js +687 -0
  79. package/chunks/chunk-H2FFLZNK.js +3 -0
  80. package/chunks/chunk-H44E2CRN.js +193 -0
  81. package/chunks/chunk-HDWV7PGI.js +596 -0
  82. package/chunks/chunk-HE7LCA7G.js +381 -0
  83. package/chunks/chunk-HT6P7RY3.js +2597 -0
  84. package/chunks/chunk-IOL7D5YV.js +515 -0
  85. package/chunks/chunk-IORC6MQX.js +72828 -0
  86. package/chunks/chunk-IR537GON.js +49 -0
  87. package/chunks/chunk-K26SZ37E.js +5735 -0
  88. package/chunks/chunk-KKGE5RQE.js +1094 -0
  89. package/chunks/chunk-KLTNTE2Z.js +121 -0
  90. package/chunks/chunk-KTQDLNSR.js +1732 -0
  91. package/chunks/chunk-LOHTE223.js +2572 -0
  92. package/chunks/chunk-LP3HHYQU.js +245 -0
  93. package/chunks/chunk-MMLDQR4H.js +852 -0
  94. package/chunks/chunk-MYVT64FN.js +16 -0
  95. package/chunks/chunk-O462Y7P2.js +33019 -0
  96. package/chunks/chunk-OEFNRYI2.js +150 -0
  97. package/chunks/chunk-P6WKNFWX.js +1968 -0
  98. package/chunks/chunk-QI233I24.js +333 -0
  99. package/chunks/chunk-QJQKHO7G.js +917 -0
  100. package/chunks/chunk-QKICO43A.js +808 -0
  101. package/chunks/chunk-QOKTUOU2.js +102 -0
  102. package/chunks/chunk-RDZYQQLW.js +596 -0
  103. package/chunks/chunk-RJWOYEOG.js +271 -0
  104. package/chunks/chunk-RRMJC3ZE.js +105 -0
  105. package/chunks/chunk-RWONANDA.js +973 -0
  106. package/chunks/chunk-SAFFWQW4.js +5921 -0
  107. package/chunks/chunk-SF4KZ4O3.js +502 -0
  108. package/chunks/chunk-SNKTC4BP.js +1422 -0
  109. package/chunks/chunk-SOG2U7B3.js +662 -0
  110. package/chunks/chunk-SZJCPG2I.js +110 -0
  111. package/chunks/chunk-UJ4IK5PO.js +2010 -0
  112. package/chunks/chunk-UM3ZNQIM.js +9329 -0
  113. package/chunks/chunk-VGRDNSHA.js +3249 -0
  114. package/chunks/chunk-VQG4FT5D.js +685 -0
  115. package/chunks/chunk-WKNNZVJS.js +2798 -0
  116. package/chunks/chunk-WU6AFRAZ.js +1167 -0
  117. package/chunks/chunk-WVTBZEQO.js +1531 -0
  118. package/chunks/chunk-YLMN3N25.js +4054 -0
  119. package/chunks/commands-U3AMV5ZU.js +16795 -0
  120. package/chunks/corpus-v1.json +403 -0
  121. package/chunks/cost-ledger-ZCKMBJEN.js +13 -0
  122. package/chunks/data/appsec-archetypes.json +102 -0
  123. package/chunks/data/chromium-archetypes.json +204 -0
  124. package/chunks/data/freebsd-archetypes.json +171 -0
  125. package/chunks/data/kernel-archetypes.json +611 -0
  126. package/chunks/db-26NGQFKO.js +16 -0
  127. package/chunks/disclose-A6AEIEDA.js +132 -0
  128. package/chunks/dist-FDKALV4R.js +2772 -0
  129. package/chunks/dist-GL66KMUX.js +74 -0
  130. package/chunks/dist-JR67XKYO.js +159 -0
  131. package/chunks/eval-runner-DDLE5RQ3.js +27 -0
  132. package/chunks/example-manifest.json +95 -0
  133. package/chunks/exploit-agent-XP23ISN7.js +98 -0
  134. package/chunks/exploit-autoclimb-E6T7RRSC.js +81 -0
  135. package/chunks/exploit-climb-2FAUP6XU.js +358 -0
  136. package/chunks/fix-IG7LYXH3.js +12 -0
  137. package/chunks/github-issues-MJ6OYOOU.js +157 -0
  138. package/chunks/harness-HWOYFKFY.js +22 -0
  139. package/chunks/http-conformance-DU66MZIU.js +11 -0
  140. package/chunks/http-sender-GWH2IYEA.js +10 -0
  141. package/chunks/hunt-scan-XPELSPQQ.js +38 -0
  142. package/chunks/identity-6ZAIIWOR.js +191 -0
  143. package/chunks/kernel-primitive-TENE3R7T.js +44 -0
  144. package/chunks/kernel-vm-runner-4F6QSNFY.js +62 -0
  145. package/chunks/memsafety-scan-J7SECV5W.js +16 -0
  146. package/chunks/native-loop-NTONUDP7.js +54 -0
  147. package/chunks/npm-detectors-KB5Y5ZFX.js +69 -0
  148. package/chunks/npm-dynamic-discovery-AHROOZDB.js +13 -0
  149. package/chunks/orchestrate-ZUWAUWBC.js +62 -0
  150. package/chunks/pipeline-FCARFZU3.js +14 -0
  151. package/chunks/pre-recon-cve-66EB6G4M.js +351 -0
  152. package/chunks/prepare-MYY743TK.js +13 -0
  153. package/chunks/process-3Q7QJIOZ.js +13 -0
  154. package/chunks/replay-runner-RRR4E2A7.js +39 -0
  155. package/chunks/run-ESNN4V5W.js +32632 -0
  156. package/chunks/runtime-62ZQAH7H.js +43 -0
  157. package/chunks/runtime-J7PLXZNM.js +12 -0
  158. package/chunks/scan-stream-FHI2FYZE.js +96 -0
  159. package/chunks/scope-BI7BF4ZY.js +18 -0
  160. package/chunks/session-store-BCFQYDCE.js +28 -0
  161. package/chunks/source-files-PWRQR6LY.js +12 -0
  162. package/chunks/specdrift-WCLH6TTQ.js +19 -0
  163. package/chunks/variant-candidates-6KM6F6MD.js +13 -0
  164. package/chunks/web-recon-prepass-DPVCBRZA.js +1148 -0
  165. package/dashboard/assets/0sec-icon-66SreztZ.gif +0 -0
  166. package/dashboard/assets/bot-yILPnRgD.js +1 -0
  167. package/dashboard/assets/chevron-down-BeDJ-Vka.js +1 -0
  168. package/dashboard/assets/circle-alert-BEnMBMT-.js +1 -0
  169. package/dashboard/assets/client-DRYsuOGl.js +9 -0
  170. package/dashboard/assets/copy-Bi5vzoF9.js +1 -0
  171. package/dashboard/assets/desktop-CXTQonNm.js +32 -0
  172. package/dashboard/assets/desktop-NOekk4QS.css +1 -0
  173. package/dashboard/assets/dist-CmX-h7a4.js +1 -0
  174. package/dashboard/assets/dist-DAwYQmf_.js +45 -0
  175. package/dashboard/assets/findings-page-CACW9nw2.js +5 -0
  176. package/dashboard/assets/format-PoISqsES.js +1 -0
  177. package/dashboard/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  178. package/dashboard/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  179. package/dashboard/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  180. package/dashboard/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  181. package/dashboard/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  182. package/dashboard/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
  183. package/dashboard/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
  184. package/dashboard/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
  185. package/dashboard/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
  186. package/dashboard/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  187. package/dashboard/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  188. package/dashboard/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
  189. package/dashboard/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
  190. package/dashboard/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
  191. package/dashboard/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
  192. package/dashboard/assets/jsx-runtime-C7oxC63R.js +1 -0
  193. package/dashboard/assets/live-page-DrgQqQK5.js +1 -0
  194. package/dashboard/assets/meta-tile-CcskIV_o.js +1 -0
  195. package/dashboard/assets/operations-BKE8T-vY.css +2 -0
  196. package/dashboard/assets/operations-D8nUP5_m.js +4 -0
  197. package/dashboard/assets/operations-app-CQQhG54n.js +2 -0
  198. package/dashboard/assets/overview-page-DTGS8dPo.js +1 -0
  199. package/dashboard/assets/page-header-MFVvEtZW.js +1 -0
  200. package/dashboard/assets/play-Dwo-9xt6.js +1 -0
  201. package/dashboard/assets/scans-page-ChVtq8Us.js +1 -0
  202. package/dashboard/assets/search-CiooTLck.js +1 -0
  203. package/dashboard/assets/siren-CCBwTSuk.js +1 -0
  204. package/dashboard/assets/table-BYS-nIVA.js +1 -0
  205. package/dashboard/assets/tabs-DivxbhQy.js +1 -0
  206. package/dashboard/desktop.html +21 -0
  207. package/dashboard/index.html +15 -0
  208. package/package.json +30 -18
  209. package/bin/0sec.cjs +0 -361
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __0secCreateRequire } from "node:module";
3
+ const require = __0secCreateRequire(import.meta.url);
4
+
5
+ // packages/core/dist/shared-analysis.js
6
+ import { execFileSync } from "node:child_process";
7
+ import { mkdtempSync, rmSync, statSync, writeFileSync } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
10
+ var FOXGUARD_PINNED_TAG = "v0.14.0";
11
+ var CLI_RUNTIME_TYPES = /* @__PURE__ */ new Set(["claude", "codex", "gemini"]);
12
+ function bufferToString(value) {
13
+ if (!value) {
14
+ return "";
15
+ }
16
+ return Buffer.isBuffer(value) ? value.toString("utf-8") : value;
17
+ }
18
+ function mapSemgrepSeverity(level) {
19
+ switch (level.toUpperCase()) {
20
+ case "ERROR":
21
+ return "high";
22
+ case "WARNING":
23
+ return "medium";
24
+ case "INFO":
25
+ return "low";
26
+ default:
27
+ return "info";
28
+ }
29
+ }
30
+ function mapFoxguardSeverity(level) {
31
+ switch ((level ?? "").toLowerCase()) {
32
+ case "error":
33
+ case "critical":
34
+ return "critical";
35
+ case "warning":
36
+ case "high":
37
+ return "high";
38
+ case "note":
39
+ case "medium":
40
+ return "medium";
41
+ case "low":
42
+ return "low";
43
+ default:
44
+ return "info";
45
+ }
46
+ }
47
+ function runSemgrepScan(targetPath, emit, opts) {
48
+ emit({
49
+ type: "stage:start",
50
+ stage: "source-analysis",
51
+ message: "Running semgrep security scan..."
52
+ });
53
+ if (opts?.paths?.length === 0) {
54
+ emit({ type: "stage:end", stage: "source-analysis", message: "Semgrep: no files selected" });
55
+ return [];
56
+ }
57
+ const args = [
58
+ "scan",
59
+ "--config",
60
+ "auto",
61
+ "--json",
62
+ ...opts?.noGitIgnore ? ["--no-git-ignore"] : [],
63
+ "--timeout",
64
+ "60",
65
+ "--max-target-bytes",
66
+ "1000000",
67
+ ...opts?.paths ?? [targetPath]
68
+ ];
69
+ let rawOutput;
70
+ try {
71
+ rawOutput = execFileSync("semgrep", args, {
72
+ timeout: 3e5,
73
+ stdio: "pipe",
74
+ encoding: "utf-8",
75
+ env: { ...process.env, SEMGREP_SEND_METRICS: "off" }
76
+ });
77
+ } catch (err) {
78
+ if (!err || typeof err !== "object" || !("status" in err) || err.status !== 1)
79
+ throw err;
80
+ rawOutput = bufferToString("stdout" in err ? err.stdout : void 0);
81
+ }
82
+ const raw = JSON.parse(rawOutput);
83
+ if (!raw || !Array.isArray(raw.results))
84
+ throw new Error("invalid Semgrep JSON report");
85
+ const results = raw.results;
86
+ const findings = results.map((r) => ({
87
+ ruleId: r.check_id,
88
+ message: r.extra?.message ?? "",
89
+ severity: mapSemgrepSeverity(r.extra?.severity ?? "WARNING"),
90
+ path: r.path,
91
+ startLine: r.start?.line ?? 0,
92
+ endLine: r.end?.line ?? 0,
93
+ snippet: r.extra?.lines ?? "",
94
+ metadata: r.extra?.metadata
95
+ }));
96
+ emit({
97
+ type: "stage:end",
98
+ stage: "source-analysis",
99
+ message: `Semgrep: ${findings.length} findings`
100
+ });
101
+ return findings;
102
+ }
103
+ function selectedStaticScanner() {
104
+ return process.env["0SEC_STATIC"] === "semgrep" ? "semgrep" : "foxguard";
105
+ }
106
+ function runFoxguardScan(targetPath, emit, opts) {
107
+ emit({
108
+ type: "stage:start",
109
+ stage: "source-analysis",
110
+ message: "Running foxguard security scan..."
111
+ });
112
+ if (opts?.paths?.length === 0) {
113
+ emit({ type: "stage:end", stage: "source-analysis", message: "Foxguard: no files selected" });
114
+ return [];
115
+ }
116
+ const foxguardTag = opts?.foxguardTag ?? FOXGUARD_PINNED_TAG;
117
+ const runner = opts?.runner ?? execFileSync;
118
+ const logger = opts?.logger ?? ((m) => console.warn(m));
119
+ const cwd = statSync(targetPath, { throwIfNoEntry: false })?.isFile() ? dirname(resolve(targetPath)) : resolve(targetPath);
120
+ let useNpm = opts?.foxguardCommand !== void 0 || opts?.foxguardTag !== void 0;
121
+ const findings = [];
122
+ let selectionDir;
123
+ try {
124
+ let selectionFile;
125
+ if (opts?.paths && !opts.diffBase) {
126
+ const paths = opts.paths.map((path) => {
127
+ const selected = relative(cwd, resolve(cwd, path));
128
+ if (isAbsolute(selected) || selected === ".." || selected.startsWith(`..${sep}`) || /[\r\n\0]/.test(selected)) {
129
+ throw new Error(`selected Foxguard path is outside the scan root or cannot be represented: ${path}`);
130
+ }
131
+ return selected.split(sep).join("/");
132
+ });
133
+ selectionDir = mkdtempSync(join(tmpdir(), "0sec-foxguard-"));
134
+ selectionFile = join(selectionDir, "changed-files.txt");
135
+ writeFileSync(selectionFile, `${paths.join("\n")}
136
+ `, { mode: 384 });
137
+ }
138
+ const scanRoot = relative(cwd, resolve(targetPath)) || ".";
139
+ const invocations = [opts?.diffBase ? ["diff", opts.diffBase, scanRoot, "--format", "json"] : ["--format", "json", ...selectionFile ? ["--changed-files-from", selectionFile] : [], scanRoot]];
140
+ for (const args of invocations) {
141
+ let rawOutput;
142
+ const invoke = () => {
143
+ try {
144
+ return bufferToString(runner(useNpm ? opts?.foxguardCommand ?? "npx" : "foxguard", useNpm ? ["--yes", `foxguard@${foxguardTag}`, ...args] : args, {
145
+ cwd,
146
+ timeout: 3e5,
147
+ maxBuffer: 64 * 1024 * 1024,
148
+ stdio: "pipe",
149
+ encoding: "utf-8"
150
+ }));
151
+ } catch (err) {
152
+ if (err && typeof err === "object" && "status" in err && err.status === 1) {
153
+ return bufferToString("stdout" in err ? err.stdout : void 0);
154
+ }
155
+ throw err;
156
+ }
157
+ };
158
+ try {
159
+ rawOutput = invoke();
160
+ } catch (err) {
161
+ if (!useNpm && err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
162
+ useNpm = true;
163
+ rawOutput = invoke();
164
+ } else {
165
+ throw err;
166
+ }
167
+ }
168
+ const report = parseFoxguardJson(rawOutput);
169
+ if (report === null)
170
+ throw new Error("invalid Foxguard JSON report");
171
+ if (report.filesScanned === 0) {
172
+ throw new Error("Foxguard scanned 0 files; static coverage is unavailable (files may be excluded or unsupported)");
173
+ }
174
+ for (const finding of translateFoxguardFindings(report.findings)) {
175
+ finding.path = resolve(cwd, finding.path);
176
+ findings.push(finding);
177
+ }
178
+ }
179
+ } catch (err) {
180
+ const message = err instanceof Error ? err.message : String(err);
181
+ logger(`[0sec] foxguard scan failed (${message}). Npm pin: foxguard@${foxguardTag}. Set 0SEC_STATIC=semgrep to use semgrep.`);
182
+ emit({ type: "error", stage: "source-analysis", message: `Foxguard scan failed: ${message}` });
183
+ throw err;
184
+ } finally {
185
+ if (selectionDir)
186
+ rmSync(selectionDir, { recursive: true, force: true });
187
+ }
188
+ emit({
189
+ type: "stage:end",
190
+ stage: "source-analysis",
191
+ message: `Foxguard: ${findings.length} findings`
192
+ });
193
+ return findings;
194
+ }
195
+ function runSelectedStaticScan(targetPath, emit, opts) {
196
+ return selectedStaticScanner() === "foxguard" ? runFoxguardScan(targetPath, emit, opts) : runSemgrepScan(targetPath, emit, opts);
197
+ }
198
+ function parseFoxguardJson(rawJson) {
199
+ let parsed;
200
+ try {
201
+ parsed = JSON.parse(rawJson);
202
+ } catch {
203
+ return null;
204
+ }
205
+ if (Array.isArray(parsed))
206
+ return { findings: parsed };
207
+ if (!parsed || typeof parsed !== "object" || !("findings" in parsed))
208
+ return null;
209
+ for (const field of ["schema_version", "finding_schema_version"]) {
210
+ if (field in parsed && !/^1\.\d+\.\d+$/.test(String(parsed[field]))) {
211
+ return null;
212
+ }
213
+ }
214
+ if (!Array.isArray(parsed.findings))
215
+ return null;
216
+ const target = "target" in parsed ? parsed.target : void 0;
217
+ const filesScanned = target && typeof target === "object" && "files_scanned" in target ? target.files_scanned : void 0;
218
+ if (filesScanned !== void 0 && (typeof filesScanned !== "number" || !Number.isSafeInteger(filesScanned) || filesScanned < 0))
219
+ return null;
220
+ return { findings: parsed.findings, ...typeof filesScanned === "number" ? { filesScanned } : {} };
221
+ }
222
+ function translateFoxguardFindings(rawFindings) {
223
+ const out = [];
224
+ for (const raw of rawFindings) {
225
+ if (!raw || typeof raw !== "object")
226
+ continue;
227
+ if (!raw.rule_id || !raw.file || typeof raw.line !== "number")
228
+ continue;
229
+ const startLine = raw.line;
230
+ const endLine = typeof raw.end_line === "number" ? raw.end_line : startLine;
231
+ const metadata = { scanner: "foxguard" };
232
+ if (raw.cwe)
233
+ metadata.cwe = raw.cwe;
234
+ if (typeof raw.confidence === "number")
235
+ metadata.confidence = raw.confidence;
236
+ if (typeof raw.taint_hops === "number")
237
+ metadata.taintHops = raw.taint_hops;
238
+ if (raw.source_line || raw.sink_line) {
239
+ metadata.dataflow = {
240
+ sourceLine: raw.source_line,
241
+ sourceDescription: raw.source_description,
242
+ sinkLine: raw.sink_line,
243
+ sinkDescription: raw.sink_description
244
+ };
245
+ }
246
+ if (raw.fix_suggestion)
247
+ metadata.fixSuggestion = raw.fix_suggestion;
248
+ if (raw.tags && raw.tags.length > 0)
249
+ metadata.tags = raw.tags;
250
+ if (raw.crypto_algorithm)
251
+ metadata.cryptoAlgorithm = raw.crypto_algorithm;
252
+ if (raw.cnsa2_deadline)
253
+ metadata.cnsa2Deadline = raw.cnsa2_deadline;
254
+ if (raw.dep_name)
255
+ metadata.depName = raw.dep_name;
256
+ out.push({
257
+ ruleId: raw.rule_id,
258
+ message: raw.description ?? "",
259
+ severity: mapFoxguardSeverity(raw.severity),
260
+ path: raw.file,
261
+ startLine,
262
+ endLine,
263
+ snippet: raw.snippet ?? "",
264
+ metadata
265
+ });
266
+ }
267
+ return out;
268
+ }
269
+
270
+ export {
271
+ CLI_RUNTIME_TYPES,
272
+ bufferToString,
273
+ selectedStaticScanner,
274
+ runSelectedStaticScan
275
+ };