@quantakrypto/qscan
Advanced tools
| import type { RepoHeadRequester } from "@quantakrypto/core"; | ||
| /** | ||
| * Issue a HEAD request to `url` and classify the result: | ||
| * - a received HTTP response → `{ kind: "status", status }` (core treats 404/410 | ||
| * as unresolved); | ||
| * - a DNS / host-not-found failure → `{ kind: "unresolved" }` (the declared | ||
| * repository host does not exist); | ||
| * - anything else (timeout, TLS, reset, bad URL) → `{ kind: "error" }`, which | ||
| * core skips silently. Redirects are not followed — a 3xx means the URL | ||
| * resolves, which is all provenance needs. | ||
| */ | ||
| export declare const repoHeadRequest: RepoHeadRequester; | ||
| //# sourceMappingURL=provenance-net.d.ts.map |
| {"version":3,"file":"provenance-net.d.ts","sourceRoot":"","sources":["../src/provenance-net.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAmB,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE7E;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,iBA+B1B,CAAC"} |
| /** | ||
| * The networked half of the provenance check (`--audit`). | ||
| * | ||
| * `@quantakrypto/core`'s {@link checkProvenance} stays strictly offline (ADR-0005): | ||
| * it parses the manifest and decides what to verify, but delegates the actual | ||
| * HEAD request to an injected {@link RepoHeadRequester}. qScan is the plane | ||
| * allowed to make outbound requests, so the `node:https`/`node:http`-backed | ||
| * requester lives here. It NEVER rejects — every failure is mapped onto a | ||
| * {@link RepoHeadOutcome} so core's logic stays branch-simple. | ||
| */ | ||
| import * as http from "node:http"; | ||
| import * as https from "node:https"; | ||
| /** | ||
| * Issue a HEAD request to `url` and classify the result: | ||
| * - a received HTTP response → `{ kind: "status", status }` (core treats 404/410 | ||
| * as unresolved); | ||
| * - a DNS / host-not-found failure → `{ kind: "unresolved" }` (the declared | ||
| * repository host does not exist); | ||
| * - anything else (timeout, TLS, reset, bad URL) → `{ kind: "error" }`, which | ||
| * core skips silently. Redirects are not followed — a 3xx means the URL | ||
| * resolves, which is all provenance needs. | ||
| */ | ||
| export const repoHeadRequest = (url, timeoutMs) => new Promise((resolve) => { | ||
| let target; | ||
| try { | ||
| target = new URL(url); | ||
| } | ||
| catch { | ||
| resolve({ kind: "error", message: "invalid URL" }); | ||
| return; | ||
| } | ||
| if (target.protocol !== "http:" && target.protocol !== "https:") { | ||
| resolve({ kind: "error", message: `unsupported protocol ${target.protocol}` }); | ||
| return; | ||
| } | ||
| const mod = target.protocol === "http:" ? http : https; | ||
| const req = mod.request(target, { method: "HEAD", timeout: timeoutMs, headers: { "user-agent": "qscan-provenance" } }, (res) => { | ||
| res.resume(); // drain and free the socket. | ||
| resolve({ kind: "status", status: res.statusCode ?? 0 }); | ||
| }); | ||
| req.on("timeout", () => req.destroy(new Error("request timed out"))); | ||
| req.on("error", (err) => { | ||
| if (err.code === "ENOTFOUND" || err.code === "EAI_FAIL") { | ||
| resolve({ kind: "unresolved" }); | ||
| } | ||
| else { | ||
| resolve({ kind: "error", message: err.message }); | ||
| } | ||
| }); | ||
| req.end(); | ||
| }); | ||
| //# sourceMappingURL=provenance-net.js.map |
| {"version":3,"file":"provenance-net.js","sourceRoot":"","sources":["../src/provenance-net.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAIpC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAsB,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CACnE,IAAI,OAAO,CAAkB,CAAC,OAAO,EAAE,EAAE;IACvC,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAChE,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,wBAAwB,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC/E,OAAO;IACT,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;IACvD,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CACrB,MAAM,EACN,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,kBAAkB,EAAE,EAAE,EACrF,CAAC,GAAG,EAAE,EAAE;QACN,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,6BAA6B;QAC3C,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3D,CAAC,CACF,CAAC;IACF,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;IACrE,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;QAC7C,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACxD,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,EAAE,CAAC;AACZ,CAAC,CAAC,CAAC","sourcesContent":["/**\n * The networked half of the provenance check (`--audit`).\n *\n * `@quantakrypto/core`'s {@link checkProvenance} stays strictly offline (ADR-0005):\n * it parses the manifest and decides what to verify, but delegates the actual\n * HEAD request to an injected {@link RepoHeadRequester}. qScan is the plane\n * allowed to make outbound requests, so the `node:https`/`node:http`-backed\n * requester lives here. It NEVER rejects — every failure is mapped onto a\n * {@link RepoHeadOutcome} so core's logic stays branch-simple.\n */\nimport * as http from \"node:http\";\nimport * as https from \"node:https\";\n\nimport type { RepoHeadOutcome, RepoHeadRequester } from \"@quantakrypto/core\";\n\n/**\n * Issue a HEAD request to `url` and classify the result:\n * - a received HTTP response → `{ kind: \"status\", status }` (core treats 404/410\n * as unresolved);\n * - a DNS / host-not-found failure → `{ kind: \"unresolved\" }` (the declared\n * repository host does not exist);\n * - anything else (timeout, TLS, reset, bad URL) → `{ kind: \"error\" }`, which\n * core skips silently. Redirects are not followed — a 3xx means the URL\n * resolves, which is all provenance needs.\n */\nexport const repoHeadRequest: RepoHeadRequester = (url, timeoutMs) =>\n new Promise<RepoHeadOutcome>((resolve) => {\n let target: URL;\n try {\n target = new URL(url);\n } catch {\n resolve({ kind: \"error\", message: \"invalid URL\" });\n return;\n }\n if (target.protocol !== \"http:\" && target.protocol !== \"https:\") {\n resolve({ kind: \"error\", message: `unsupported protocol ${target.protocol}` });\n return;\n }\n const mod = target.protocol === \"http:\" ? http : https;\n const req = mod.request(\n target,\n { method: \"HEAD\", timeout: timeoutMs, headers: { \"user-agent\": \"qscan-provenance\" } },\n (res) => {\n res.resume(); // drain and free the socket.\n resolve({ kind: \"status\", status: res.statusCode ?? 0 });\n },\n );\n req.on(\"timeout\", () => req.destroy(new Error(\"request timed out\")));\n req.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"ENOTFOUND\" || err.code === \"EAI_FAIL\") {\n resolve({ kind: \"unresolved\" });\n } else {\n resolve({ kind: \"error\", message: err.message });\n }\n });\n req.end();\n });\n"]} |
+8
-0
@@ -145,2 +145,10 @@ /** | ||
| /** | ||
| * Run opt-in supply-chain audit checks (`--audit`): shell out to each present | ||
| * ecosystem's advisory tool (cargo audit / pip-audit / npm audit) for known- | ||
| * vulnerable pinned dependencies, and verify the declared source repository | ||
| * resolves (provenance). Findings merge into the report + exit code; a missing | ||
| * tool or network hiccup degrades to a diagnostic, never a failure. | ||
| */ | ||
| audit: boolean; | ||
| /** | ||
| * Compute + emit HNDL (harvest-now-decrypt-later) exposure (`--hndl`). Reads | ||
@@ -147,0 +155,0 @@ * `hndl.yml` at the scan root, scores each finding + a repo summary, and adds |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"} |
+5
-0
@@ -49,2 +49,3 @@ /** | ||
| hndl: false, | ||
| audit: false, | ||
| mandates: [], | ||
@@ -350,2 +351,6 @@ failNow: false, | ||
| break; | ||
| case "--audit": | ||
| rejectInlineValue(); | ||
| options.audit = true; | ||
| break; | ||
| // Crypto-agility manifest controls (see `crypto-agility emit`). | ||
@@ -352,0 +357,0 @@ case "--crypto-agility": |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,cAAc,EACd,cAAc,EACd,YAAY,EACZ,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAI5B,qFAAqF;AACrF,MAAM,cAAc,GAA4B,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;AAC5F,iFAAiF;AACjF,MAAM,cAAc,GAA4B,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;AAC7E,qCAAqC;AACrC,MAAM,aAAa,GAAG,CAAC,WAAW,EAAE,mBAAmB,CAAU,CAAC;AAGlE,4EAA4E;AAC5E,2EAA2E;AAC3E,iFAAiF;AACjF,wDAAwD;AACxD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC;AAWxD,MAAM,OAAO,GAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;AAyM9F,mEAAmE;AACnE,MAAM,OAAO,QAAS,SAAQ,KAAK;IACf,IAAI,GAAG,UAAU,CAAC;CACrC;AAED,qDAAqD;AACrD,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,IAAI,EAAE,GAAG;QACT,MAAM,EAAE,OAAO;QACf,iBAAiB,EAAE,MAAM;QACzB,MAAM,EAAE,IAAI;QACZ,YAAY,EAAE,IAAI;QAClB,MAAM,EAAE,IAAI;QACZ,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,EAAE;QACX,gBAAgB,EAAE,KAAK;QACvB,YAAY,EAAE,KAAK;QACnB,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE,KAAK;QACZ,WAAW,EAAE,MAAM;QACnB,UAAU,EAAE,KAAK;QACjB,YAAY,EAAE,KAAK;QACnB,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,KAAK;QACX,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE,KAAK;KACf,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,sEAAsE;AACtE,MAAM,CAAC,MAAM,kBAAkB,GAAG,0BAA0B,CAAC;AAE7D,MAAM,UAAU,SAAS,CAAC,IAAuB;IAC/C,gFAAgF;IAChF,6EAA6E;IAC7E,kEAAkE;IAClE,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7C,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;gBAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC9D,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,IAAI;gBAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;YACpE,MAAM,IAAI,QAAQ,CAAC,+CAA+C,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;YACnB,MAAM,IAAI,QAAQ,CAAC,4BAA4B,GAAG,oBAAoB,CAAC,CAAC;QAC1E,CAAC;QACD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK;YAAE,OAAO,MAAM,CAAC,CAAC,iCAAiC;QAC3E,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACxD,CAAC;IAED,uDAAuD;IACvD,iEAAiE;IACjE,gEAAgE;IAChE,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,gBAAgB,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7C,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;gBAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC9D,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,IAAI;gBAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;YACpE,MAAM,IAAI,QAAQ,CAAC,mEAAmE,CAAC,CAAC;QAC1F,CAAC;QACD,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,6EAA6E;YAC7E,qEAAqE;YACrE,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK;gBAAE,OAAO,MAAM,CAAC;YACzC,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QAClE,CAAC;QACD,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC3B,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC5E,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;YAClF,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAC1E,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,MAAM,IAAI,QAAQ,CAAC,yDAAyD,CAAC,CAAC;YAChF,CAAC;YACD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,QAAQ,CAChB,yDAAyD,WAAW,CAAC,MAAM,GAAG,CAC/E,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,yBAAyB,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAW,EAAE,CAAC;QAC7E,CAAC;QACD,MAAM,IAAI,QAAQ,CAAC,sCAAsC,GAAG,8BAA8B,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,8EAA8E;AAC9E,SAAS,YAAY,CAAC,IAAuB;IAC3C,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC5C,IAAI,UAA8B,CAAC;IACnC,6EAA6E;IAC7E,IAAI,YAAY,GAAG,KAAK,CAAC;IAEzB,yEAAyE;IACzE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAW,CAAC;QAE9B,mDAAmD;QACnD,IAAI,WAA+B,CAAC;QACpC,IAAI,IAAI,GAAG,GAAG,CAAC;QACf,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxB,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAClC,CAAC;QAED,mFAAmF;QACnF,MAAM,SAAS,GAAG,GAAW,EAAE;YAC7B,IAAI,WAAW,KAAK,SAAS;gBAAE,OAAO,WAAW,CAAC;YAClD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACzB,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACjE,MAAM,IAAI,QAAQ,CAAC,WAAW,IAAI,oBAAoB,CAAC,CAAC;YAC1D,CAAC;YACD,CAAC,EAAE,CAAC;YACJ,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;QAEF;;;;WAIG;QACH,MAAM,iBAAiB,GAAG,GAAS,EAAE;YACnC,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,MAAM,IAAI,QAAQ,CAAC,WAAW,IAAI,wCAAwC,CAAC,CAAC;YAC9E,CAAC;QACH,CAAC,CAAC;QAEF,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,IAAI,CAAC;YACV,KAAK,QAAQ;gBACX,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC1B,KAAK,IAAI,CAAC;YACV,KAAK,WAAW;gBACd,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;YAE7B,KAAK,UAAU;gBACb,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;gBACvC,MAAM;YACR,KAAK,QAAQ;gBACX,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;gBACxB,MAAM;YACR,KAAK,SAAS;gBACZ,uEAAuE;gBACvE,6CAA6C;gBAC7C,CAAC,OAAO,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;gBAC9C,MAAM;YACR,KAAK,IAAI,CAAC;YACV,KAAK,UAAU;gBACb,OAAO,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;gBAC7B,MAAM;YACR,KAAK,sBAAsB;gBACzB,OAAO,CAAC,iBAAiB,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC;gBACpD,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;gBAClC,MAAM;YAER,KAAK,aAAa;gBAChB,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC;gBACvB,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACvB,MAAM;YACR,KAAK,WAAW;gBACd,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,YAAY,GAAG,KAAK,CAAC;gBAC7B,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;gBAC7B,MAAM;YACR,KAAK,aAAa;gBAChB,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC;gBACvB,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACvB,MAAM;YAER,KAAK,UAAU;gBACb,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;gBACjC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACvB,MAAM;YACR,KAAK,WAAW;gBACd,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;gBAClC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACxB,MAAM;YACR,KAAK,iBAAiB;gBACpB,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,SAAS,EAAE,EAAE,iBAAiB,CAAC,CAAC;gBAC5D,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBAC5B,MAAM;YACR,KAAK,OAAO;gBACV,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC;gBAC3C,MAAM;YACR,KAAK,UAAU;gBACb,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;gBACtB,MAAM;YACR,KAAK,gBAAgB;gBACnB,OAAO,CAAC,WAAW,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC;gBAC9C,MAAM;YACR,KAAK,gBAAgB;gBACnB,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,SAAS,EAAE,EAAE,gBAAgB,CAAC,CAAC;gBAC3D,MAAM;YACR,KAAK,QAAQ;gBACX,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;gBACnC,MAAM;YACR,KAAK,WAAW;gBACd,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC;gBACzC,MAAM;YACR,KAAK,WAAW;gBACd,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;gBACnC,MAAM;YACR,KAAK,eAAe;gBAClB,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,CAAC;gBACzD,MAAM;YACR,KAAK,YAAY;gBACf,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;gBACvB,MAAM;YACR,KAAK,WAAW;gBACd,OAAO,CAAC,YAAY,GAAG,cAAc,CAAC,SAAS,EAAE,CAAC,CAAC;gBACnD,MAAM;YACR,KAAK,WAAW;gBACd,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;gBACtB,MAAM;YACR,KAAK,gBAAgB;gBACnB,OAAO,CAAC,WAAW,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC;gBAC9C,MAAM;YACR,KAAK,aAAa;gBAChB,OAAO,CAAC,QAAQ,GAAG,SAAS,EAAE,CAAC;gBAC/B,MAAM;YACR,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,oEAAoE;gBACpE,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;oBAC9B,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC;gBAClC,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;oBACzB,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;wBAClE,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;wBACzB,CAAC,EAAE,CAAC;oBACN,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,SAAS,GAAG,kBAAkB,CAAC;oBACzC,CAAC;gBACH,CAAC;gBACD,MAAM;YACR,CAAC;YACD,KAAK,sBAAsB;gBACzB,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;gBAChC,QAAQ,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;gBACjC,MAAM;YACR,KAAK,iBAAiB;gBACpB,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;gBAC5B,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;gBAC7B,MAAM;YAER,+EAA+E;YAC/E,iDAAiD;YACjD,KAAK,UAAU;gBACb,OAAO,CAAC,UAAU,GAAG,SAAS,EAAE,CAAC;gBACjC,MAAM;YACR,KAAK,kBAAkB;gBACrB,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;gBAC5B,MAAM;YAER,KAAK,WAAW;gBACd,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;gBACvB,MAAM;YACR,KAAK,SAAS;gBACZ,OAAO,CAAC,KAAK,GAAG,SAAS,EAAE,CAAC;gBAC5B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,mCAAmC;gBAC3D,MAAM;YAER,KAAK,YAAY;gBACf,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACxB,MAAM;YACR,KAAK,eAAe,CAAC,CAAC,CAAC;gBACrB,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,EAAE,EAAE,eAAe,CAAC,CAAC;gBAC9C,OAAO,CAAC,WAAW,GAAG,CAAC,CAAC;gBACxB,uEAAuE;gBACvE,wEAAwE;gBACxE,yEAAyE;gBACzE,oBAAoB;gBACpB,OAAO,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC1B,MAAM;YACR,CAAC;YAED,KAAK,YAAY;gBACf,OAAO,CAAC,QAAQ,GAAG,SAAS,EAAE,CAAC;gBAC/B,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACzB,MAAM;YACR,KAAK,UAAU;gBACb,OAAO,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;gBAC7B,MAAM;YACR,KAAK,QAAQ;gBACX,OAAO,CAAC,IAAI,GAAG,SAAS,EAAE,CAAC;gBAC3B,MAAM;YACR,KAAK,aAAa;gBAChB,OAAO,CAAC,SAAS,GAAG,SAAS,EAAE,CAAC;gBAChC,MAAM;YACR,KAAK,kBAAkB;gBACrB,OAAO,CAAC,aAAa,GAAG,SAAS,EAAE,CAAC;gBACpC,MAAM;YACR,KAAK,SAAS;gBACZ,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;gBACrB,MAAM;YACR,KAAK,SAAS;gBACZ,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,WAAW,GAAG,QAAQ,CAAC;gBAC/B,MAAM;YACR,KAAK,YAAY;gBACf,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,WAAW,GAAG,OAAO,CAAC;gBAC9B,MAAM;YACR,KAAK,eAAe;gBAClB,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;gBAC1B,MAAM;YACR,KAAK,QAAQ;gBACX,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;gBACpB,MAAM;YAER,gEAAgE;YAChE,KAAK,kBAAkB;gBACrB,iBAAiB,EAAE,CAAC;gBACpB,YAAY,GAAG,IAAI,CAAC;gBACpB,MAAM;YACR,KAAK,eAAe;gBAClB,OAAO,CAAC,WAAW,GAAG,SAAS,EAAE,CAAC;gBAClC,MAAM;YACR,KAAK,cAAc;gBACjB,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;gBAC9B,MAAM;YACR,KAAK,iBAAiB;gBACpB,iBAAiB,EAAE,CAAC;gBACpB,OAAO,CAAC,cAAc,GAAG,KAAK,CAAC;gBAC/B,MAAM;YAER;gBACE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oBACzC,MAAM,IAAI,QAAQ,CAAC,mBAAmB,IAAI,GAAG,CAAC,CAAC;gBACjD,CAAC;gBACD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;oBAC7B,MAAM,IAAI,QAAQ,CAChB,8BAA8B,GAAG,2BAA2B,UAAU,IAAI,CAC3E,CAAC;gBACJ,CAAC;gBACD,UAAU,GAAG,GAAG,CAAC;gBACjB,MAAM;QACV,CAAC;IACH,CAAC;IAED,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,GAAG,UAAU,CAAC;IACxD,iFAAiF;IACjF,mEAAmE;IACnE,IAAI,YAAY;QAAE,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,CAAC;IAClE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC5C,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,IAAK,OAA6B,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAoB,CAAC;IAChF,MAAM,IAAI,QAAQ,CAAC,qBAAqB,KAAK,uBAAuB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7F,CAAC;AAED,8CAA8C;AAC9C,SAAS,cAAc,CAAC,KAAa;IACnC,IAAK,cAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAqB,CAAC;IACxF,MAAM,IAAI,QAAQ,CAChB,sBAAsB,KAAK,uBAAuB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC/E,CAAC;AACJ,CAAC;AAED,2CAA2C;AAC3C,SAAS,MAAM,CAAC,KAAa;IAC3B,IAAK,cAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAqB,CAAC;IACxF,MAAM,IAAI,QAAQ,CAAC,mBAAmB,KAAK,uBAAuB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClG,CAAC;AAED,2EAA2E;AAC3E,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,GAAG,GAAG,mBAAmB,EAAE,CAAC;IAClC,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,MAAM,IAAI,QAAQ,CAAC,sBAAsB,KAAK,uBAAuB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1F,CAAC;AAED,mDAAmD;AACnD,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAK,aAAmC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAoB,CAAC;IACtF,MAAM,IAAI,QAAQ,CAChB,2BAA2B,KAAK,uBAAuB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACnF,CAAC;AACJ,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,KAAK,CAAC,KAAa,EAAE,IAAY;IAC/C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,QAAQ,CAAC,WAAW,IAAI,KAAK,KAAK,qCAAqC,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACpC,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAK,cAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAiB,CAAC;IACpF,MAAM,IAAI,QAAQ,CAAC,qBAAqB,KAAK,uBAAuB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpG,CAAC","sourcesContent":["/**\n * Zero-dependency command-line argument parsing for qScan.\n *\n * Hand-rolled rather than pulled from a library to keep the package free of\n * runtime dependencies. The grammar is deliberately small: long flags\n * (`--flag`, `--flag value`, `--flag=value`), a couple of short aliases\n * (`-o`, `-v`, `-h`), repeatable `--ignore`, and a single optional positional\n * path. Unknown flags are a usage error.\n */\n\nimport {\n meetsThreshold,\n SEVERITY_ORDER,\n severityRank,\n standardsProfileIds,\n} from \"@quantakrypto/core\";\nimport type { ContextLevel, ReportFormat, SecurityTier, Severity } from \"@quantakrypto/core\";\nimport type { ColorChoice } from \"./color.js\";\n\n/** Valid context levels for `--context` (how much source triage/remediate sends). */\nconst CONTEXT_LEVELS: readonly ContextLevel[] = [\"metadata\", \"snippet\", \"function\", \"file\"];\n/** Valid CNSA security tiers for `--tier` (report migration-target guidance). */\nconst SECURITY_TIERS: readonly SecurityTier[] = [\"category-3\", \"category-5\"];\n/** Valid `--llm-provider` values. */\nconst LLM_PROVIDERS = [\"anthropic\", \"openai-compatible\"] as const;\nexport type LlmProvider = (typeof LLM_PROVIDERS)[number];\n\n// Severity ordering, ranking, and threshold logic are the monorepo's single\n// source of truth in `@quantakrypto/core`. Re-export them here so existing\n// `@quantakrypto/qscan` callers (and tests) keep importing them from `./args.js`\n// without qScan maintaining a second, drift-prone copy.\nexport { meetsThreshold, SEVERITY_ORDER, severityRank };\n\n/**\n * Output formats qScan accepts on the command line. Extends core's\n * {@link ReportFormat} with `\"cbom\"` (a CycloneDX cryptographic bill of\n * materials), `\"evidence\"` (ISO A.8.24 readiness report), and `\"vex\"` (an\n * OpenVEX 0.2.0 document) — all rendered locally via core (`toCbom`,\n * `buildReadinessReport`, `toOpenVex`).\n */\nexport type QscanFormat = ReportFormat | \"cbom\" | \"evidence\" | \"vex\";\n\nconst FORMATS: readonly QscanFormat[] = [\"human\", \"json\", \"sarif\", \"cbom\", \"evidence\", \"vex\"];\n\n/** Fully-resolved options the CLI/programmatic runner operates on. */\nexport interface QscanOptions {\n /** Directory or file to scan. */\n path: string;\n /** Report format. */\n format: QscanFormat;\n /** Write the report to this file instead of stdout, when set. */\n output?: string;\n /** External CBOM files to merge into the `--cbom` output (CycloneDX bom-link). */\n mergeCboms?: string[];\n /** Findings at or above this severity cause a non-zero exit. */\n severityThreshold: Severity;\n /** Scan source files for inline crypto usage. */\n source: boolean;\n /** Scan dependency manifests for vulnerable libraries. */\n dependencies: boolean;\n /** Scan config files (TLS/certificates). */\n config: boolean;\n /** Extra exclude patterns (repeatable `--ignore`). */\n ignore: string[];\n /**\n * Restrict the walk to paths matching one of these include patterns\n * (repeatable `--include`). When empty, every non-excluded file is scanned.\n */\n include: string[];\n /** Max file size to read, in bytes (`--max-file-size`). */\n maxFileSize?: number;\n /** Disable the built-in ignore list (`--no-default-ignores`). */\n noDefaultIgnores: boolean;\n /** Compliance mandates to gate findings against (repeatable `--mandate <id>`). */\n mandates: string[];\n /** Fail early when a mandate deadline is within this many months (`--lead-months`). */\n leadMonths?: number;\n /** Fail on any mandate-prohibited finding now, ignoring the deadline (`--fail-now`). */\n failNow: boolean;\n /** Scan minified/generated/bundled files instead of skipping them. */\n scanMinified: boolean;\n /**\n * Incremental mode: scan only the files git reports as changed\n * (`--changed`), optionally relative to {@link since}.\n */\n changed: boolean;\n /** Git ref/range the `--changed` diff is taken against (`--since`). */\n since?: string;\n /** Route the scan through core's worker-thread pool (`--parallel`). */\n parallel: boolean;\n /**\n * Worker count for parallel scanning (`--concurrency`). Implies parallel.\n * A value of 0 or 1 forces the in-process serial path.\n */\n concurrency?: number;\n /** Suppress findings whose fingerprint is in this baseline file. */\n baseline?: string;\n /** Write current findings as a baseline to this file, then exit 0. */\n writeBaseline?: string;\n /** Suppress the human summary banner (still writes reports/output files). */\n quiet: boolean;\n /**\n * ANSI color policy for the human report (`--color` / `--no-color`). `\"auto\"`\n * (default) colors only a live terminal and honors `NO_COLOR` / `FORCE_COLOR`;\n * see {@link resolveColor}. Color is decoration only — never the sole signal.\n */\n colorChoice: ColorChoice;\n /** How many findings the human report lists (`--top N`). Default: 5. */\n topN?: number;\n /** Rule ids to suppress (from `quantakrypto.config.json` `disabledRules`). */\n disabledRules?: string[];\n /** Content-hash scan cache path (`--cache [path]`); reuse unchanged files. */\n cacheFile?: string;\n /** Run the BYOK LLM triage pass (`--triage`): annotate + re-sort, never suppress. */\n triage: boolean;\n /** Only triage findings at/above this seriousness (`--triage-floor`). Default: medium. */\n triageFloor?: Severity;\n /** Cap findings sent to the LLM during triage (`--max-findings`; spend guard). */\n maxFindings?: number;\n /** CNSA security tier for the migration-targets footer (`--tier`). Default: none. */\n tier?: SecurityTier;\n /**\n * Standards regime the migration guidance is tailored to (`--profile`): one of the\n * built-in ids (nist / cnsa-2.0 / bsi-tr-02102 / anssi / uk-ncsc). Default: none\n * (`--tier` maps to a profile for back-compat). Governs parameter sets, deadlines,\n * and the hybrid stance surfaced in remediation.\n */\n profile?: string;\n /** Org cryptography policy file (`--policy`) for the evidence report's §4 verdicts. */\n policy?: string;\n /**\n * External signer command for the evidence attestation (`--sign`). The report's\n * contentHash is piped to it on stdin; its stdout is recorded as the detached\n * signature. Only valid with `--format evidence`.\n */\n sign?: string;\n /** External RFC-3161 timestamper command for the evidence attestation (`--timestamp`). */\n timestamp?: string;\n /** How much source context leaves the machine (`--context`). Default: snippet. */\n contextLevel?: ContextLevel;\n /** Print the exact triage payload and exit without calling the provider (`--dry-run`). */\n dryRun: boolean;\n /** BYOK provider (`--llm-provider`). Default: anthropic. */\n llmProvider?: LlmProvider;\n /** BYOK model id (`--llm-model`). */\n llmModel?: string;\n /**\n * Omit code snippets from the JSON/SARIF report (`--no-snippets`). Passed to\n * core's reporters as `{ redactSnippets: true }`. Snippets of `sensitive`\n * findings are always omitted regardless of this flag.\n */\n noSnippets: boolean;\n /**\n * Explicit path to a `quantakrypto.config.json` (`--config <path>`). Overrides\n * auto-discovery at the scan root. Distinct from `--no-config`, which toggles\n * config/TLS *detector* scanning — this names the config FILE.\n */\n configFile?: string;\n /**\n * Disable `quantakrypto.config.json` auto-discovery (`--no-config-file`). Distinct\n * from `--no-config` (which skips config-file *detectors*).\n */\n noConfigFile: boolean;\n /**\n * Compute + emit HNDL (harvest-now-decrypt-later) exposure (`--hndl`). Reads\n * `hndl.yml` at the scan root, scores each finding + a repo summary, and adds\n * the exposure fields to the JSON / SARIF report. Additive: never changes the\n * exit code. See docs/HNDL.md.\n */\n hndl: boolean;\n /**\n * URL to a posture credential recorded in a crypto-agility manifest\n * (`--attestation`). Only consumed by `crypto-agility emit`; recorded verbatim,\n * never fetched (offline boundary). See docs/CRYPTO-AGILITY-MANIFEST.md.\n */\n attestation?: string;\n /**\n * Operator assertion of hybrid post-quantum key exchange for a crypto-agility\n * manifest (`--hybrid-kex` → true, `--no-hybrid-kex` → false). Left undefined,\n * the manifest reports `hybridKexInUse: null` (a static scan cannot observe a\n * negotiated TLS group). Only consumed by `crypto-agility emit`.\n */\n hybridKexInUse?: boolean;\n}\n\n/**\n * Option keys that a `quantakrypto.config.json` may also set. When such a key was set\n * by a CLI flag, the flag wins (precedence: flags > config > defaults); when it\n * was left at its default, config may fill it. {@link parseArgs} records which\n * of these keys came from an explicit flag in {@link ParsedRun.explicit}.\n */\nexport type ConfigurableKey =\n | \"severityThreshold\"\n | \"source\"\n | \"dependencies\"\n | \"config\"\n | \"include\"\n | \"ignore\"\n | \"maxFileSize\"\n | \"noDefaultIgnores\"\n | \"scanMinified\"\n | \"baseline\";\n\n/** A successful parse: resolved options plus which configurable keys were explicit. */\nexport interface ParsedRun {\n kind: \"run\";\n options: QscanOptions;\n /** The set of {@link ConfigurableKey}s the user set via a flag. */\n explicit: Set<ConfigurableKey>;\n}\n\n/** The `qscan hndl init` subcommand: scaffold an `hndl.yml`. */\nexport interface ParsedHndlInit {\n kind: \"hndl-init\";\n options: QscanOptions;\n}\n\n/**\n * Emit a crypto-agility manifest: either `qscan crypto-agility emit [path]` or the\n * `--crypto-agility` flag on a normal scan. Additive: it always exits 0, never\n * consulting the severity threshold.\n */\nexport interface ParsedCryptoAgilityEmit {\n kind: \"crypto-agility-emit\";\n options: QscanOptions;\n}\n\n/** Validate a local manifest file: `qscan crypto-agility validate <file>`. */\nexport interface ParsedCryptoAgilityValidate {\n kind: \"crypto-agility-validate\";\n /** Path to the manifest JSON file to check. */\n file: string;\n}\n\n/** Result of {@link parseArgs}: either resolved options or a meta action. */\nexport type ParsedArgs =\n | ParsedRun\n | ParsedHndlInit\n | ParsedCryptoAgilityEmit\n | ParsedCryptoAgilityValidate\n | { kind: \"help\" }\n | { kind: \"version\" };\n\n/** Thrown on malformed input; the CLI maps this to exit code 2. */\nexport class ArgError extends Error {\n override readonly name = \"ArgError\";\n}\n\n/** Default options, before any flags are applied. */\nexport function defaultOptions(): QscanOptions {\n return {\n path: \".\",\n format: \"human\",\n severityThreshold: \"high\",\n source: true,\n dependencies: true,\n config: true,\n ignore: [],\n include: [],\n noDefaultIgnores: false,\n scanMinified: false,\n changed: false,\n parallel: false,\n quiet: false,\n colorChoice: \"auto\",\n noSnippets: false,\n noConfigFile: false,\n triage: false,\n dryRun: false,\n hndl: false,\n mandates: [],\n failNow: false,\n };\n}\n\n/**\n * Parse a raw argv slice (i.e. without `node` and the script path).\n *\n * @throws {ArgError} On unknown flags, missing values, or invalid enum values.\n */\n/** Default scan-cache file when `--cache` is given without a path. */\nexport const DEFAULT_CACHE_FILE = \".quantakrypto-cache.json\";\n\nexport function parseArgs(argv: readonly string[]): ParsedArgs {\n // Subcommand dispatch: `qscan hndl <sub> …`. Only `init` exists today. `--help`\n // / `--version` anywhere still short-circuit to the meta actions (handled by\n // the shared loop below), so `qscan hndl init --help` shows help.\n if (argv[0] === \"hndl\") {\n const sub = argv[1];\n if (sub === undefined || sub.startsWith(\"-\")) {\n if (sub === \"--help\" || sub === \"-h\") return { kind: \"help\" };\n if (sub === \"--version\" || sub === \"-v\") return { kind: \"version\" };\n throw new ArgError(`\"hndl\" requires a subcommand (expected: init)`);\n }\n if (sub !== \"init\") {\n throw new ArgError(`unknown hndl subcommand \"${sub}\" (expected: init)`);\n }\n const parsed = parseRunArgs(argv.slice(2));\n if (parsed.kind !== \"run\") return parsed; // --help / --version passthrough\n return { kind: \"hndl-init\", options: parsed.options };\n }\n\n // Subcommand dispatch: `qscan crypto-agility <sub> …`.\n // emit [path] derive + write a manifest (always exits 0)\n // validate <file> check a local manifest against the schema\n if (argv[0] === \"crypto-agility\") {\n const sub = argv[1];\n if (sub === undefined || sub.startsWith(\"-\")) {\n if (sub === \"--help\" || sub === \"-h\") return { kind: \"help\" };\n if (sub === \"--version\" || sub === \"-v\") return { kind: \"version\" };\n throw new ArgError(`\"crypto-agility\" requires a subcommand (expected: emit, validate)`);\n }\n if (sub === \"emit\") {\n const parsed = parseRunArgs(argv.slice(2));\n // `--help`/`--version` short-circuit; a redundant `--crypto-agility` flag on\n // the emit subcommand already yields the emit kind (returned as-is).\n if (parsed.kind !== \"run\") return parsed;\n return { kind: \"crypto-agility-emit\", options: parsed.options };\n }\n if (sub === \"validate\") {\n const rest = argv.slice(2);\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) return { kind: \"help\" };\n if (rest.includes(\"--version\") || rest.includes(\"-v\")) return { kind: \"version\" };\n const positionals = rest.filter((a) => !(a.startsWith(\"-\") && a !== \"-\"));\n if (positionals.length === 0) {\n throw new ArgError(`\"crypto-agility validate\" requires a manifest file path`);\n }\n if (positionals.length > 1) {\n throw new ArgError(\n `\"crypto-agility validate\" takes exactly one file (got ${positionals.length})`,\n );\n }\n return { kind: \"crypto-agility-validate\", file: positionals[0] as string };\n }\n throw new ArgError(`unknown crypto-agility subcommand \"${sub}\" (expected: emit, validate)`);\n }\n return parseRunArgs(argv);\n}\n\n/** Parse the run-mode grammar (flags + a single optional positional path). */\nfunction parseRunArgs(argv: readonly string[]): ParsedArgs {\n const options = defaultOptions();\n const explicit = new Set<ConfigurableKey>();\n let positional: string | undefined;\n // Set by `--crypto-agility`: the whole run becomes a manifest emit (exit 0).\n let emitManifest = false;\n\n // Manual index walk so flags can consume the following token as a value.\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i] as string;\n\n // `--flag=value` → split into flag + inline value.\n let inlineValue: string | undefined;\n let flag = arg;\n if (arg.startsWith(\"--\") && arg.includes(\"=\")) {\n const eq = arg.indexOf(\"=\");\n flag = arg.slice(0, eq);\n inlineValue = arg.slice(eq + 1);\n }\n\n /** Consume a value for `flag`: prefer the inline `=value`, else the next token. */\n const takeValue = (): string => {\n if (inlineValue !== undefined) return inlineValue;\n const next = argv[i + 1];\n if (next === undefined || (next.startsWith(\"-\") && next !== \"-\")) {\n throw new ArgError(`option \"${flag}\" requires a value`);\n }\n i++;\n return next;\n };\n\n /**\n * Reject an inline `=value` on a boolean flag. Without this, `--quiet=false`\n * would silently ignore the value and turn the flag ON — the opposite of the\n * caller's intent. Boolean flags take no value, so any `=value` is an error.\n */\n const rejectInlineValue = (): void => {\n if (inlineValue !== undefined) {\n throw new ArgError(`option \"${flag}\" is a boolean flag and takes no value`);\n }\n };\n\n switch (flag) {\n case \"-h\":\n case \"--help\":\n return { kind: \"help\" };\n case \"-v\":\n case \"--version\":\n return { kind: \"version\" };\n\n case \"--format\":\n options.format = asFormat(takeValue());\n break;\n case \"--cbom\":\n rejectInlineValue();\n options.format = \"cbom\";\n break;\n case \"--merge\":\n // Merge an external CBOM (e.g. a qprobe endpoint CBOM) into the --cbom\n // output via CycloneDX bom-link. Repeatable.\n (options.mergeCboms ??= []).push(takeValue());\n break;\n case \"-o\":\n case \"--output\":\n options.output = takeValue();\n break;\n case \"--severity-threshold\":\n options.severityThreshold = asSeverity(takeValue());\n explicit.add(\"severityThreshold\");\n break;\n\n case \"--no-source\":\n rejectInlineValue();\n options.source = false;\n explicit.add(\"source\");\n break;\n case \"--no-deps\":\n rejectInlineValue();\n options.dependencies = false;\n explicit.add(\"dependencies\");\n break;\n case \"--no-config\":\n rejectInlineValue();\n options.config = false;\n explicit.add(\"config\");\n break;\n\n case \"--ignore\":\n options.ignore.push(takeValue());\n explicit.add(\"ignore\");\n break;\n case \"--include\":\n options.include.push(takeValue());\n explicit.add(\"include\");\n break;\n case \"--max-file-size\":\n options.maxFileSize = asInt(takeValue(), \"--max-file-size\");\n explicit.add(\"maxFileSize\");\n break;\n case \"--top\":\n options.topN = asInt(takeValue(), \"--top\");\n break;\n case \"--triage\":\n rejectInlineValue();\n options.triage = true;\n break;\n case \"--triage-floor\":\n options.triageFloor = asSeverity(takeValue());\n break;\n case \"--max-findings\":\n options.maxFindings = asInt(takeValue(), \"--max-findings\");\n break;\n case \"--tier\":\n options.tier = asTier(takeValue());\n break;\n case \"--profile\":\n options.profile = asProfile(takeValue());\n break;\n case \"--mandate\":\n options.mandates.push(takeValue());\n break;\n case \"--lead-months\":\n options.leadMonths = asInt(takeValue(), \"--lead-months\");\n break;\n case \"--fail-now\":\n rejectInlineValue();\n options.failNow = true;\n break;\n case \"--context\":\n options.contextLevel = asContextLevel(takeValue());\n break;\n case \"--dry-run\":\n rejectInlineValue();\n options.dryRun = true;\n break;\n case \"--llm-provider\":\n options.llmProvider = asProvider(takeValue());\n break;\n case \"--llm-model\":\n options.llmModel = takeValue();\n break;\n case \"--cache\": {\n // `--cache` alone uses the default file; `--cache <path>` names it.\n if (inlineValue !== undefined) {\n options.cacheFile = inlineValue;\n } else {\n const next = argv[i + 1];\n if (next !== undefined && !(next.startsWith(\"-\") && next !== \"-\")) {\n options.cacheFile = next;\n i++;\n } else {\n options.cacheFile = DEFAULT_CACHE_FILE;\n }\n }\n break;\n }\n case \"--no-default-ignores\":\n rejectInlineValue();\n options.noDefaultIgnores = true;\n explicit.add(\"noDefaultIgnores\");\n break;\n case \"--scan-minified\":\n rejectInlineValue();\n options.scanMinified = true;\n explicit.add(\"scanMinified\");\n break;\n\n // `quantakrypto.config.json` FILE controls (distinct from `--no-config`, which\n // toggles config/TLS *detector* scanning above).\n case \"--config\":\n options.configFile = takeValue();\n break;\n case \"--no-config-file\":\n rejectInlineValue();\n options.noConfigFile = true;\n break;\n\n case \"--changed\":\n rejectInlineValue();\n options.changed = true;\n break;\n case \"--since\":\n options.since = takeValue();\n options.changed = true; // --since implies incremental mode\n break;\n\n case \"--parallel\":\n rejectInlineValue();\n options.parallel = true;\n break;\n case \"--concurrency\": {\n const n = asInt(takeValue(), \"--concurrency\");\n options.concurrency = n;\n // `--concurrency 0` documents \"serial\": core treats <1 as \"auto\" (full\n // parallelism), so without this special-case 0 would do the OPPOSITE of\n // what's documented. 0 forces the in-process serial path; any value >= 1\n // implies parallel.\n options.parallel = n >= 1;\n break;\n }\n\n case \"--baseline\":\n options.baseline = takeValue();\n explicit.add(\"baseline\");\n break;\n case \"--policy\":\n options.policy = takeValue();\n break;\n case \"--sign\":\n options.sign = takeValue();\n break;\n case \"--timestamp\":\n options.timestamp = takeValue();\n break;\n case \"--write-baseline\":\n options.writeBaseline = takeValue();\n break;\n case \"--quiet\":\n rejectInlineValue();\n options.quiet = true;\n break;\n case \"--color\":\n rejectInlineValue();\n options.colorChoice = \"always\";\n break;\n case \"--no-color\":\n rejectInlineValue();\n options.colorChoice = \"never\";\n break;\n case \"--no-snippets\":\n rejectInlineValue();\n options.noSnippets = true;\n break;\n case \"--hndl\":\n rejectInlineValue();\n options.hndl = true;\n break;\n\n // Crypto-agility manifest controls (see `crypto-agility emit`).\n case \"--crypto-agility\":\n rejectInlineValue();\n emitManifest = true;\n break;\n case \"--attestation\":\n options.attestation = takeValue();\n break;\n case \"--hybrid-kex\":\n rejectInlineValue();\n options.hybridKexInUse = true;\n break;\n case \"--no-hybrid-kex\":\n rejectInlineValue();\n options.hybridKexInUse = false;\n break;\n\n default:\n if (flag.startsWith(\"-\") && flag !== \"-\") {\n throw new ArgError(`unknown option \"${flag}\"`);\n }\n if (positional !== undefined) {\n throw new ArgError(\n `unexpected extra argument \"${arg}\" (path already set to \"${positional}\")`,\n );\n }\n positional = arg;\n break;\n }\n }\n\n if (positional !== undefined) options.path = positional;\n // `--crypto-agility` turns the whole run into a manifest emit, taking it off the\n // findings-threshold exit path entirely (the emit always exits 0).\n if (emitManifest) return { kind: \"crypto-agility-emit\", options };\n return { kind: \"run\", options, explicit };\n}\n\n/** Validate/normalize a `--format` value. */\nexport function asFormat(value: string): QscanFormat {\n if ((FORMATS as readonly string[]).includes(value)) return value as QscanFormat;\n throw new ArgError(`invalid --format \"${value}\" (expected one of: ${FORMATS.join(\", \")})`);\n}\n\n/** Validate/normalize a `--context` level. */\nfunction asContextLevel(value: string): ContextLevel {\n if ((CONTEXT_LEVELS as readonly string[]).includes(value)) return value as ContextLevel;\n throw new ArgError(\n `invalid --context \"${value}\" (expected one of: ${CONTEXT_LEVELS.join(\", \")})`,\n );\n}\n\n/** Validate/normalize a `--tier` value. */\nfunction asTier(value: string): SecurityTier {\n if ((SECURITY_TIERS as readonly string[]).includes(value)) return value as SecurityTier;\n throw new ArgError(`invalid --tier \"${value}\" (expected one of: ${SECURITY_TIERS.join(\", \")})`);\n}\n\n/** Validate a `--profile` value against the built-in standards regimes. */\nfunction asProfile(value: string): string {\n const ids = standardsProfileIds();\n if (ids.includes(value)) return value;\n throw new ArgError(`invalid --profile \"${value}\" (expected one of: ${ids.join(\", \")})`);\n}\n\n/** Validate/normalize a `--llm-provider` value. */\nfunction asProvider(value: string): LlmProvider {\n if ((LLM_PROVIDERS as readonly string[]).includes(value)) return value as LlmProvider;\n throw new ArgError(\n `invalid --llm-provider \"${value}\" (expected one of: ${LLM_PROVIDERS.join(\", \")})`,\n );\n}\n\n/** Validate/normalize a non-negative integer flag value. */\nexport function asInt(value: string, flag: string): number {\n if (!/^\\d+$/.test(value)) {\n throw new ArgError(`invalid ${flag} \"${value}\" (expected a non-negative integer)`);\n }\n return Number.parseInt(value, 10);\n}\n\n/** Validate/normalize a severity value. */\nexport function asSeverity(value: string): Severity {\n if ((SEVERITY_ORDER as readonly string[]).includes(value)) return value as Severity;\n throw new ArgError(`invalid severity \"${value}\" (expected one of: ${SEVERITY_ORDER.join(\", \")})`);\n}\n"]} | ||
| {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Zero-dependency command-line argument parsing for qScan.\n *\n * Hand-rolled rather than pulled from a library to keep the package free of\n * runtime dependencies. The grammar is deliberately small: long flags\n * (`--flag`, `--flag value`, `--flag=value`), a couple of short aliases\n * (`-o`, `-v`, `-h`), repeatable `--ignore`, and a single optional positional\n * path. Unknown flags are a usage error.\n */\n\nimport {\n meetsThreshold,\n SEVERITY_ORDER,\n severityRank,\n standardsProfileIds,\n} from \"@quantakrypto/core\";\nimport type { ContextLevel, ReportFormat, SecurityTier, Severity } from \"@quantakrypto/core\";\nimport type { ColorChoice } from \"./color.js\";\n\n/** Valid context levels for `--context` (how much source triage/remediate sends). */\nconst CONTEXT_LEVELS: readonly ContextLevel[] = [\"metadata\", \"snippet\", \"function\", \"file\"];\n/** Valid CNSA security tiers for `--tier` (report migration-target guidance). */\nconst SECURITY_TIERS: readonly SecurityTier[] = [\"category-3\", \"category-5\"];\n/** Valid `--llm-provider` values. */\nconst LLM_PROVIDERS = [\"anthropic\", \"openai-compatible\"] as const;\nexport type LlmProvider = (typeof LLM_PROVIDERS)[number];\n\n// Severity ordering, ranking, and threshold logic are the monorepo's single\n// source of truth in `@quantakrypto/core`. Re-export them here so existing\n// `@quantakrypto/qscan` callers (and tests) keep importing them from `./args.js`\n// without qScan maintaining a second, drift-prone copy.\nexport { meetsThreshold, SEVERITY_ORDER, severityRank };\n\n/**\n * Output formats qScan accepts on the command line. Extends core's\n * {@link ReportFormat} with `\"cbom\"` (a CycloneDX cryptographic bill of\n * materials), `\"evidence\"` (ISO A.8.24 readiness report), and `\"vex\"` (an\n * OpenVEX 0.2.0 document) — all rendered locally via core (`toCbom`,\n * `buildReadinessReport`, `toOpenVex`).\n */\nexport type QscanFormat = ReportFormat | \"cbom\" | \"evidence\" | \"vex\";\n\nconst FORMATS: readonly QscanFormat[] = [\"human\", \"json\", \"sarif\", \"cbom\", \"evidence\", \"vex\"];\n\n/** Fully-resolved options the CLI/programmatic runner operates on. */\nexport interface QscanOptions {\n /** Directory or file to scan. */\n path: string;\n /** Report format. */\n format: QscanFormat;\n /** Write the report to this file instead of stdout, when set. */\n output?: string;\n /** External CBOM files to merge into the `--cbom` output (CycloneDX bom-link). */\n mergeCboms?: string[];\n /** Findings at or above this severity cause a non-zero exit. */\n severityThreshold: Severity;\n /** Scan source files for inline crypto usage. */\n source: boolean;\n /** Scan dependency manifests for vulnerable libraries. */\n dependencies: boolean;\n /** Scan config files (TLS/certificates). */\n config: boolean;\n /** Extra exclude patterns (repeatable `--ignore`). */\n ignore: string[];\n /**\n * Restrict the walk to paths matching one of these include patterns\n * (repeatable `--include`). When empty, every non-excluded file is scanned.\n */\n include: string[];\n /** Max file size to read, in bytes (`--max-file-size`). */\n maxFileSize?: number;\n /** Disable the built-in ignore list (`--no-default-ignores`). */\n noDefaultIgnores: boolean;\n /** Compliance mandates to gate findings against (repeatable `--mandate <id>`). */\n mandates: string[];\n /** Fail early when a mandate deadline is within this many months (`--lead-months`). */\n leadMonths?: number;\n /** Fail on any mandate-prohibited finding now, ignoring the deadline (`--fail-now`). */\n failNow: boolean;\n /** Scan minified/generated/bundled files instead of skipping them. */\n scanMinified: boolean;\n /**\n * Incremental mode: scan only the files git reports as changed\n * (`--changed`), optionally relative to {@link since}.\n */\n changed: boolean;\n /** Git ref/range the `--changed` diff is taken against (`--since`). */\n since?: string;\n /** Route the scan through core's worker-thread pool (`--parallel`). */\n parallel: boolean;\n /**\n * Worker count for parallel scanning (`--concurrency`). Implies parallel.\n * A value of 0 or 1 forces the in-process serial path.\n */\n concurrency?: number;\n /** Suppress findings whose fingerprint is in this baseline file. */\n baseline?: string;\n /** Write current findings as a baseline to this file, then exit 0. */\n writeBaseline?: string;\n /** Suppress the human summary banner (still writes reports/output files). */\n quiet: boolean;\n /**\n * ANSI color policy for the human report (`--color` / `--no-color`). `\"auto\"`\n * (default) colors only a live terminal and honors `NO_COLOR` / `FORCE_COLOR`;\n * see {@link resolveColor}. Color is decoration only — never the sole signal.\n */\n colorChoice: ColorChoice;\n /** How many findings the human report lists (`--top N`). Default: 5. */\n topN?: number;\n /** Rule ids to suppress (from `quantakrypto.config.json` `disabledRules`). */\n disabledRules?: string[];\n /** Content-hash scan cache path (`--cache [path]`); reuse unchanged files. */\n cacheFile?: string;\n /** Run the BYOK LLM triage pass (`--triage`): annotate + re-sort, never suppress. */\n triage: boolean;\n /** Only triage findings at/above this seriousness (`--triage-floor`). Default: medium. */\n triageFloor?: Severity;\n /** Cap findings sent to the LLM during triage (`--max-findings`; spend guard). */\n maxFindings?: number;\n /** CNSA security tier for the migration-targets footer (`--tier`). Default: none. */\n tier?: SecurityTier;\n /**\n * Standards regime the migration guidance is tailored to (`--profile`): one of the\n * built-in ids (nist / cnsa-2.0 / bsi-tr-02102 / anssi / uk-ncsc). Default: none\n * (`--tier` maps to a profile for back-compat). Governs parameter sets, deadlines,\n * and the hybrid stance surfaced in remediation.\n */\n profile?: string;\n /** Org cryptography policy file (`--policy`) for the evidence report's §4 verdicts. */\n policy?: string;\n /**\n * External signer command for the evidence attestation (`--sign`). The report's\n * contentHash is piped to it on stdin; its stdout is recorded as the detached\n * signature. Only valid with `--format evidence`.\n */\n sign?: string;\n /** External RFC-3161 timestamper command for the evidence attestation (`--timestamp`). */\n timestamp?: string;\n /** How much source context leaves the machine (`--context`). Default: snippet. */\n contextLevel?: ContextLevel;\n /** Print the exact triage payload and exit without calling the provider (`--dry-run`). */\n dryRun: boolean;\n /** BYOK provider (`--llm-provider`). Default: anthropic. */\n llmProvider?: LlmProvider;\n /** BYOK model id (`--llm-model`). */\n llmModel?: string;\n /**\n * Omit code snippets from the JSON/SARIF report (`--no-snippets`). Passed to\n * core's reporters as `{ redactSnippets: true }`. Snippets of `sensitive`\n * findings are always omitted regardless of this flag.\n */\n noSnippets: boolean;\n /**\n * Explicit path to a `quantakrypto.config.json` (`--config <path>`). Overrides\n * auto-discovery at the scan root. Distinct from `--no-config`, which toggles\n * config/TLS *detector* scanning — this names the config FILE.\n */\n configFile?: string;\n /**\n * Disable `quantakrypto.config.json` auto-discovery (`--no-config-file`). Distinct\n * from `--no-config` (which skips config-file *detectors*).\n */\n noConfigFile: boolean;\n /**\n * Run opt-in supply-chain audit checks (`--audit`): shell out to each present\n * ecosystem's advisory tool (cargo audit / pip-audit / npm audit) for known-\n * vulnerable pinned dependencies, and verify the declared source repository\n * resolves (provenance). Findings merge into the report + exit code; a missing\n * tool or network hiccup degrades to a diagnostic, never a failure.\n */\n audit: boolean;\n /**\n * Compute + emit HNDL (harvest-now-decrypt-later) exposure (`--hndl`). Reads\n * `hndl.yml` at the scan root, scores each finding + a repo summary, and adds\n * the exposure fields to the JSON / SARIF report. Additive: never changes the\n * exit code. See docs/HNDL.md.\n */\n hndl: boolean;\n /**\n * URL to a posture credential recorded in a crypto-agility manifest\n * (`--attestation`). Only consumed by `crypto-agility emit`; recorded verbatim,\n * never fetched (offline boundary). See docs/CRYPTO-AGILITY-MANIFEST.md.\n */\n attestation?: string;\n /**\n * Operator assertion of hybrid post-quantum key exchange for a crypto-agility\n * manifest (`--hybrid-kex` → true, `--no-hybrid-kex` → false). Left undefined,\n * the manifest reports `hybridKexInUse: null` (a static scan cannot observe a\n * negotiated TLS group). Only consumed by `crypto-agility emit`.\n */\n hybridKexInUse?: boolean;\n}\n\n/**\n * Option keys that a `quantakrypto.config.json` may also set. When such a key was set\n * by a CLI flag, the flag wins (precedence: flags > config > defaults); when it\n * was left at its default, config may fill it. {@link parseArgs} records which\n * of these keys came from an explicit flag in {@link ParsedRun.explicit}.\n */\nexport type ConfigurableKey =\n | \"severityThreshold\"\n | \"source\"\n | \"dependencies\"\n | \"config\"\n | \"include\"\n | \"ignore\"\n | \"maxFileSize\"\n | \"noDefaultIgnores\"\n | \"scanMinified\"\n | \"baseline\";\n\n/** A successful parse: resolved options plus which configurable keys were explicit. */\nexport interface ParsedRun {\n kind: \"run\";\n options: QscanOptions;\n /** The set of {@link ConfigurableKey}s the user set via a flag. */\n explicit: Set<ConfigurableKey>;\n}\n\n/** The `qscan hndl init` subcommand: scaffold an `hndl.yml`. */\nexport interface ParsedHndlInit {\n kind: \"hndl-init\";\n options: QscanOptions;\n}\n\n/**\n * Emit a crypto-agility manifest: either `qscan crypto-agility emit [path]` or the\n * `--crypto-agility` flag on a normal scan. Additive: it always exits 0, never\n * consulting the severity threshold.\n */\nexport interface ParsedCryptoAgilityEmit {\n kind: \"crypto-agility-emit\";\n options: QscanOptions;\n}\n\n/** Validate a local manifest file: `qscan crypto-agility validate <file>`. */\nexport interface ParsedCryptoAgilityValidate {\n kind: \"crypto-agility-validate\";\n /** Path to the manifest JSON file to check. */\n file: string;\n}\n\n/** Result of {@link parseArgs}: either resolved options or a meta action. */\nexport type ParsedArgs =\n | ParsedRun\n | ParsedHndlInit\n | ParsedCryptoAgilityEmit\n | ParsedCryptoAgilityValidate\n | { kind: \"help\" }\n | { kind: \"version\" };\n\n/** Thrown on malformed input; the CLI maps this to exit code 2. */\nexport class ArgError extends Error {\n override readonly name = \"ArgError\";\n}\n\n/** Default options, before any flags are applied. */\nexport function defaultOptions(): QscanOptions {\n return {\n path: \".\",\n format: \"human\",\n severityThreshold: \"high\",\n source: true,\n dependencies: true,\n config: true,\n ignore: [],\n include: [],\n noDefaultIgnores: false,\n scanMinified: false,\n changed: false,\n parallel: false,\n quiet: false,\n colorChoice: \"auto\",\n noSnippets: false,\n noConfigFile: false,\n triage: false,\n dryRun: false,\n hndl: false,\n audit: false,\n mandates: [],\n failNow: false,\n };\n}\n\n/**\n * Parse a raw argv slice (i.e. without `node` and the script path).\n *\n * @throws {ArgError} On unknown flags, missing values, or invalid enum values.\n */\n/** Default scan-cache file when `--cache` is given without a path. */\nexport const DEFAULT_CACHE_FILE = \".quantakrypto-cache.json\";\n\nexport function parseArgs(argv: readonly string[]): ParsedArgs {\n // Subcommand dispatch: `qscan hndl <sub> …`. Only `init` exists today. `--help`\n // / `--version` anywhere still short-circuit to the meta actions (handled by\n // the shared loop below), so `qscan hndl init --help` shows help.\n if (argv[0] === \"hndl\") {\n const sub = argv[1];\n if (sub === undefined || sub.startsWith(\"-\")) {\n if (sub === \"--help\" || sub === \"-h\") return { kind: \"help\" };\n if (sub === \"--version\" || sub === \"-v\") return { kind: \"version\" };\n throw new ArgError(`\"hndl\" requires a subcommand (expected: init)`);\n }\n if (sub !== \"init\") {\n throw new ArgError(`unknown hndl subcommand \"${sub}\" (expected: init)`);\n }\n const parsed = parseRunArgs(argv.slice(2));\n if (parsed.kind !== \"run\") return parsed; // --help / --version passthrough\n return { kind: \"hndl-init\", options: parsed.options };\n }\n\n // Subcommand dispatch: `qscan crypto-agility <sub> …`.\n // emit [path] derive + write a manifest (always exits 0)\n // validate <file> check a local manifest against the schema\n if (argv[0] === \"crypto-agility\") {\n const sub = argv[1];\n if (sub === undefined || sub.startsWith(\"-\")) {\n if (sub === \"--help\" || sub === \"-h\") return { kind: \"help\" };\n if (sub === \"--version\" || sub === \"-v\") return { kind: \"version\" };\n throw new ArgError(`\"crypto-agility\" requires a subcommand (expected: emit, validate)`);\n }\n if (sub === \"emit\") {\n const parsed = parseRunArgs(argv.slice(2));\n // `--help`/`--version` short-circuit; a redundant `--crypto-agility` flag on\n // the emit subcommand already yields the emit kind (returned as-is).\n if (parsed.kind !== \"run\") return parsed;\n return { kind: \"crypto-agility-emit\", options: parsed.options };\n }\n if (sub === \"validate\") {\n const rest = argv.slice(2);\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) return { kind: \"help\" };\n if (rest.includes(\"--version\") || rest.includes(\"-v\")) return { kind: \"version\" };\n const positionals = rest.filter((a) => !(a.startsWith(\"-\") && a !== \"-\"));\n if (positionals.length === 0) {\n throw new ArgError(`\"crypto-agility validate\" requires a manifest file path`);\n }\n if (positionals.length > 1) {\n throw new ArgError(\n `\"crypto-agility validate\" takes exactly one file (got ${positionals.length})`,\n );\n }\n return { kind: \"crypto-agility-validate\", file: positionals[0] as string };\n }\n throw new ArgError(`unknown crypto-agility subcommand \"${sub}\" (expected: emit, validate)`);\n }\n return parseRunArgs(argv);\n}\n\n/** Parse the run-mode grammar (flags + a single optional positional path). */\nfunction parseRunArgs(argv: readonly string[]): ParsedArgs {\n const options = defaultOptions();\n const explicit = new Set<ConfigurableKey>();\n let positional: string | undefined;\n // Set by `--crypto-agility`: the whole run becomes a manifest emit (exit 0).\n let emitManifest = false;\n\n // Manual index walk so flags can consume the following token as a value.\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i] as string;\n\n // `--flag=value` → split into flag + inline value.\n let inlineValue: string | undefined;\n let flag = arg;\n if (arg.startsWith(\"--\") && arg.includes(\"=\")) {\n const eq = arg.indexOf(\"=\");\n flag = arg.slice(0, eq);\n inlineValue = arg.slice(eq + 1);\n }\n\n /** Consume a value for `flag`: prefer the inline `=value`, else the next token. */\n const takeValue = (): string => {\n if (inlineValue !== undefined) return inlineValue;\n const next = argv[i + 1];\n if (next === undefined || (next.startsWith(\"-\") && next !== \"-\")) {\n throw new ArgError(`option \"${flag}\" requires a value`);\n }\n i++;\n return next;\n };\n\n /**\n * Reject an inline `=value` on a boolean flag. Without this, `--quiet=false`\n * would silently ignore the value and turn the flag ON — the opposite of the\n * caller's intent. Boolean flags take no value, so any `=value` is an error.\n */\n const rejectInlineValue = (): void => {\n if (inlineValue !== undefined) {\n throw new ArgError(`option \"${flag}\" is a boolean flag and takes no value`);\n }\n };\n\n switch (flag) {\n case \"-h\":\n case \"--help\":\n return { kind: \"help\" };\n case \"-v\":\n case \"--version\":\n return { kind: \"version\" };\n\n case \"--format\":\n options.format = asFormat(takeValue());\n break;\n case \"--cbom\":\n rejectInlineValue();\n options.format = \"cbom\";\n break;\n case \"--merge\":\n // Merge an external CBOM (e.g. a qprobe endpoint CBOM) into the --cbom\n // output via CycloneDX bom-link. Repeatable.\n (options.mergeCboms ??= []).push(takeValue());\n break;\n case \"-o\":\n case \"--output\":\n options.output = takeValue();\n break;\n case \"--severity-threshold\":\n options.severityThreshold = asSeverity(takeValue());\n explicit.add(\"severityThreshold\");\n break;\n\n case \"--no-source\":\n rejectInlineValue();\n options.source = false;\n explicit.add(\"source\");\n break;\n case \"--no-deps\":\n rejectInlineValue();\n options.dependencies = false;\n explicit.add(\"dependencies\");\n break;\n case \"--no-config\":\n rejectInlineValue();\n options.config = false;\n explicit.add(\"config\");\n break;\n\n case \"--ignore\":\n options.ignore.push(takeValue());\n explicit.add(\"ignore\");\n break;\n case \"--include\":\n options.include.push(takeValue());\n explicit.add(\"include\");\n break;\n case \"--max-file-size\":\n options.maxFileSize = asInt(takeValue(), \"--max-file-size\");\n explicit.add(\"maxFileSize\");\n break;\n case \"--top\":\n options.topN = asInt(takeValue(), \"--top\");\n break;\n case \"--triage\":\n rejectInlineValue();\n options.triage = true;\n break;\n case \"--triage-floor\":\n options.triageFloor = asSeverity(takeValue());\n break;\n case \"--max-findings\":\n options.maxFindings = asInt(takeValue(), \"--max-findings\");\n break;\n case \"--tier\":\n options.tier = asTier(takeValue());\n break;\n case \"--profile\":\n options.profile = asProfile(takeValue());\n break;\n case \"--mandate\":\n options.mandates.push(takeValue());\n break;\n case \"--lead-months\":\n options.leadMonths = asInt(takeValue(), \"--lead-months\");\n break;\n case \"--fail-now\":\n rejectInlineValue();\n options.failNow = true;\n break;\n case \"--context\":\n options.contextLevel = asContextLevel(takeValue());\n break;\n case \"--dry-run\":\n rejectInlineValue();\n options.dryRun = true;\n break;\n case \"--llm-provider\":\n options.llmProvider = asProvider(takeValue());\n break;\n case \"--llm-model\":\n options.llmModel = takeValue();\n break;\n case \"--cache\": {\n // `--cache` alone uses the default file; `--cache <path>` names it.\n if (inlineValue !== undefined) {\n options.cacheFile = inlineValue;\n } else {\n const next = argv[i + 1];\n if (next !== undefined && !(next.startsWith(\"-\") && next !== \"-\")) {\n options.cacheFile = next;\n i++;\n } else {\n options.cacheFile = DEFAULT_CACHE_FILE;\n }\n }\n break;\n }\n case \"--no-default-ignores\":\n rejectInlineValue();\n options.noDefaultIgnores = true;\n explicit.add(\"noDefaultIgnores\");\n break;\n case \"--scan-minified\":\n rejectInlineValue();\n options.scanMinified = true;\n explicit.add(\"scanMinified\");\n break;\n\n // `quantakrypto.config.json` FILE controls (distinct from `--no-config`, which\n // toggles config/TLS *detector* scanning above).\n case \"--config\":\n options.configFile = takeValue();\n break;\n case \"--no-config-file\":\n rejectInlineValue();\n options.noConfigFile = true;\n break;\n\n case \"--changed\":\n rejectInlineValue();\n options.changed = true;\n break;\n case \"--since\":\n options.since = takeValue();\n options.changed = true; // --since implies incremental mode\n break;\n\n case \"--parallel\":\n rejectInlineValue();\n options.parallel = true;\n break;\n case \"--concurrency\": {\n const n = asInt(takeValue(), \"--concurrency\");\n options.concurrency = n;\n // `--concurrency 0` documents \"serial\": core treats <1 as \"auto\" (full\n // parallelism), so without this special-case 0 would do the OPPOSITE of\n // what's documented. 0 forces the in-process serial path; any value >= 1\n // implies parallel.\n options.parallel = n >= 1;\n break;\n }\n\n case \"--baseline\":\n options.baseline = takeValue();\n explicit.add(\"baseline\");\n break;\n case \"--policy\":\n options.policy = takeValue();\n break;\n case \"--sign\":\n options.sign = takeValue();\n break;\n case \"--timestamp\":\n options.timestamp = takeValue();\n break;\n case \"--write-baseline\":\n options.writeBaseline = takeValue();\n break;\n case \"--quiet\":\n rejectInlineValue();\n options.quiet = true;\n break;\n case \"--color\":\n rejectInlineValue();\n options.colorChoice = \"always\";\n break;\n case \"--no-color\":\n rejectInlineValue();\n options.colorChoice = \"never\";\n break;\n case \"--no-snippets\":\n rejectInlineValue();\n options.noSnippets = true;\n break;\n case \"--hndl\":\n rejectInlineValue();\n options.hndl = true;\n break;\n case \"--audit\":\n rejectInlineValue();\n options.audit = true;\n break;\n\n // Crypto-agility manifest controls (see `crypto-agility emit`).\n case \"--crypto-agility\":\n rejectInlineValue();\n emitManifest = true;\n break;\n case \"--attestation\":\n options.attestation = takeValue();\n break;\n case \"--hybrid-kex\":\n rejectInlineValue();\n options.hybridKexInUse = true;\n break;\n case \"--no-hybrid-kex\":\n rejectInlineValue();\n options.hybridKexInUse = false;\n break;\n\n default:\n if (flag.startsWith(\"-\") && flag !== \"-\") {\n throw new ArgError(`unknown option \"${flag}\"`);\n }\n if (positional !== undefined) {\n throw new ArgError(\n `unexpected extra argument \"${arg}\" (path already set to \"${positional}\")`,\n );\n }\n positional = arg;\n break;\n }\n }\n\n if (positional !== undefined) options.path = positional;\n // `--crypto-agility` turns the whole run into a manifest emit, taking it off the\n // findings-threshold exit path entirely (the emit always exits 0).\n if (emitManifest) return { kind: \"crypto-agility-emit\", options };\n return { kind: \"run\", options, explicit };\n}\n\n/** Validate/normalize a `--format` value. */\nexport function asFormat(value: string): QscanFormat {\n if ((FORMATS as readonly string[]).includes(value)) return value as QscanFormat;\n throw new ArgError(`invalid --format \"${value}\" (expected one of: ${FORMATS.join(\", \")})`);\n}\n\n/** Validate/normalize a `--context` level. */\nfunction asContextLevel(value: string): ContextLevel {\n if ((CONTEXT_LEVELS as readonly string[]).includes(value)) return value as ContextLevel;\n throw new ArgError(\n `invalid --context \"${value}\" (expected one of: ${CONTEXT_LEVELS.join(\", \")})`,\n );\n}\n\n/** Validate/normalize a `--tier` value. */\nfunction asTier(value: string): SecurityTier {\n if ((SECURITY_TIERS as readonly string[]).includes(value)) return value as SecurityTier;\n throw new ArgError(`invalid --tier \"${value}\" (expected one of: ${SECURITY_TIERS.join(\", \")})`);\n}\n\n/** Validate a `--profile` value against the built-in standards regimes. */\nfunction asProfile(value: string): string {\n const ids = standardsProfileIds();\n if (ids.includes(value)) return value;\n throw new ArgError(`invalid --profile \"${value}\" (expected one of: ${ids.join(\", \")})`);\n}\n\n/** Validate/normalize a `--llm-provider` value. */\nfunction asProvider(value: string): LlmProvider {\n if ((LLM_PROVIDERS as readonly string[]).includes(value)) return value as LlmProvider;\n throw new ArgError(\n `invalid --llm-provider \"${value}\" (expected one of: ${LLM_PROVIDERS.join(\", \")})`,\n );\n}\n\n/** Validate/normalize a non-negative integer flag value. */\nexport function asInt(value: string, flag: string): number {\n if (!/^\\d+$/.test(value)) {\n throw new ArgError(`invalid ${flag} \"${value}\" (expected a non-negative integer)`);\n }\n return Number.parseInt(value, 10);\n}\n\n/** Validate/normalize a severity value. */\nexport function asSeverity(value: string): Severity {\n if ((SEVERITY_ORDER as readonly string[]).includes(value)) return value as Severity;\n throw new ArgError(`invalid severity \"${value}\" (expected one of: ${SEVERITY_ORDER.join(\", \")})`);\n}\n"]} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAuBH,2EAA2E;AAC3E,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmMnE"} | ||
| {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAuBH,2EAA2E;AAC3E,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAyMnE"} |
+5
-0
@@ -204,2 +204,7 @@ #!/usr/bin/env node | ||
| } | ||
| if (!options.quiet && run.auditDiagnostics) { | ||
| for (const d of run.auditDiagnostics) { | ||
| process.stderr.write(`qscan: audit: ${d}\n`); | ||
| } | ||
| } | ||
| return run.exitCode; | ||
@@ -206,0 +211,0 @@ } |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * qScan command-line entry point.\n *\n * Thin shell over the programmatic API in `./index.ts`:\n * parse argv → runQscan → print/write report → process.exit(code).\n *\n * All policy (scanning, baseline, thresholds, rendering) lives in `index.ts`;\n * this file only deals with argv, stdout/stderr, files, and exit codes.\n */\n\nimport { realpathSync } from \"node:fs\";\nimport { writeFile } from \"node:fs/promises\";\nimport process from \"node:process\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { ConfigError } from \"@quantakrypto/core\";\n\nimport { ArgError, parseArgs } from \"./args.js\";\nimport type { ParsedArgs, QscanOptions } from \"./args.js\";\nimport { resolveColor } from \"./color.js\";\nimport { resolveConfig } from \"./config.js\";\nimport { HELP_TEXT, versionLine } from \"./help.js\";\nimport {\n EXIT,\n runCryptoAgilityEmit,\n runCryptoAgilityValidate,\n runHndlInit,\n runQscan,\n} from \"./index.js\";\nimport type { QscanRun } from \"./index.js\";\n\n/** Run the CLI and return the desired process exit code (never throws). */\nexport async function main(argv: readonly string[]): Promise<number> {\n let parsed: ParsedArgs;\n try {\n parsed = parseArgs(argv);\n } catch (err) {\n if (err instanceof ArgError) {\n process.stderr.write(`qscan: ${err.message}\\n`);\n process.stderr.write(`Run \"qscan --help\" for usage.\\n`);\n return EXIT.ERROR;\n }\n throw err;\n }\n\n if (parsed.kind === \"help\") {\n process.stdout.write(HELP_TEXT);\n return EXIT.OK;\n }\n if (parsed.kind === \"version\") {\n process.stdout.write(`${versionLine()}\\n`);\n return EXIT.OK;\n }\n\n // `qscan hndl init`: scaffold an hndl.yml from a seeding scan. Refuses to\n // overwrite an existing file.\n if (parsed.kind === \"hndl-init\") {\n try {\n const init = await runHndlInit(parsed.options);\n if (init.exists) {\n process.stderr.write(\n `qscan: ${init.path} already exists; refusing to overwrite. Edit it, or remove it and re-run.\\n`,\n );\n return EXIT.ERROR;\n }\n await writeFile(init.path, init.content, \"utf8\");\n process.stderr.write(\n `qscan: wrote ${init.path} (seeded from ${init.seededFindings} data-adjacent finding(s) of ${init.findingsScanned} scanned).\\n`,\n );\n process.stderr.write(\n `qscan: review the assets, then run \"qscan ${parsed.options.path} --hndl\" for exposure scores.\\n`,\n );\n return EXIT.OK;\n } catch (err) {\n if (isErrno(err) && err.code === \"ENOENT\") {\n process.stderr.write(`qscan: path not found: ${parsed.options.path}\\n`);\n return EXIT.ERROR;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n }\n\n // `qscan crypto-agility emit` / `--crypto-agility`: derive a posture manifest and\n // write it to stdout (or `--output`). Additive: always exits 0, never consulting\n // the severity threshold.\n if (parsed.kind === \"crypto-agility-emit\") {\n try {\n const { manifest } = await runCryptoAgilityEmit(parsed.options);\n const out = manifest.endsWith(\"\\n\") ? manifest : `${manifest}\\n`;\n if (parsed.options.output) {\n await writeFile(parsed.options.output, out, \"utf8\");\n if (!parsed.options.quiet) {\n process.stderr.write(\n `qscan: wrote crypto-agility manifest to ${parsed.options.output}\\n`,\n );\n }\n } else {\n await writeStdout(out);\n }\n return EXIT.OK;\n } catch (err) {\n if (isErrno(err) && err.code === \"ENOENT\") {\n const missing = typeof err.path === \"string\" && err.path ? err.path : parsed.options.path;\n process.stderr.write(`qscan: path not found: ${missing}\\n`);\n return EXIT.ERROR;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n }\n\n // `qscan crypto-agility validate <file>`: check a LOCAL manifest against the\n // schema. Exit 0 when valid, 1 when the manifest is invalid, 2 on an I/O error.\n if (parsed.kind === \"crypto-agility-validate\") {\n let validation;\n try {\n validation = await runCryptoAgilityValidate(parsed.file);\n } catch (err) {\n if (isErrno(err) && err.code === \"ENOENT\") {\n process.stderr.write(`qscan: path not found: ${parsed.file}\\n`);\n return EXIT.ERROR;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n if (validation.valid) {\n process.stdout.write(`qscan: ${parsed.file} is a valid crypto-agility manifest\\n`);\n return EXIT.OK;\n }\n process.stderr.write(`qscan: ${parsed.file} is not a valid crypto-agility manifest:\\n`);\n for (const e of validation.errors) {\n process.stderr.write(` - ${e}\\n`);\n }\n return EXIT.FINDINGS;\n }\n\n // Resolve `quantakrypto.config.json` (flags > config > defaults) before scanning.\n let options: QscanOptions;\n try {\n const resolved = await resolveConfig(parsed.options, parsed.explicit);\n options = resolved.options;\n if (!options.quiet) {\n for (const w of resolved.warnings) {\n process.stderr.write(`qscan: config warning: ${w}\\n`);\n }\n if (resolved.configPath) {\n process.stderr.write(`qscan: using config ${resolved.configPath}\\n`);\n }\n }\n } catch (err) {\n if (err instanceof ConfigError) {\n process.stderr.write(`qscan: ${err.message}\\n`);\n return EXIT.ERROR;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n\n // Color policy: --color/--no-color > NO_COLOR/FORCE_COLOR > interactive stdout.\n // Color is decoration only (every signal is also text), so this is purely an\n // accessibility / pipe-safety control. See resolveColor for the precedence.\n const color = resolveColor({\n choice: options.colorChoice,\n format: options.format,\n toFile: Boolean(options.output),\n isTTY: Boolean(process.stdout.isTTY),\n env: { NO_COLOR: process.env.NO_COLOR, FORCE_COLOR: process.env.FORCE_COLOR },\n });\n\n let run: QscanRun;\n try {\n run = await runQscan(options, { color });\n } catch (err) {\n // A missing file is the most common failure; a raw \"ENOENT: no such file or\n // directory, stat '…'\" reads like a tool bug. Turn it into a plain, actionable\n // line (still exit 2). Report the ACTUAL missing path from `err.path` when present\n // — an ENOENT can come from `--policy`, `--baseline`, or `--write-baseline`, not\n // just the scan path, and blaming the (existing) scan path misdirects the user.\n if (isErrno(err) && err.code === \"ENOENT\") {\n const missing = typeof err.path === \"string\" && err.path ? err.path : options.path;\n process.stderr.write(`qscan: path not found: ${missing}\\n`);\n return EXIT.ERROR;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n\n // --write-baseline: report what was written and stop.\n if (run.baselineWritten) {\n if (!options.quiet) {\n const n = run.baselineWritten.fingerprints.length;\n process.stderr.write(\n `qscan: wrote baseline with ${n} fingerprint${n === 1 ? \"\" : \"s\"} to ${options.writeBaseline}\\n`,\n );\n }\n return run.exitCode;\n }\n\n const report = run.report ?? \"\";\n try {\n if (options.output) {\n await writeFile(options.output, report.endsWith(\"\\n\") ? report : `${report}\\n`, \"utf8\");\n if (!options.quiet) {\n process.stderr.write(`qscan: wrote ${options.format} report to ${options.output}\\n`);\n }\n } else if (!options.quiet || options.format !== \"human\") {\n // In quiet mode we still emit machine formats to stdout (the point of a\n // pipe), but suppress the human banner.\n await writeStdout(report.endsWith(\"\\n\") ? report : `${report}\\n`);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n\n if (!options.quiet && run.suppressed.length > 0) {\n process.stderr.write(`qscan: suppressed ${run.suppressed.length} finding(s) via baseline\\n`);\n }\n\n return run.exitCode;\n}\n\n/** True for Node system errors (fs/os), which carry a string `code` like `ENOENT`. */\nfunction isErrno(err: unknown): err is NodeJS.ErrnoException {\n return err instanceof Error && typeof (err as NodeJS.ErrnoException).code === \"string\";\n}\n\n/**\n * Write to stdout, awaiting `drain` when the kernel buffer is full.\n *\n * `process.stdout.write` returns `false` when the OS buffer can't accept the\n * whole chunk (typical for large reports down a pipe or file redirect). If the\n * process then exits before the buffer flushes, the tail of the report is lost.\n * When the write is not fully flushed we wait for the `drain` event, so the\n * bytes are handed to the OS before we return and the report is never\n * truncated, regardless of how the caller exits. A fully-flushed write (the\n * common case, and a TTY) resolves synchronously on the next microtask.\n */\nfunction writeStdout(chunk: string): Promise<void> {\n const flushed = process.stdout.write(chunk);\n if (flushed) return Promise.resolve();\n return new Promise((resolve) => process.stdout.once(\"drain\", resolve));\n}\n\n/**\n * True when this module is the program's entry point. Resolves symlinks so the\n * check also holds when launched via the `qscan` bin shim in node_modules/.bin\n * (npm symlinks it) or through /tmp -> /private/tmp on macOS — otherwise\n * `npx @quantakrypto/qscan` (and `npm i -g`) would be a silent no-op.\n */\nfunction isMainModule(): boolean {\n const argv1 = process.argv[1];\n if (argv1 === undefined) return false;\n const thisPath = fileURLToPath(import.meta.url);\n try {\n return realpathSync(argv1) === realpathSync(thisPath);\n } catch {\n return argv1 === thisPath;\n }\n}\n\n// Only auto-run when invoked as a script (not when imported by a test).\nconst invokedDirectly = isMainModule();\n\nif (invokedDirectly) {\n main(process.argv.slice(2))\n .then((code) => {\n // Set the exit code and return WITHOUT calling process.exit(): a bare\n // process.exit() tears down the event loop before stdout's async buffer\n // drains, truncating large SARIF/JSON reports written to a pipe or file\n // redirect. Letting the loop empty naturally lets the buffer flush first.\n process.exitCode = code;\n })\n .catch((err) => {\n const message = err instanceof Error ? (err.stack ?? err.message) : String(err);\n process.stderr.write(`qscan: fatal: ${message}\\n`);\n process.exitCode = EXIT.ERROR;\n });\n}\n"]} | ||
| {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * qScan command-line entry point.\n *\n * Thin shell over the programmatic API in `./index.ts`:\n * parse argv → runQscan → print/write report → process.exit(code).\n *\n * All policy (scanning, baseline, thresholds, rendering) lives in `index.ts`;\n * this file only deals with argv, stdout/stderr, files, and exit codes.\n */\n\nimport { realpathSync } from \"node:fs\";\nimport { writeFile } from \"node:fs/promises\";\nimport process from \"node:process\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { ConfigError } from \"@quantakrypto/core\";\n\nimport { ArgError, parseArgs } from \"./args.js\";\nimport type { ParsedArgs, QscanOptions } from \"./args.js\";\nimport { resolveColor } from \"./color.js\";\nimport { resolveConfig } from \"./config.js\";\nimport { HELP_TEXT, versionLine } from \"./help.js\";\nimport {\n EXIT,\n runCryptoAgilityEmit,\n runCryptoAgilityValidate,\n runHndlInit,\n runQscan,\n} from \"./index.js\";\nimport type { QscanRun } from \"./index.js\";\n\n/** Run the CLI and return the desired process exit code (never throws). */\nexport async function main(argv: readonly string[]): Promise<number> {\n let parsed: ParsedArgs;\n try {\n parsed = parseArgs(argv);\n } catch (err) {\n if (err instanceof ArgError) {\n process.stderr.write(`qscan: ${err.message}\\n`);\n process.stderr.write(`Run \"qscan --help\" for usage.\\n`);\n return EXIT.ERROR;\n }\n throw err;\n }\n\n if (parsed.kind === \"help\") {\n process.stdout.write(HELP_TEXT);\n return EXIT.OK;\n }\n if (parsed.kind === \"version\") {\n process.stdout.write(`${versionLine()}\\n`);\n return EXIT.OK;\n }\n\n // `qscan hndl init`: scaffold an hndl.yml from a seeding scan. Refuses to\n // overwrite an existing file.\n if (parsed.kind === \"hndl-init\") {\n try {\n const init = await runHndlInit(parsed.options);\n if (init.exists) {\n process.stderr.write(\n `qscan: ${init.path} already exists; refusing to overwrite. Edit it, or remove it and re-run.\\n`,\n );\n return EXIT.ERROR;\n }\n await writeFile(init.path, init.content, \"utf8\");\n process.stderr.write(\n `qscan: wrote ${init.path} (seeded from ${init.seededFindings} data-adjacent finding(s) of ${init.findingsScanned} scanned).\\n`,\n );\n process.stderr.write(\n `qscan: review the assets, then run \"qscan ${parsed.options.path} --hndl\" for exposure scores.\\n`,\n );\n return EXIT.OK;\n } catch (err) {\n if (isErrno(err) && err.code === \"ENOENT\") {\n process.stderr.write(`qscan: path not found: ${parsed.options.path}\\n`);\n return EXIT.ERROR;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n }\n\n // `qscan crypto-agility emit` / `--crypto-agility`: derive a posture manifest and\n // write it to stdout (or `--output`). Additive: always exits 0, never consulting\n // the severity threshold.\n if (parsed.kind === \"crypto-agility-emit\") {\n try {\n const { manifest } = await runCryptoAgilityEmit(parsed.options);\n const out = manifest.endsWith(\"\\n\") ? manifest : `${manifest}\\n`;\n if (parsed.options.output) {\n await writeFile(parsed.options.output, out, \"utf8\");\n if (!parsed.options.quiet) {\n process.stderr.write(\n `qscan: wrote crypto-agility manifest to ${parsed.options.output}\\n`,\n );\n }\n } else {\n await writeStdout(out);\n }\n return EXIT.OK;\n } catch (err) {\n if (isErrno(err) && err.code === \"ENOENT\") {\n const missing = typeof err.path === \"string\" && err.path ? err.path : parsed.options.path;\n process.stderr.write(`qscan: path not found: ${missing}\\n`);\n return EXIT.ERROR;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n }\n\n // `qscan crypto-agility validate <file>`: check a LOCAL manifest against the\n // schema. Exit 0 when valid, 1 when the manifest is invalid, 2 on an I/O error.\n if (parsed.kind === \"crypto-agility-validate\") {\n let validation;\n try {\n validation = await runCryptoAgilityValidate(parsed.file);\n } catch (err) {\n if (isErrno(err) && err.code === \"ENOENT\") {\n process.stderr.write(`qscan: path not found: ${parsed.file}\\n`);\n return EXIT.ERROR;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n if (validation.valid) {\n process.stdout.write(`qscan: ${parsed.file} is a valid crypto-agility manifest\\n`);\n return EXIT.OK;\n }\n process.stderr.write(`qscan: ${parsed.file} is not a valid crypto-agility manifest:\\n`);\n for (const e of validation.errors) {\n process.stderr.write(` - ${e}\\n`);\n }\n return EXIT.FINDINGS;\n }\n\n // Resolve `quantakrypto.config.json` (flags > config > defaults) before scanning.\n let options: QscanOptions;\n try {\n const resolved = await resolveConfig(parsed.options, parsed.explicit);\n options = resolved.options;\n if (!options.quiet) {\n for (const w of resolved.warnings) {\n process.stderr.write(`qscan: config warning: ${w}\\n`);\n }\n if (resolved.configPath) {\n process.stderr.write(`qscan: using config ${resolved.configPath}\\n`);\n }\n }\n } catch (err) {\n if (err instanceof ConfigError) {\n process.stderr.write(`qscan: ${err.message}\\n`);\n return EXIT.ERROR;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n\n // Color policy: --color/--no-color > NO_COLOR/FORCE_COLOR > interactive stdout.\n // Color is decoration only (every signal is also text), so this is purely an\n // accessibility / pipe-safety control. See resolveColor for the precedence.\n const color = resolveColor({\n choice: options.colorChoice,\n format: options.format,\n toFile: Boolean(options.output),\n isTTY: Boolean(process.stdout.isTTY),\n env: { NO_COLOR: process.env.NO_COLOR, FORCE_COLOR: process.env.FORCE_COLOR },\n });\n\n let run: QscanRun;\n try {\n run = await runQscan(options, { color });\n } catch (err) {\n // A missing file is the most common failure; a raw \"ENOENT: no such file or\n // directory, stat '…'\" reads like a tool bug. Turn it into a plain, actionable\n // line (still exit 2). Report the ACTUAL missing path from `err.path` when present\n // — an ENOENT can come from `--policy`, `--baseline`, or `--write-baseline`, not\n // just the scan path, and blaming the (existing) scan path misdirects the user.\n if (isErrno(err) && err.code === \"ENOENT\") {\n const missing = typeof err.path === \"string\" && err.path ? err.path : options.path;\n process.stderr.write(`qscan: path not found: ${missing}\\n`);\n return EXIT.ERROR;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n\n // --write-baseline: report what was written and stop.\n if (run.baselineWritten) {\n if (!options.quiet) {\n const n = run.baselineWritten.fingerprints.length;\n process.stderr.write(\n `qscan: wrote baseline with ${n} fingerprint${n === 1 ? \"\" : \"s\"} to ${options.writeBaseline}\\n`,\n );\n }\n return run.exitCode;\n }\n\n const report = run.report ?? \"\";\n try {\n if (options.output) {\n await writeFile(options.output, report.endsWith(\"\\n\") ? report : `${report}\\n`, \"utf8\");\n if (!options.quiet) {\n process.stderr.write(`qscan: wrote ${options.format} report to ${options.output}\\n`);\n }\n } else if (!options.quiet || options.format !== \"human\") {\n // In quiet mode we still emit machine formats to stdout (the point of a\n // pipe), but suppress the human banner.\n await writeStdout(report.endsWith(\"\\n\") ? report : `${report}\\n`);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`qscan: ${message}\\n`);\n return EXIT.ERROR;\n }\n\n if (!options.quiet && run.suppressed.length > 0) {\n process.stderr.write(`qscan: suppressed ${run.suppressed.length} finding(s) via baseline\\n`);\n }\n\n if (!options.quiet && run.auditDiagnostics) {\n for (const d of run.auditDiagnostics) {\n process.stderr.write(`qscan: audit: ${d}\\n`);\n }\n }\n\n return run.exitCode;\n}\n\n/** True for Node system errors (fs/os), which carry a string `code` like `ENOENT`. */\nfunction isErrno(err: unknown): err is NodeJS.ErrnoException {\n return err instanceof Error && typeof (err as NodeJS.ErrnoException).code === \"string\";\n}\n\n/**\n * Write to stdout, awaiting `drain` when the kernel buffer is full.\n *\n * `process.stdout.write` returns `false` when the OS buffer can't accept the\n * whole chunk (typical for large reports down a pipe or file redirect). If the\n * process then exits before the buffer flushes, the tail of the report is lost.\n * When the write is not fully flushed we wait for the `drain` event, so the\n * bytes are handed to the OS before we return and the report is never\n * truncated, regardless of how the caller exits. A fully-flushed write (the\n * common case, and a TTY) resolves synchronously on the next microtask.\n */\nfunction writeStdout(chunk: string): Promise<void> {\n const flushed = process.stdout.write(chunk);\n if (flushed) return Promise.resolve();\n return new Promise((resolve) => process.stdout.once(\"drain\", resolve));\n}\n\n/**\n * True when this module is the program's entry point. Resolves symlinks so the\n * check also holds when launched via the `qscan` bin shim in node_modules/.bin\n * (npm symlinks it) or through /tmp -> /private/tmp on macOS — otherwise\n * `npx @quantakrypto/qscan` (and `npm i -g`) would be a silent no-op.\n */\nfunction isMainModule(): boolean {\n const argv1 = process.argv[1];\n if (argv1 === undefined) return false;\n const thisPath = fileURLToPath(import.meta.url);\n try {\n return realpathSync(argv1) === realpathSync(thisPath);\n } catch {\n return argv1 === thisPath;\n }\n}\n\n// Only auto-run when invoked as a script (not when imported by a test).\nconst invokedDirectly = isMainModule();\n\nif (invokedDirectly) {\n main(process.argv.slice(2))\n .then((code) => {\n // Set the exit code and return WITHOUT calling process.exit(): a bare\n // process.exit() tears down the event loop before stdout's async buffer\n // drains, truncating large SARIF/JSON reports written to a pipe or file\n // redirect. Letting the loop empty naturally lets the buffer flush first.\n process.exitCode = code;\n })\n .catch((err) => {\n const message = err instanceof Error ? (err.stack ?? err.message) : String(err);\n process.stderr.write(`qscan: fatal: ${message}\\n`);\n process.exitCode = EXIT.ERROR;\n });\n}\n"]} |
+1
-1
@@ -8,5 +8,5 @@ /** | ||
| /** The full `--help` screen. */ | ||
| export declare const HELP_TEXT = "qscan \u2014 find quantum-vulnerable cryptography in any codebase\n\nUSAGE\n qscan [path] [options]\n qscan hndl init [path] Scaffold an hndl.yml data map (see --hndl)\n qscan crypto-agility emit [path] Write a crypto-agility manifest (exits 0)\n qscan crypto-agility validate <file> Check a local manifest against the schema\n\nARGUMENTS\n path Directory or file to scan (default: \".\")\n\nOPTIONS\n --format <human|json|sarif|cbom|evidence|vex>\n Output format (default: human)\n --cbom Alias for --format cbom (CycloneDX CBOM)\n --format vex OpenVEX 0.2.0 document \u2014 one statement per rule,\n status \"affected\", with remediation + any\n --triage verdict for supply-chain VEX pipelines\n --merge <cbom.json> Merge an external CBOM (e.g. a qprobe endpoint\n CBOM) into the --cbom output via CycloneDX\n bom-link \u2014 one combined code + infra CBOM.\n Repeatable.\n --format evidence ISO 27001 A.8.24 readiness report \u2014 findings +\n inventory + CBOM + a deterministic content hash\n (sign/timestamp it with an external signer)\n --policy <file> Crypto-policy JSON; adds conformant/violation/\n transition verdicts to the evidence report\n --sign <command> Sign the evidence report: its contentHash is\n piped to <command> on stdin; stdout is recorded\n as the detached signature (needs --format evidence)\n --timestamp <command> Like --sign, but records an RFC-3161 timestamp\n token from <command> (needs --format evidence)\n -o, --output <file> Write the report to a file instead of stdout\n --severity-threshold <level> Fail (exit 1) on findings at/above this level;\n one of critical|high|medium|low|info\n (default: high)\n --no-source Skip scanning source files for inline crypto\n --no-deps Skip scanning dependency manifests\n --no-config Skip scanning config files (TLS/certificates)\n --config <path> Use this quantakrypto.config.json instead of\n auto-discovering one at the scan root\n --no-config-file Disable quantakrypto.config.json auto-discovery\n --ignore <pattern> Exclude paths matching <pattern> (repeatable)\n --include <pattern> Restrict the scan to matching paths (repeatable)\n --max-file-size <bytes> Skip files larger than <bytes> (default: 2 MiB)\n --no-default-ignores Don't skip node_modules/.git/dist by default\n --scan-minified Scan minified/generated/bundled files too\n --changed Scan only files changed in the git work tree\n --since <git-ref> With --changed, diff against <git-ref>\n --parallel Scan using a worker-thread pool when worthwhile\n --concurrency <n> Worker count for --parallel (implies --parallel);\n 0 forces the in-process serial path\n --top <n> List <n> findings in the human report (default: 5)\n --tier <category-3|category-5> Add CNSA migration targets to the report footer\n (category-5 = CNSA 2.0: ML-KEM-1024 / ML-DSA-87;\n an alias for --profile cnsa-2.0)\n --profile <id> Tailor migration guidance to a standards regime:\n nist (default) | cnsa-2.0 | bsi-tr-02102 | anssi |\n uk-ncsc. Sets the parameter sets, deadlines, and\n whether hybridization is required/recommended/optional\n --mandate <id> Gate findings against a compliance mandate's dated\n clauses (repeatable): cnsa-2.0 | nist-ir-8547. Reports\n each prohibited finding with its clause + deadline;\n fails the build only once a deadline has passed\n --lead-months <n> Fail early when a --mandate deadline is within n months\n --fail-now Fail on any --mandate-prohibited finding, ignoring the date\n --cache [file] Reuse findings for unchanged files across runs\n (default file: .quantakrypto-cache.json)\n --triage BYOK LLM pass that re-ranks findings by real\n exposure and explains them (never suppresses,\n never changes the exit code). Needs an API key in\n QK_LLM_API_KEY / ANTHROPIC_API_KEY / OPENAI_API_KEY\n --triage-floor <level> Only triage findings at/above this level (default: medium)\n --max-findings <n> Cap findings sent to the LLM during triage (default: 100; spend guard)\n --context <level> Source shared with the LLM: metadata|snippet|\n function|file (default: snippet; secrets always redacted)\n --dry-run With --triage, print the exact payload that would\n be sent and exit without calling the provider\n --llm-provider <name> anthropic | openai-compatible (default: anthropic)\n --llm-model <id> Model id for the BYOK provider\n --hndl Score harvest-now-decrypt-later exposure per\n finding + a repo summary from hndl.yml (data\n assets, classification, retention + secrecy\n lifetime vs the quantum-threat horizon; Mosca's\n inequality). Adds exposure fields to json/sarif;\n additive, never changes the exit code. Scaffold\n the map with \"qscan hndl init\". See docs/HNDL.md\n --crypto-agility Emit a crypto-agility posture manifest instead of a\n scan report (equivalent to \"crypto-agility emit\";\n always exits 0). A well-known-URL JSON document any\n agent/CI bot can read like security.txt: readiness\n score, quantum-vulnerable findings by severity, CBOM\n algorithm families, policy deadlines. Combine with\n --attestation / --hybrid-kex / --policy / -o.\n See docs/CRYPTO-AGILITY-MANIFEST.md\n --attestation <url> Record a posture-credential URL in the manifest\n (recorded verbatim, never fetched; offline boundary)\n --hybrid-kex / --no-hybrid-kex\n Assert hybrid post-quantum key exchange is / is not\n in use in the manifest (default: null / undetermined,\n since a static scan can't observe a negotiated group)\n --baseline <file> Suppress findings listed in a baseline file\n --write-baseline <file> Write current findings as a baseline, then exit 0\n --quiet Suppress the human summary banner\n --no-snippets Omit code snippets from the json/sarif report\n --color Force ANSI color in the human report\n --no-color Disable ANSI color (also: NO_COLOR env). Color is\n decoration only \u2014 every signal is printed as text\n -v, --version Print version and exit\n -h, --help Print this help and exit\n\nEXIT CODES\n 0 No findings at/above the threshold (or a baseline was written)\n 1 One or more findings at/above the severity threshold\n 2 Usage error or I/O failure\n\nEXAMPLES\n qscan . Scan the current directory\n qscan src --format sarif -o qscan.sarif\n qscan . --severity-threshold critical\n qscan . --write-baseline qscan-baseline.json\n qscan . --baseline qscan-baseline.json\n qscan . --include src --include lib\n qscan . --config ./ci/quantakrypto.config.json\n qscan . --changed --since origin/main\n qscan . --parallel --concurrency 4\n qscan . --cbom -o qscan-cbom.json\n qscan hndl init Scaffold hndl.yml seeded with detected assets\n qscan . --hndl --format json Emit per-finding HNDL exposure + a repo summary\n qscan . --crypto-agility -o .well-known/crypto-agility.json\n qscan crypto-agility validate .well-known/crypto-agility.json\n"; | ||
| export declare const HELP_TEXT = "qscan \u2014 find quantum-vulnerable cryptography in any codebase\n\nUSAGE\n qscan [path] [options]\n qscan hndl init [path] Scaffold an hndl.yml data map (see --hndl)\n qscan crypto-agility emit [path] Write a crypto-agility manifest (exits 0)\n qscan crypto-agility validate <file> Check a local manifest against the schema\n\nARGUMENTS\n path Directory or file to scan (default: \".\")\n\nOPTIONS\n --format <human|json|sarif|cbom|evidence|vex>\n Output format (default: human)\n --cbom Alias for --format cbom (CycloneDX CBOM)\n --format vex OpenVEX 0.2.0 document \u2014 one statement per rule,\n status \"affected\", with remediation + any\n --triage verdict for supply-chain VEX pipelines\n --merge <cbom.json> Merge an external CBOM (e.g. a qprobe endpoint\n CBOM) into the --cbom output via CycloneDX\n bom-link \u2014 one combined code + infra CBOM.\n Repeatable.\n --format evidence ISO 27001 A.8.24 readiness report \u2014 findings +\n inventory + CBOM + a deterministic content hash\n (sign/timestamp it with an external signer)\n --policy <file> Crypto-policy JSON; adds conformant/violation/\n transition verdicts to the evidence report\n --sign <command> Sign the evidence report: its contentHash is\n piped to <command> on stdin; stdout is recorded\n as the detached signature (needs --format evidence)\n --timestamp <command> Like --sign, but records an RFC-3161 timestamp\n token from <command> (needs --format evidence)\n -o, --output <file> Write the report to a file instead of stdout\n --severity-threshold <level> Fail (exit 1) on findings at/above this level;\n one of critical|high|medium|low|info\n (default: high)\n --no-source Skip scanning source files for inline crypto\n --no-deps Skip scanning dependency manifests\n --no-config Skip scanning config files (TLS/certificates)\n --config <path> Use this quantakrypto.config.json instead of\n auto-discovering one at the scan root\n --no-config-file Disable quantakrypto.config.json auto-discovery\n --ignore <pattern> Exclude paths matching <pattern> (repeatable)\n --include <pattern> Restrict the scan to matching paths (repeatable)\n --max-file-size <bytes> Skip files larger than <bytes> (default: 2 MiB)\n --no-default-ignores Don't skip node_modules/.git/dist by default\n --scan-minified Scan minified/generated/bundled files too\n --changed Scan only files changed in the git work tree\n --since <git-ref> With --changed, diff against <git-ref>\n --parallel Scan using a worker-thread pool when worthwhile\n --concurrency <n> Worker count for --parallel (implies --parallel);\n 0 forces the in-process serial path\n --top <n> List <n> findings in the human report (default: 5)\n --tier <category-3|category-5> Add CNSA migration targets to the report footer\n (category-5 = CNSA 2.0: ML-KEM-1024 / ML-DSA-87;\n an alias for --profile cnsa-2.0)\n --profile <id> Tailor migration guidance to a standards regime:\n nist (default) | cnsa-2.0 | bsi-tr-02102 | anssi |\n uk-ncsc. Sets the parameter sets, deadlines, and\n whether hybridization is required/recommended/optional\n --mandate <id> Gate findings against a compliance mandate's dated\n clauses (repeatable): cnsa-2.0 | nist-ir-8547. Reports\n each prohibited finding with its clause + deadline;\n fails the build only once a deadline has passed\n --lead-months <n> Fail early when a --mandate deadline is within n months\n --fail-now Fail on any --mandate-prohibited finding, ignoring the date\n --cache [file] Reuse findings for unchanged files across runs\n (default file: .quantakrypto-cache.json)\n --triage BYOK LLM pass that re-ranks findings by real\n exposure and explains them (never suppresses,\n never changes the exit code). Needs an API key in\n QK_LLM_API_KEY / ANTHROPIC_API_KEY / OPENAI_API_KEY\n --triage-floor <level> Only triage findings at/above this level (default: medium)\n --max-findings <n> Cap findings sent to the LLM during triage (default: 100; spend guard)\n --context <level> Source shared with the LLM: metadata|snippet|\n function|file (default: snippet; secrets always redacted)\n --dry-run With --triage, print the exact payload that would\n be sent and exit without calling the provider\n --llm-provider <name> anthropic | openai-compatible (default: anthropic)\n --llm-model <id> Model id for the BYOK provider\n --hndl Score harvest-now-decrypt-later exposure per\n finding + a repo summary from hndl.yml (data\n assets, classification, retention + secrecy\n lifetime vs the quantum-threat horizon; Mosca's\n inequality). Adds exposure fields to json/sarif;\n additive, never changes the exit code. Scaffold\n the map with \"qscan hndl init\". See docs/HNDL.md\n --audit Opt-in supply-chain audit: run each present\n ecosystem's advisory tool (cargo audit / pip-audit\n / npm audit) for known-vulnerable pinned\n dependencies, and verify the declared source\n repository resolves (provenance). Findings merge\n into the report and the exit code. A missing tool\n or a network hiccup degrades to a diagnostic on\n stderr, never a failure. Requires the ecosystem's\n audit tool on PATH; the provenance HEAD request is\n the only network call qScan itself makes\n --crypto-agility Emit a crypto-agility posture manifest instead of a\n scan report (equivalent to \"crypto-agility emit\";\n always exits 0). A well-known-URL JSON document any\n agent/CI bot can read like security.txt: readiness\n score, quantum-vulnerable findings by severity, CBOM\n algorithm families, policy deadlines. Combine with\n --attestation / --hybrid-kex / --policy / -o.\n See docs/CRYPTO-AGILITY-MANIFEST.md\n --attestation <url> Record a posture-credential URL in the manifest\n (recorded verbatim, never fetched; offline boundary)\n --hybrid-kex / --no-hybrid-kex\n Assert hybrid post-quantum key exchange is / is not\n in use in the manifest (default: null / undetermined,\n since a static scan can't observe a negotiated group)\n --baseline <file> Suppress findings listed in a baseline file\n --write-baseline <file> Write current findings as a baseline, then exit 0\n --quiet Suppress the human summary banner\n --no-snippets Omit code snippets from the json/sarif report\n --color Force ANSI color in the human report\n --no-color Disable ANSI color (also: NO_COLOR env). Color is\n decoration only \u2014 every signal is printed as text\n -v, --version Print version and exit\n -h, --help Print this help and exit\n\nEXIT CODES\n 0 No findings at/above the threshold (or a baseline was written)\n 1 One or more findings at/above the severity threshold\n 2 Usage error or I/O failure\n\nEXAMPLES\n qscan . Scan the current directory\n qscan src --format sarif -o qscan.sarif\n qscan . --severity-threshold critical\n qscan . --write-baseline qscan-baseline.json\n qscan . --baseline qscan-baseline.json\n qscan . --include src --include lib\n qscan . --config ./ci/quantakrypto.config.json\n qscan . --changed --since origin/main\n qscan . --parallel --concurrency 4\n qscan . --cbom -o qscan-cbom.json\n qscan hndl init Scaffold hndl.yml seeded with detected assets\n qscan . --hndl --format json Emit per-finding HNDL exposure + a repo summary\n qscan . --audit Add dependency-advisory + provenance checks\n qscan . --crypto-agility -o .well-known/crypto-agility.json\n qscan crypto-agility validate .well-known/crypto-agility.json\n"; | ||
| /** The `--version` line. */ | ||
| export declare function versionLine(): string; | ||
| //# sourceMappingURL=help.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,gCAAgC;AAChC,eAAO,MAAM,SAAS,+1RAmIrB,CAAC;AAEF,4BAA4B;AAC5B,wBAAgB,WAAW,IAAI,MAAM,CAEpC"} | ||
| {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,gCAAgC;AAChC,eAAO,MAAM,SAAS,4sTA8IrB,CAAC;AAEF,4BAA4B;AAC5B,wBAAgB,WAAW,IAAI,MAAM,CAEpC"} |
+11
-0
@@ -96,2 +96,12 @@ /** | ||
| the map with "qscan hndl init". See docs/HNDL.md | ||
| --audit Opt-in supply-chain audit: run each present | ||
| ecosystem's advisory tool (cargo audit / pip-audit | ||
| / npm audit) for known-vulnerable pinned | ||
| dependencies, and verify the declared source | ||
| repository resolves (provenance). Findings merge | ||
| into the report and the exit code. A missing tool | ||
| or a network hiccup degrades to a diagnostic on | ||
| stderr, never a failure. Requires the ecosystem's | ||
| audit tool on PATH; the provenance HEAD request is | ||
| the only network call qScan itself makes | ||
| --crypto-agility Emit a crypto-agility posture manifest instead of a | ||
@@ -139,2 +149,3 @@ scan report (equivalent to "crypto-agility emit"; | ||
| qscan . --hndl --format json Emit per-finding HNDL exposure + a repo summary | ||
| qscan . --audit Add dependency-advisory + provenance checks | ||
| qscan . --crypto-agility -o .well-known/crypto-agility.json | ||
@@ -141,0 +152,0 @@ qscan crypto-agility validate .well-known/crypto-agility.json |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,gCAAgC;AAChC,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmIxB,CAAC;AAEF,4BAA4B;AAC5B,MAAM,UAAU,WAAW;IACzB,OAAO,SAAS,OAAO,EAAE,CAAC;AAC5B,CAAC","sourcesContent":["/**\n * Static help / usage text for the qScan CLI.\n *\n * Kept in its own module so it can be unit-tested and reused without pulling in\n * filesystem or process side effects.\n */\n\nimport { VERSION } from \"@quantakrypto/core\";\n\n/** The full `--help` screen. */\nexport const HELP_TEXT = `qscan — find quantum-vulnerable cryptography in any codebase\n\nUSAGE\n qscan [path] [options]\n qscan hndl init [path] Scaffold an hndl.yml data map (see --hndl)\n qscan crypto-agility emit [path] Write a crypto-agility manifest (exits 0)\n qscan crypto-agility validate <file> Check a local manifest against the schema\n\nARGUMENTS\n path Directory or file to scan (default: \".\")\n\nOPTIONS\n --format <human|json|sarif|cbom|evidence|vex>\n Output format (default: human)\n --cbom Alias for --format cbom (CycloneDX CBOM)\n --format vex OpenVEX 0.2.0 document — one statement per rule,\n status \"affected\", with remediation + any\n --triage verdict for supply-chain VEX pipelines\n --merge <cbom.json> Merge an external CBOM (e.g. a qprobe endpoint\n CBOM) into the --cbom output via CycloneDX\n bom-link — one combined code + infra CBOM.\n Repeatable.\n --format evidence ISO 27001 A.8.24 readiness report — findings +\n inventory + CBOM + a deterministic content hash\n (sign/timestamp it with an external signer)\n --policy <file> Crypto-policy JSON; adds conformant/violation/\n transition verdicts to the evidence report\n --sign <command> Sign the evidence report: its contentHash is\n piped to <command> on stdin; stdout is recorded\n as the detached signature (needs --format evidence)\n --timestamp <command> Like --sign, but records an RFC-3161 timestamp\n token from <command> (needs --format evidence)\n -o, --output <file> Write the report to a file instead of stdout\n --severity-threshold <level> Fail (exit 1) on findings at/above this level;\n one of critical|high|medium|low|info\n (default: high)\n --no-source Skip scanning source files for inline crypto\n --no-deps Skip scanning dependency manifests\n --no-config Skip scanning config files (TLS/certificates)\n --config <path> Use this quantakrypto.config.json instead of\n auto-discovering one at the scan root\n --no-config-file Disable quantakrypto.config.json auto-discovery\n --ignore <pattern> Exclude paths matching <pattern> (repeatable)\n --include <pattern> Restrict the scan to matching paths (repeatable)\n --max-file-size <bytes> Skip files larger than <bytes> (default: 2 MiB)\n --no-default-ignores Don't skip node_modules/.git/dist by default\n --scan-minified Scan minified/generated/bundled files too\n --changed Scan only files changed in the git work tree\n --since <git-ref> With --changed, diff against <git-ref>\n --parallel Scan using a worker-thread pool when worthwhile\n --concurrency <n> Worker count for --parallel (implies --parallel);\n 0 forces the in-process serial path\n --top <n> List <n> findings in the human report (default: 5)\n --tier <category-3|category-5> Add CNSA migration targets to the report footer\n (category-5 = CNSA 2.0: ML-KEM-1024 / ML-DSA-87;\n an alias for --profile cnsa-2.0)\n --profile <id> Tailor migration guidance to a standards regime:\n nist (default) | cnsa-2.0 | bsi-tr-02102 | anssi |\n uk-ncsc. Sets the parameter sets, deadlines, and\n whether hybridization is required/recommended/optional\n --mandate <id> Gate findings against a compliance mandate's dated\n clauses (repeatable): cnsa-2.0 | nist-ir-8547. Reports\n each prohibited finding with its clause + deadline;\n fails the build only once a deadline has passed\n --lead-months <n> Fail early when a --mandate deadline is within n months\n --fail-now Fail on any --mandate-prohibited finding, ignoring the date\n --cache [file] Reuse findings for unchanged files across runs\n (default file: .quantakrypto-cache.json)\n --triage BYOK LLM pass that re-ranks findings by real\n exposure and explains them (never suppresses,\n never changes the exit code). Needs an API key in\n QK_LLM_API_KEY / ANTHROPIC_API_KEY / OPENAI_API_KEY\n --triage-floor <level> Only triage findings at/above this level (default: medium)\n --max-findings <n> Cap findings sent to the LLM during triage (default: 100; spend guard)\n --context <level> Source shared with the LLM: metadata|snippet|\n function|file (default: snippet; secrets always redacted)\n --dry-run With --triage, print the exact payload that would\n be sent and exit without calling the provider\n --llm-provider <name> anthropic | openai-compatible (default: anthropic)\n --llm-model <id> Model id for the BYOK provider\n --hndl Score harvest-now-decrypt-later exposure per\n finding + a repo summary from hndl.yml (data\n assets, classification, retention + secrecy\n lifetime vs the quantum-threat horizon; Mosca's\n inequality). Adds exposure fields to json/sarif;\n additive, never changes the exit code. Scaffold\n the map with \"qscan hndl init\". See docs/HNDL.md\n --crypto-agility Emit a crypto-agility posture manifest instead of a\n scan report (equivalent to \"crypto-agility emit\";\n always exits 0). A well-known-URL JSON document any\n agent/CI bot can read like security.txt: readiness\n score, quantum-vulnerable findings by severity, CBOM\n algorithm families, policy deadlines. Combine with\n --attestation / --hybrid-kex / --policy / -o.\n See docs/CRYPTO-AGILITY-MANIFEST.md\n --attestation <url> Record a posture-credential URL in the manifest\n (recorded verbatim, never fetched; offline boundary)\n --hybrid-kex / --no-hybrid-kex\n Assert hybrid post-quantum key exchange is / is not\n in use in the manifest (default: null / undetermined,\n since a static scan can't observe a negotiated group)\n --baseline <file> Suppress findings listed in a baseline file\n --write-baseline <file> Write current findings as a baseline, then exit 0\n --quiet Suppress the human summary banner\n --no-snippets Omit code snippets from the json/sarif report\n --color Force ANSI color in the human report\n --no-color Disable ANSI color (also: NO_COLOR env). Color is\n decoration only — every signal is printed as text\n -v, --version Print version and exit\n -h, --help Print this help and exit\n\nEXIT CODES\n 0 No findings at/above the threshold (or a baseline was written)\n 1 One or more findings at/above the severity threshold\n 2 Usage error or I/O failure\n\nEXAMPLES\n qscan . Scan the current directory\n qscan src --format sarif -o qscan.sarif\n qscan . --severity-threshold critical\n qscan . --write-baseline qscan-baseline.json\n qscan . --baseline qscan-baseline.json\n qscan . --include src --include lib\n qscan . --config ./ci/quantakrypto.config.json\n qscan . --changed --since origin/main\n qscan . --parallel --concurrency 4\n qscan . --cbom -o qscan-cbom.json\n qscan hndl init Scaffold hndl.yml seeded with detected assets\n qscan . --hndl --format json Emit per-finding HNDL exposure + a repo summary\n qscan . --crypto-agility -o .well-known/crypto-agility.json\n qscan crypto-agility validate .well-known/crypto-agility.json\n`;\n\n/** The `--version` line. */\nexport function versionLine(): string {\n return `qscan ${VERSION}`;\n}\n"]} | ||
| {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,gCAAgC;AAChC,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8IxB,CAAC;AAEF,4BAA4B;AAC5B,MAAM,UAAU,WAAW;IACzB,OAAO,SAAS,OAAO,EAAE,CAAC;AAC5B,CAAC","sourcesContent":["/**\n * Static help / usage text for the qScan CLI.\n *\n * Kept in its own module so it can be unit-tested and reused without pulling in\n * filesystem or process side effects.\n */\n\nimport { VERSION } from \"@quantakrypto/core\";\n\n/** The full `--help` screen. */\nexport const HELP_TEXT = `qscan — find quantum-vulnerable cryptography in any codebase\n\nUSAGE\n qscan [path] [options]\n qscan hndl init [path] Scaffold an hndl.yml data map (see --hndl)\n qscan crypto-agility emit [path] Write a crypto-agility manifest (exits 0)\n qscan crypto-agility validate <file> Check a local manifest against the schema\n\nARGUMENTS\n path Directory or file to scan (default: \".\")\n\nOPTIONS\n --format <human|json|sarif|cbom|evidence|vex>\n Output format (default: human)\n --cbom Alias for --format cbom (CycloneDX CBOM)\n --format vex OpenVEX 0.2.0 document — one statement per rule,\n status \"affected\", with remediation + any\n --triage verdict for supply-chain VEX pipelines\n --merge <cbom.json> Merge an external CBOM (e.g. a qprobe endpoint\n CBOM) into the --cbom output via CycloneDX\n bom-link — one combined code + infra CBOM.\n Repeatable.\n --format evidence ISO 27001 A.8.24 readiness report — findings +\n inventory + CBOM + a deterministic content hash\n (sign/timestamp it with an external signer)\n --policy <file> Crypto-policy JSON; adds conformant/violation/\n transition verdicts to the evidence report\n --sign <command> Sign the evidence report: its contentHash is\n piped to <command> on stdin; stdout is recorded\n as the detached signature (needs --format evidence)\n --timestamp <command> Like --sign, but records an RFC-3161 timestamp\n token from <command> (needs --format evidence)\n -o, --output <file> Write the report to a file instead of stdout\n --severity-threshold <level> Fail (exit 1) on findings at/above this level;\n one of critical|high|medium|low|info\n (default: high)\n --no-source Skip scanning source files for inline crypto\n --no-deps Skip scanning dependency manifests\n --no-config Skip scanning config files (TLS/certificates)\n --config <path> Use this quantakrypto.config.json instead of\n auto-discovering one at the scan root\n --no-config-file Disable quantakrypto.config.json auto-discovery\n --ignore <pattern> Exclude paths matching <pattern> (repeatable)\n --include <pattern> Restrict the scan to matching paths (repeatable)\n --max-file-size <bytes> Skip files larger than <bytes> (default: 2 MiB)\n --no-default-ignores Don't skip node_modules/.git/dist by default\n --scan-minified Scan minified/generated/bundled files too\n --changed Scan only files changed in the git work tree\n --since <git-ref> With --changed, diff against <git-ref>\n --parallel Scan using a worker-thread pool when worthwhile\n --concurrency <n> Worker count for --parallel (implies --parallel);\n 0 forces the in-process serial path\n --top <n> List <n> findings in the human report (default: 5)\n --tier <category-3|category-5> Add CNSA migration targets to the report footer\n (category-5 = CNSA 2.0: ML-KEM-1024 / ML-DSA-87;\n an alias for --profile cnsa-2.0)\n --profile <id> Tailor migration guidance to a standards regime:\n nist (default) | cnsa-2.0 | bsi-tr-02102 | anssi |\n uk-ncsc. Sets the parameter sets, deadlines, and\n whether hybridization is required/recommended/optional\n --mandate <id> Gate findings against a compliance mandate's dated\n clauses (repeatable): cnsa-2.0 | nist-ir-8547. Reports\n each prohibited finding with its clause + deadline;\n fails the build only once a deadline has passed\n --lead-months <n> Fail early when a --mandate deadline is within n months\n --fail-now Fail on any --mandate-prohibited finding, ignoring the date\n --cache [file] Reuse findings for unchanged files across runs\n (default file: .quantakrypto-cache.json)\n --triage BYOK LLM pass that re-ranks findings by real\n exposure and explains them (never suppresses,\n never changes the exit code). Needs an API key in\n QK_LLM_API_KEY / ANTHROPIC_API_KEY / OPENAI_API_KEY\n --triage-floor <level> Only triage findings at/above this level (default: medium)\n --max-findings <n> Cap findings sent to the LLM during triage (default: 100; spend guard)\n --context <level> Source shared with the LLM: metadata|snippet|\n function|file (default: snippet; secrets always redacted)\n --dry-run With --triage, print the exact payload that would\n be sent and exit without calling the provider\n --llm-provider <name> anthropic | openai-compatible (default: anthropic)\n --llm-model <id> Model id for the BYOK provider\n --hndl Score harvest-now-decrypt-later exposure per\n finding + a repo summary from hndl.yml (data\n assets, classification, retention + secrecy\n lifetime vs the quantum-threat horizon; Mosca's\n inequality). Adds exposure fields to json/sarif;\n additive, never changes the exit code. Scaffold\n the map with \"qscan hndl init\". See docs/HNDL.md\n --audit Opt-in supply-chain audit: run each present\n ecosystem's advisory tool (cargo audit / pip-audit\n / npm audit) for known-vulnerable pinned\n dependencies, and verify the declared source\n repository resolves (provenance). Findings merge\n into the report and the exit code. A missing tool\n or a network hiccup degrades to a diagnostic on\n stderr, never a failure. Requires the ecosystem's\n audit tool on PATH; the provenance HEAD request is\n the only network call qScan itself makes\n --crypto-agility Emit a crypto-agility posture manifest instead of a\n scan report (equivalent to \"crypto-agility emit\";\n always exits 0). A well-known-URL JSON document any\n agent/CI bot can read like security.txt: readiness\n score, quantum-vulnerable findings by severity, CBOM\n algorithm families, policy deadlines. Combine with\n --attestation / --hybrid-kex / --policy / -o.\n See docs/CRYPTO-AGILITY-MANIFEST.md\n --attestation <url> Record a posture-credential URL in the manifest\n (recorded verbatim, never fetched; offline boundary)\n --hybrid-kex / --no-hybrid-kex\n Assert hybrid post-quantum key exchange is / is not\n in use in the manifest (default: null / undetermined,\n since a static scan can't observe a negotiated group)\n --baseline <file> Suppress findings listed in a baseline file\n --write-baseline <file> Write current findings as a baseline, then exit 0\n --quiet Suppress the human summary banner\n --no-snippets Omit code snippets from the json/sarif report\n --color Force ANSI color in the human report\n --no-color Disable ANSI color (also: NO_COLOR env). Color is\n decoration only — every signal is printed as text\n -v, --version Print version and exit\n -h, --help Print this help and exit\n\nEXIT CODES\n 0 No findings at/above the threshold (or a baseline was written)\n 1 One or more findings at/above the severity threshold\n 2 Usage error or I/O failure\n\nEXAMPLES\n qscan . Scan the current directory\n qscan src --format sarif -o qscan.sarif\n qscan . --severity-threshold critical\n qscan . --write-baseline qscan-baseline.json\n qscan . --baseline qscan-baseline.json\n qscan . --include src --include lib\n qscan . --config ./ci/quantakrypto.config.json\n qscan . --changed --since origin/main\n qscan . --parallel --concurrency 4\n qscan . --cbom -o qscan-cbom.json\n qscan hndl init Scaffold hndl.yml seeded with detected assets\n qscan . --hndl --format json Emit per-finding HNDL exposure + a repo summary\n qscan . --audit Add dependency-advisory + provenance checks\n qscan . --crypto-agility -o .well-known/crypto-agility.json\n qscan crypto-agility validate .well-known/crypto-agility.json\n`;\n\n/** The `--version` line. */\nexport function versionLine(): string {\n return `qscan ${VERSION}`;\n}\n"]} |
+5
-0
@@ -44,2 +44,7 @@ /** | ||
| baselineWritten?: Baseline; | ||
| /** | ||
| * Non-fatal diagnostics from the `--audit` checks (a skipped tool, a network | ||
| * hiccup). Present only when `--audit` ran; the CLI surfaces them on stderr. | ||
| */ | ||
| auditDiagnostics?: string[]; | ||
| /** Suggested process exit code. */ | ||
@@ -46,0 +51,0 @@ exitCode: number; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} |
+37
-3
@@ -15,4 +15,5 @@ /** | ||
| import process from "node:process"; | ||
| import { buildCryptoAgilityManifest, buildReadinessReport, changedFiles, computeHndl, findingScope, HNDL_FILENAME, loadHndlMap, parseCryptoPolicy, evaluateMandates, mandateGateFails, assertKnownMandates, scaffoldHndlYaml, scan, scanParallel, signReadinessReport, validateCryptoAgilityManifest, } from "@quantakrypto/core"; | ||
| import { buildCryptoAgilityManifest, buildInventory, buildReadinessReport, changedFiles, checkProvenance, compareFindings, computeHndl, findingScope, HNDL_FILENAME, loadHndlMap, parseCryptoPolicy, evaluateMandates, mandateGateFails, assertKnownMandates, scaffoldHndlYaml, scan, scanAdvisories, scanParallel, signReadinessReport, validateCryptoAgilityManifest, } from "@quantakrypto/core"; | ||
| import { commandSigner } from "./sign.js"; | ||
| import { repoHeadRequest } from "./provenance-net.js"; | ||
| import { applyBaseline, readBaseline, saveBaseline } from "./baseline.js"; | ||
@@ -102,2 +103,22 @@ import { defaultOptions, meetsThreshold } from "./args.js"; | ||
| const result = await scanFn(scanOptions); | ||
| // --audit: opt-in supply-chain checks. Shell out to each present ecosystem's | ||
| // advisory tool and verify the declared source repository resolves. Findings | ||
| // merge into the result (so they count toward the report AND the exit code); | ||
| // the inventory is rebuilt so the summary counts stay consistent. Both checks | ||
| // degrade to diagnostics — never throw — so an offline run or a missing tool | ||
| // can't fail the scan. The provenance HEAD request is injected (the networked | ||
| // half lives in qScan; core stays offline per ADR-0005). | ||
| let auditDiagnostics; | ||
| if (options.audit) { | ||
| const [advisories, provenance] = await Promise.all([ | ||
| scanAdvisories(options.path), | ||
| checkProvenance(options.path, { network: true, head: repoHeadRequest }), | ||
| ]); | ||
| const extra = [...advisories.findings, ...provenance.findings]; | ||
| if (extra.length > 0) { | ||
| result.findings = [...result.findings, ...extra].sort(compareFindings); | ||
| result.inventory = buildInventory(result.findings); | ||
| } | ||
| auditDiagnostics = [...advisories.diagnostics, ...provenance.diagnostics]; | ||
| } | ||
| // --write-baseline: snapshot every finding, persist, and exit cleanly. | ||
@@ -110,2 +131,3 @@ if (options.writeBaseline) { | ||
| baselineWritten: baseline, | ||
| ...(auditDiagnostics ? { auditDiagnostics } : {}), | ||
| exitCode: EXIT.OK, | ||
@@ -171,3 +193,9 @@ }; | ||
| if (triaged.preflight !== undefined) { | ||
| return { result, suppressed, report: triaged.preflight, exitCode: EXIT.OK }; | ||
| return { | ||
| result, | ||
| suppressed, | ||
| report: triaged.preflight, | ||
| ...(auditDiagnostics ? { auditDiagnostics } : {}), | ||
| exitCode: EXIT.OK, | ||
| }; | ||
| } | ||
@@ -250,3 +278,9 @@ } | ||
| } | ||
| return { result, suppressed, report, exitCode }; | ||
| return { | ||
| result, | ||
| suppressed, | ||
| report, | ||
| ...(auditDiagnostics ? { auditDiagnostics } : {}), | ||
| exitCode, | ||
| }; | ||
| } | ||
@@ -253,0 +287,0 @@ /** A concise human compliance block appended to the default report for `--mandate`. */ |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @quantakrypto/qscan — programmatic API.\n *\n * `runQscan` is the single entry point shared by the CLI (`src/cli.ts`) and by\n * `@quantakrypto/action`. It runs a scan via `@quantakrypto/core`, applies an optional\n * baseline, decides an exit code from the severity threshold, and (optionally)\n * renders a report. The CLI is a thin shell around it.\n *\n * The module also re-exports the argument-parsing and baseline helpers so\n * downstream tools can reuse them without reaching into internal paths.\n */\n\nimport { readFile, stat } from \"node:fs/promises\";\nimport * as nodePath from \"node:path\";\nimport process from \"node:process\";\n\nimport {\n buildCryptoAgilityManifest,\n buildReadinessReport,\n changedFiles,\n computeHndl,\n findingScope,\n HNDL_FILENAME,\n loadHndlMap,\n parseCryptoPolicy,\n evaluateMandates,\n mandateGateFails,\n assertKnownMandates,\n scaffoldHndlYaml,\n scan,\n scanParallel,\n signReadinessReport,\n validateCryptoAgilityManifest,\n} from \"@quantakrypto/core\";\nimport type {\n Baseline,\n CryptoPolicy,\n CycloneDxBom,\n EvidenceSigner,\n Finding,\n HndlReport,\n ManifestValidation,\n ParallelScanOptions,\n ReadinessReport,\n ScanResult,\n SecurityTier,\n} from \"@quantakrypto/core\";\nimport type { MandateEvaluation } from \"@quantakrypto/core\";\nimport { commandSigner } from \"./sign.js\";\n\nimport { applyBaseline, readBaseline, saveBaseline } from \"./baseline.js\";\nimport { defaultOptions, meetsThreshold } from \"./args.js\";\nimport type { QscanOptions } from \"./args.js\";\nimport { renderCbom, renderHuman, renderJson, renderSarif, renderVex } from \"./report.js\";\n\nexport type { QscanOptions, ParsedArgs, ParsedRun, QscanFormat } from \"./args.js\";\nexport type { Baseline } from \"./baseline.js\";\nexport {\n ArgError,\n asFormat,\n asInt,\n asSeverity,\n defaultOptions,\n meetsThreshold,\n parseArgs,\n severityRank,\n SEVERITY_ORDER,\n} from \"./args.js\";\nexport {\n applyBaseline,\n baselineFromFindings,\n BASELINE_VERSION,\n buildBaseline,\n fingerprint,\n fingerprintFinding,\n loadBaseline,\n readBaseline,\n saveBaseline,\n writeBaseline,\n} from \"./baseline.js\";\nexport { renderCbom, renderHuman, renderJson, renderSarif, renderVex } from \"./report.js\";\nexport { HELP_TEXT, versionLine } from \"./help.js\";\nexport {\n runRemediate,\n parseRemediateArgs,\n unifiedDiff,\n REMEDIATE_HELP,\n REMEDIATE_EXIT,\n} from \"./remediate-cli.js\";\nexport type {\n RemediateMode,\n RemediateOptions,\n RemediateRun,\n RemediateHooks,\n} from \"./remediate-cli.js\";\nexport { applyConfig, resolveConfig } from \"./config.js\";\nexport type { ResolvedConfig } from \"./config.js\";\nexport type { ConfigurableKey } from \"./args.js\";\n\n/** Process-style exit codes qScan uses. */\nexport const EXIT = {\n /** No findings at/above threshold, or a baseline was written. */\n OK: 0,\n /** One or more findings at/above the severity threshold. */\n FINDINGS: 1,\n /** Usage error or I/O failure. */\n ERROR: 2,\n} as const;\n\n/** Outcome of {@link runQscan}. */\nexport interface QscanRun {\n /** The scan result, with the baseline already applied to `findings`. */\n result: ScanResult;\n /** Findings suppressed because their fingerprint was in the baseline. */\n suppressed: Finding[];\n /** Rendered report in the requested format (`undefined` for a baseline write). */\n report?: string;\n /** The baseline that was written, when `writeBaseline` was requested. */\n baselineWritten?: Baseline;\n /** Suggested process exit code. */\n exitCode: number;\n}\n\n/**\n * The scan implementation `runQscan` calls. Matches `@quantakrypto/core`'s `scan` /\n * `scanParallel` (parallel options are a superset of `ScanOptions`).\n * Injectable so the GitHub Action and tests can supply a custom scanner.\n */\nexport type ScanFn = (options: ParallelScanOptions) => Promise<ScanResult>;\n\n/**\n * Resolve the changed-file list for incremental scans. Injectable for testing;\n * defaults to core's git-aware {@link changedFiles}.\n */\nexport type ChangedFilesFn = (root: string, since?: string) => Promise<string[]>;\n\n/** Behavioral hooks for {@link runQscan}, mainly for testing. */\nexport interface RunQscanHooks {\n /** Emit raw ANSI color in the human report. Default: false. */\n color?: boolean;\n /** Override the scanner. Default: `scan` / `scanParallel` from `@quantakrypto/core`. */\n scanFn?: ScanFn;\n /** Override changed-file resolution. Default: `changedFiles` from `@quantakrypto/core`. */\n changedFilesFn?: ChangedFilesFn;\n /** Inject the triage function (offline testing of the `--triage` path, so the\n * exit-code invariant can be exercised without a network client or API key).\n * `import type` keeps this a compile-time-only reference — the networked agent\n * package is still only loaded via the dynamic import inside `runTriage`. */\n triageFn?: import(\"./triage-run.js\").TriageFn;\n}\n\n/**\n * Translate resolved {@link QscanOptions} into core {@link ParallelScanOptions}.\n * `files` (the incremental file list) is layered on by {@link runQscan}.\n */\nfunction toScanOptions(options: QscanOptions): ParallelScanOptions {\n const scanOptions: ParallelScanOptions = {\n root: options.path,\n source: options.source,\n dependencies: options.dependencies,\n config: options.config,\n noDefaultIgnores: options.noDefaultIgnores,\n scanMinified: options.scanMinified,\n };\n if (options.ignore.length > 0) scanOptions.exclude = options.ignore;\n if (options.include.length > 0) scanOptions.include = options.include;\n if (options.maxFileSize !== undefined) scanOptions.maxFileSize = options.maxFileSize;\n if (options.concurrency !== undefined) scanOptions.concurrency = options.concurrency;\n if (options.disabledRules && options.disabledRules.length > 0) {\n scanOptions.disabledRules = options.disabledRules;\n }\n if (options.cacheFile) scanOptions.cacheFile = options.cacheFile;\n return scanOptions;\n}\n\n/**\n * Run a complete qScan pass: scan → baseline → threshold → render.\n *\n * This never touches `process` or stdout; the CLI is responsible for printing\n * `report`/writing `output` and calling `process.exit(exitCode)`. That keeps\n * the function pure enough to unit-test and to embed in the GitHub Action.\n *\n * Behavior:\n * - The walk is configured by `include` / `ignore` / `maxFileSize` /\n * `noDefaultIgnores` / `scanMinified`.\n * - With `changed` set, only the files git reports as changed (relative to\n * `since`, if given) are scanned via `ScanOptions.files`. A non-git tree\n * yields an empty list, so nothing is scanned.\n * - With `parallel` (or `concurrency`) set, the scan is routed through core's\n * `scanParallel`, which itself falls back to the serial path for small\n * inputs.\n * - When `opts.writeBaseline` is set, the scan runs, a baseline is built from\n * *all* findings, written to disk, and `exitCode` is {@link EXIT.OK}. No\n * report is rendered.\n * - When `opts.baseline` is set, its fingerprints are loaded and matching\n * findings are moved to `suppressed` (and removed from `result.findings`).\n * - `exitCode` is {@link EXIT.FINDINGS} when any *kept* finding meets the\n * severity threshold, else {@link EXIT.OK}.\n *\n * @throws {Error} Propagates scan / baseline I/O errors; the CLI maps these to\n * {@link EXIT.ERROR}.\n */\nexport async function runQscan(\n opts: Partial<QscanOptions> & { path: string },\n hooks: RunQscanHooks = {},\n): Promise<QscanRun> {\n const options: QscanOptions = { ...defaultOptions(), ...opts };\n // Route to the parallel pool when requested; both share the ScanOptions shape.\n const scanFn: ScanFn = hooks.scanFn ?? (options.parallel ? scanParallel : scan);\n const resolveChanged: ChangedFilesFn = hooks.changedFilesFn ?? changedFiles;\n\n const scanOptions = toScanOptions(options);\n\n // Incremental mode: restrict the scan to git-changed files.\n if (options.changed) {\n scanOptions.files = await resolveChanged(options.path, options.since);\n }\n\n const result = await scanFn(scanOptions);\n\n // --write-baseline: snapshot every finding, persist, and exit cleanly.\n if (options.writeBaseline) {\n const baseline = await saveBaseline(options.writeBaseline, result.findings);\n return {\n result,\n suppressed: [],\n baselineWritten: baseline,\n exitCode: EXIT.OK,\n };\n }\n\n // --baseline: suppress previously-accepted findings.\n //\n // The explicit `--baseline <path>` is read STRICTLY via `readBaseline`: a\n // missing or malformed file is an error (surfaced by the CLI as exit 2), not\n // silently treated as an empty baseline. Using core's tolerant `loadBaseline`\n // here would let a typo'd path (`--baseline typo.json`) suppress nothing and\n // still exit 0 — a CI footgun where a broken baseline reads as \"all clear\".\n let suppressed: Finding[] = [];\n if (options.baseline) {\n const fingerprints = await readBaseline(options.baseline);\n const split = applyBaseline(result.findings, fingerprints);\n result.findings = split.kept;\n suppressed = split.suppressed;\n }\n\n // --policy: the org cryptography policy for the evidence report's §4 verdicts.\n // Parsed strictly — a malformed policy fails loudly rather than silently\n // dropping the verdicts from the attested evidence.\n let policy: CryptoPolicy | undefined;\n if (options.policy) {\n policy = parseCryptoPolicy(JSON.parse(await readFile(options.policy, \"utf8\")));\n }\n\n // Exit code is computed from RAW severities, BEFORE triage runs, so the\n // (optional) LLM triage pass can never make a failing scan pass CI.\n let exitCode = result.findings.some((f) => meetsThreshold(f.severity, options.severityThreshold))\n ? EXIT.FINDINGS\n : EXIT.OK;\n\n // --mandate: policy-as-code compliance gate. Deadline-aware — reports every\n // mandate-prohibited finding with its named clause + deadline, but fails the build\n // only once a deadline has passed (or early with --lead-months / --fail-now). Uses\n // the same RAW findings as the exit code, so triage can never flip the gate.\n let mandateEval: MandateEvaluation | undefined;\n if (options.mandates.length > 0) {\n assertKnownMandates(options.mandates);\n mandateEval = evaluateMandates(result.findings, options.mandates, new Date());\n if (\n mandateGateFails(mandateEval, { leadMonths: options.leadMonths, failNow: options.failNow })\n ) {\n exitCode = EXIT.FINDINGS;\n }\n }\n\n // Optional BYOK triage: annotate + re-sort findings (never suppresses). The\n // agent (networked) package is loaded only here, via dynamic import.\n if (options.triage) {\n const { runTriage } = await import(\"./triage-run.js\");\n const triaged = await runTriage(result, {\n level: options.contextLevel ?? \"snippet\",\n floor: options.triageFloor,\n maxFindings: options.maxFindings,\n dryRun: options.dryRun,\n provider: options.llmProvider,\n model: options.llmModel,\n // The triage RESPONSE cache must not share a path with the scan cache —\n // they are different on-disk formats and would clobber each other every\n // run, defeating both (audit: arch #1). Derive a sibling path.\n cacheFile: options.cacheFile ? `${options.cacheFile}.responses.json` : undefined,\n root: options.path,\n triageFn: hooks.triageFn,\n });\n if (triaged.preflight !== undefined) {\n return { result, suppressed, report: triaged.preflight, exitCode: EXIT.OK };\n }\n }\n\n // `--merge` only has an effect on a `--cbom` output. If the user asked to merge but\n // the format is not cbom, that is almost certainly a mistake (a typo'd `--cbom`, or a\n // pipeline that forgot it) — the merge files would be silently ignored and the\n // combined bill of materials never produced. Fail loudly instead of dropping data.\n if (options.mergeCboms && options.mergeCboms.length > 0 && options.format !== \"cbom\") {\n throw new Error(`--merge requires --format cbom (got ${options.format ?? \"the human report\"})`);\n }\n\n // `--sign` / `--timestamp` fill the evidence attestation, so they only make sense\n // with `--format evidence`. Fail loudly rather than silently ignore the signer.\n if ((options.sign || options.timestamp) && options.format !== \"evidence\") {\n throw new Error(\n `--sign/--timestamp require --format evidence (got ${options.format ?? \"the human report\"})`,\n );\n }\n // HNDL exposure (`--hndl`): read the declared data map, score every finding\n // and build the repo summary. Computed AFTER the exit code so it can never\n // change CI pass/fail - it only annotates + ranks. A missing / malformed\n // hndl.yml fails loudly (the user opted in), surfaced by the CLI as exit 2.\n let hndl: HndlReport | undefined;\n if (options.hndl) {\n const { map } = await loadHndlMap(options.path);\n hndl = computeHndl(result.findings, map);\n }\n\n const signer: EvidenceSigner | undefined = options.sign ? commandSigner(options.sign) : undefined;\n const timestamper: EvidenceSigner | undefined = options.timestamp\n ? commandSigner(options.timestamp)\n : undefined;\n\n // Load any external CBOMs to merge into a `--cbom` output (combined\n // code + infrastructure bill of materials). Only relevant for the cbom format.\n let mergeCbomsData: CycloneDxBom[] | undefined;\n if (options.format === \"cbom\" && options.mergeCboms && options.mergeCboms.length > 0) {\n mergeCbomsData = [];\n for (const path of options.mergeCboms) {\n let text: string;\n try {\n text = await readFile(path, \"utf8\");\n } catch {\n throw new Error(`--merge: cannot read CBOM file \"${path}\"`);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n throw new Error(`--merge: \"${path}\" is not valid JSON`);\n }\n const bom = parsed as CycloneDxBom;\n if (bom?.bomFormat !== \"CycloneDX\") {\n throw new Error(`--merge: \"${path}\" is not a CycloneDX CBOM (missing bomFormat)`);\n }\n mergeCbomsData.push(bom);\n }\n }\n\n let report = renderReport(result, options.format, {\n color: hooks.color ?? false,\n redactSnippets: options.noSnippets,\n topN: options.topN,\n tier: options.tier,\n ...(options.profile ? { profile: options.profile } : {}),\n ...(policy ? { policy } : {}),\n ...(mergeCbomsData ? { mergeCboms: mergeCbomsData } : {}),\n ...(hndl ? { hndl } : {}),\n });\n // Evidence signing is orchestrated here (async: an external signer may be async),\n // after the synchronous renderer has produced the unsigned report (ADR-0004: the\n // tool orchestrates a signer, it does not implement crypto).\n if (options.format === \"evidence\" && (signer || timestamper)) {\n const signed = await signReadinessReport(JSON.parse(report) as ReadinessReport, {\n signer,\n timestamper,\n });\n report = JSON.stringify(signed, null, 2);\n }\n\n if (mandateEval && options.format === \"human\") {\n report += \"\\n\" + renderMandateBlock(mandateEval);\n }\n\n return { result, suppressed, report, exitCode };\n}\n\n/** A concise human compliance block appended to the default report for `--mandate`. */\nfunction renderMandateBlock(ev: MandateEvaluation): string {\n const lines: string[] = [];\n lines.push(`Compliance mandates: ${ev.mandates.join(\", \") || \"(none matched)\"}`);\n lines.push(\n ` ${ev.summary.violation} violation · ${ev.summary.deprecated} deprecated · ${ev.summary.due} due · ${ev.summary.conformant} conformant` +\n (ev.notInScope > 0 ? ` · ${ev.notInScope} out of scope` : \"\") +\n (ev.nextDeadline ? ` · next deadline ${ev.nextDeadline}` : \"\"),\n );\n const rank: Record<string, number> = { violation: 0, deprecated: 1, due: 2, conformant: 3 };\n const rows = [...ev.findings].sort(\n (a, b) =>\n (rank[a.status] ?? 9) - (rank[b.status] ?? 9) || a.effective.localeCompare(b.effective),\n );\n for (const r of rows.slice(0, 12)) {\n const when =\n r.status === \"violation\"\n ? `disallowed since ${r.effective}`\n : r.status === \"deprecated\"\n ? `deprecated since ${r.effective}${r.disallowEffective ? `, disallowed ${r.disallowEffective}` : \"\"}`\n : `due ${r.effective} (${r.monthsUntil} mo)`;\n lines.push(` [${r.status}] ${r.clause} · ${r.algorithm} ${r.file}:${r.line} — ${when}`);\n }\n if (rows.length > 12) lines.push(` … and ${rows.length - 12} more`);\n return lines.join(\"\\n\");\n}\n\n/** Outcome of {@link runHndlInit}: the scaffold plus where it should be written. */\nexport interface HndlInitResult {\n /** Absolute path the `hndl.yml` should be written to. */\n path: string;\n /** True when a file already exists there (the CLI refuses to overwrite). */\n exists: boolean;\n /** The generated `hndl.yml` content. */\n content: string;\n /** How many findings the seeding scan produced. */\n findingsScanned: number;\n /** How many distinct data-adjacent (config-scope, HNDL) findings seeded stubs. */\n seededFindings: number;\n}\n\n/**\n * Scaffold an `hndl.yml` for a repo (`qscan hndl init`). Runs a scan to seed the\n * template with detected data-adjacent findings, then returns the generated\n * content and its target path WITHOUT writing it - the CLI owns file I/O and the\n * refuse-to-overwrite decision.\n */\nexport async function runHndlInit(\n opts: Partial<QscanOptions> & { path: string },\n hooks: RunQscanHooks = {},\n): Promise<HndlInitResult> {\n const options: QscanOptions = { ...defaultOptions(), ...opts };\n const scanFn: ScanFn = hooks.scanFn ?? (options.parallel ? scanParallel : scan);\n const result = await scanFn(toScanOptions(options));\n\n const content = scaffoldHndlYaml(result.findings);\n const target = resolveHndlTarget(options.path);\n let exists = false;\n try {\n await stat(target);\n exists = true;\n } catch {\n exists = false;\n }\n const seededFindings = result.findings.filter(\n (f) => f.hndl && findingScope(f) === \"config\",\n ).length;\n return {\n path: target,\n exists,\n content,\n findingsScanned: result.findings.length,\n seededFindings,\n };\n}\n\n/** Resolve where `hndl init` writes: `<dir>/hndl.yml`, or an explicit `*.yml`. */\nfunction resolveHndlTarget(root: string): string {\n const base = nodePath.basename(root);\n if (base === HNDL_FILENAME || base.endsWith(\".yml\") || base.endsWith(\".yaml\")) {\n return nodePath.resolve(root);\n }\n return nodePath.resolve(root, HNDL_FILENAME);\n}\n\n/** Outcome of {@link runCryptoAgilityEmit}: the rendered manifest and the scan. */\nexport interface CryptoAgilityEmitResult {\n /** The scan result the manifest was derived from. */\n result: ScanResult;\n /** The pretty-printed crypto-agility manifest JSON (no trailing newline). */\n manifest: string;\n}\n\n/**\n * Emit a crypto-agility manifest for a repo (`qscan crypto-agility emit` /\n * `--crypto-agility`). Runs a scan and derives the manifest from its inventory +\n * CBOM. This is deliberately additive: it NEVER consults the severity threshold and\n * the CLI always exits 0 (publishing a posture manifest must not fail CI). The\n * generation timestamp is stamped here (the CLI runtime), keeping the core builder\n * pure. A `--policy` file overlays its `transitionDeadline`; `--attestation` records\n * a credential URL verbatim (never fetched); `--hybrid-kex` / `--no-hybrid-kex`\n * assert hybrid-KEX use.\n */\nexport async function runCryptoAgilityEmit(\n opts: Partial<QscanOptions> & { path: string },\n hooks: RunQscanHooks = {},\n): Promise<CryptoAgilityEmitResult> {\n const options: QscanOptions = { ...defaultOptions(), ...opts };\n const scanFn: ScanFn = hooks.scanFn ?? (options.parallel ? scanParallel : scan);\n const result = await scanFn(toScanOptions(options));\n\n let policy: CryptoPolicy | undefined;\n if (options.policy) {\n policy = parseCryptoPolicy(JSON.parse(await readFile(options.policy, \"utf8\")));\n }\n\n const manifest = buildCryptoAgilityManifest(result, {\n generatedAt: new Date().toISOString(),\n ...(options.attestation ? { attestationUrl: options.attestation } : {}),\n ...(options.hybridKexInUse !== undefined ? { hybridKexInUse: options.hybridKexInUse } : {}),\n ...(policy ? { policy } : {}),\n ...(process.env.GITHUB_REPOSITORY ? { repository: process.env.GITHUB_REPOSITORY } : {}),\n ...(process.env.GITHUB_SHA ? { commit: process.env.GITHUB_SHA } : {}),\n });\n return { result, manifest: JSON.stringify(manifest, null, 2) };\n}\n\n/**\n * Validate a LOCAL crypto-agility manifest file against the schema\n * (`qscan crypto-agility validate <file>`). Reads and parses the file, then defers\n * to core's {@link validateCryptoAgilityManifest}. Strictly offline: it never\n * fetches a URL (the attestation link and any remote manifest are a website-side\n * concern). Read / parse failures propagate to the CLI as an I/O error (exit 2); a\n * successfully-parsed but non-conforming manifest returns `{ valid: false }` and the\n * CLI exits non-zero.\n */\nexport async function runCryptoAgilityValidate(file: string): Promise<ManifestValidation> {\n const text = await readFile(file, \"utf8\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { valid: false, errors: [`not valid JSON: ${message}`] };\n }\n return validateCryptoAgilityManifest(parsed);\n}\n\n/** Rendering controls for {@link renderReport}. */\nexport interface RenderReportOptions {\n /** Emit raw ANSI color in the human report. Default: false. */\n color?: boolean;\n /** Omit code snippets from the JSON/SARIF report (`--no-snippets`). */\n redactSnippets?: boolean;\n /** How many findings the human report lists (`--top N`). */\n topN?: number;\n /** CNSA security tier for the migration-targets footer (`--tier`). */\n tier?: SecurityTier;\n /** Standards regime for the migration-targets footer (`--profile`). */\n profile?: string;\n /** Org cryptography policy for the evidence report's §4 verdicts (`--policy`). */\n policy?: CryptoPolicy;\n /** External CBOMs to merge into the `cbom` output (CycloneDX bom-link). */\n mergeCboms?: CycloneDxBom[];\n /** HNDL exposure analysis (`--hndl`); annotates JSON/SARIF/human output. */\n hndl?: HndlReport;\n}\n\n/** Render a scan result in the requested format. */\nexport function renderReport(\n result: ScanResult,\n format: QscanOptions[\"format\"],\n opts: RenderReportOptions | boolean = {},\n): string {\n // Back-compat: `renderReport(result, format, true)` used to mean \"color on\".\n const {\n color = false,\n redactSnippets = false,\n topN = undefined,\n tier = undefined,\n profile = undefined,\n policy = undefined,\n mergeCboms = undefined,\n hndl = undefined,\n } = typeof opts === \"boolean\" ? { color: opts, policy: undefined } : opts;\n switch (format) {\n case \"json\":\n return renderJson(result, { redactSnippets, ...(hndl ? { hndl } : {}) });\n case \"sarif\":\n return renderSarif(result, { redactSnippets, ...(hndl ? { hndl } : {}) });\n case \"cbom\":\n return renderCbom(result, mergeCboms);\n case \"vex\":\n return renderVex(result);\n case \"evidence\": {\n // ISO A.8.24 readiness report; repo/commit come from CI env when present.\n // A `--policy` file adds the §4 conformant/violation/transition verdicts. The\n // attestation is left unsigned here; signing is an async step in runQscan (an\n // external signer may be async), so this renderer stays synchronous.\n const report = buildReadinessReport(result, {\n repository: process.env.GITHUB_REPOSITORY,\n commit: process.env.GITHUB_SHA,\n ...(policy ? { policy } : {}),\n });\n return JSON.stringify(report, null, 2);\n }\n case \"human\":\n default:\n return renderHuman(result, { color, topN, tier, profile, ...(hndl ? { hndl } : {}) });\n }\n}\n\n/** Re-export the core result types consumers commonly need. */\nexport type { Finding, ScanResult, ScanOptions } from \"@quantakrypto/core\";\n"]} | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @quantakrypto/qscan — programmatic API.\n *\n * `runQscan` is the single entry point shared by the CLI (`src/cli.ts`) and by\n * `@quantakrypto/action`. It runs a scan via `@quantakrypto/core`, applies an optional\n * baseline, decides an exit code from the severity threshold, and (optionally)\n * renders a report. The CLI is a thin shell around it.\n *\n * The module also re-exports the argument-parsing and baseline helpers so\n * downstream tools can reuse them without reaching into internal paths.\n */\n\nimport { readFile, stat } from \"node:fs/promises\";\nimport * as nodePath from \"node:path\";\nimport process from \"node:process\";\n\nimport {\n buildCryptoAgilityManifest,\n buildInventory,\n buildReadinessReport,\n changedFiles,\n checkProvenance,\n compareFindings,\n computeHndl,\n findingScope,\n HNDL_FILENAME,\n loadHndlMap,\n parseCryptoPolicy,\n evaluateMandates,\n mandateGateFails,\n assertKnownMandates,\n scaffoldHndlYaml,\n scan,\n scanAdvisories,\n scanParallel,\n signReadinessReport,\n validateCryptoAgilityManifest,\n} from \"@quantakrypto/core\";\nimport type {\n Baseline,\n CryptoPolicy,\n CycloneDxBom,\n EvidenceSigner,\n Finding,\n HndlReport,\n ManifestValidation,\n ParallelScanOptions,\n ReadinessReport,\n ScanResult,\n SecurityTier,\n} from \"@quantakrypto/core\";\nimport type { MandateEvaluation } from \"@quantakrypto/core\";\nimport { commandSigner } from \"./sign.js\";\nimport { repoHeadRequest } from \"./provenance-net.js\";\n\nimport { applyBaseline, readBaseline, saveBaseline } from \"./baseline.js\";\nimport { defaultOptions, meetsThreshold } from \"./args.js\";\nimport type { QscanOptions } from \"./args.js\";\nimport { renderCbom, renderHuman, renderJson, renderSarif, renderVex } from \"./report.js\";\n\nexport type { QscanOptions, ParsedArgs, ParsedRun, QscanFormat } from \"./args.js\";\nexport type { Baseline } from \"./baseline.js\";\nexport {\n ArgError,\n asFormat,\n asInt,\n asSeverity,\n defaultOptions,\n meetsThreshold,\n parseArgs,\n severityRank,\n SEVERITY_ORDER,\n} from \"./args.js\";\nexport {\n applyBaseline,\n baselineFromFindings,\n BASELINE_VERSION,\n buildBaseline,\n fingerprint,\n fingerprintFinding,\n loadBaseline,\n readBaseline,\n saveBaseline,\n writeBaseline,\n} from \"./baseline.js\";\nexport { renderCbom, renderHuman, renderJson, renderSarif, renderVex } from \"./report.js\";\nexport { HELP_TEXT, versionLine } from \"./help.js\";\nexport {\n runRemediate,\n parseRemediateArgs,\n unifiedDiff,\n REMEDIATE_HELP,\n REMEDIATE_EXIT,\n} from \"./remediate-cli.js\";\nexport type {\n RemediateMode,\n RemediateOptions,\n RemediateRun,\n RemediateHooks,\n} from \"./remediate-cli.js\";\nexport { applyConfig, resolveConfig } from \"./config.js\";\nexport type { ResolvedConfig } from \"./config.js\";\nexport type { ConfigurableKey } from \"./args.js\";\n\n/** Process-style exit codes qScan uses. */\nexport const EXIT = {\n /** No findings at/above threshold, or a baseline was written. */\n OK: 0,\n /** One or more findings at/above the severity threshold. */\n FINDINGS: 1,\n /** Usage error or I/O failure. */\n ERROR: 2,\n} as const;\n\n/** Outcome of {@link runQscan}. */\nexport interface QscanRun {\n /** The scan result, with the baseline already applied to `findings`. */\n result: ScanResult;\n /** Findings suppressed because their fingerprint was in the baseline. */\n suppressed: Finding[];\n /** Rendered report in the requested format (`undefined` for a baseline write). */\n report?: string;\n /** The baseline that was written, when `writeBaseline` was requested. */\n baselineWritten?: Baseline;\n /**\n * Non-fatal diagnostics from the `--audit` checks (a skipped tool, a network\n * hiccup). Present only when `--audit` ran; the CLI surfaces them on stderr.\n */\n auditDiagnostics?: string[];\n /** Suggested process exit code. */\n exitCode: number;\n}\n\n/**\n * The scan implementation `runQscan` calls. Matches `@quantakrypto/core`'s `scan` /\n * `scanParallel` (parallel options are a superset of `ScanOptions`).\n * Injectable so the GitHub Action and tests can supply a custom scanner.\n */\nexport type ScanFn = (options: ParallelScanOptions) => Promise<ScanResult>;\n\n/**\n * Resolve the changed-file list for incremental scans. Injectable for testing;\n * defaults to core's git-aware {@link changedFiles}.\n */\nexport type ChangedFilesFn = (root: string, since?: string) => Promise<string[]>;\n\n/** Behavioral hooks for {@link runQscan}, mainly for testing. */\nexport interface RunQscanHooks {\n /** Emit raw ANSI color in the human report. Default: false. */\n color?: boolean;\n /** Override the scanner. Default: `scan` / `scanParallel` from `@quantakrypto/core`. */\n scanFn?: ScanFn;\n /** Override changed-file resolution. Default: `changedFiles` from `@quantakrypto/core`. */\n changedFilesFn?: ChangedFilesFn;\n /** Inject the triage function (offline testing of the `--triage` path, so the\n * exit-code invariant can be exercised without a network client or API key).\n * `import type` keeps this a compile-time-only reference — the networked agent\n * package is still only loaded via the dynamic import inside `runTriage`. */\n triageFn?: import(\"./triage-run.js\").TriageFn;\n}\n\n/**\n * Translate resolved {@link QscanOptions} into core {@link ParallelScanOptions}.\n * `files` (the incremental file list) is layered on by {@link runQscan}.\n */\nfunction toScanOptions(options: QscanOptions): ParallelScanOptions {\n const scanOptions: ParallelScanOptions = {\n root: options.path,\n source: options.source,\n dependencies: options.dependencies,\n config: options.config,\n noDefaultIgnores: options.noDefaultIgnores,\n scanMinified: options.scanMinified,\n };\n if (options.ignore.length > 0) scanOptions.exclude = options.ignore;\n if (options.include.length > 0) scanOptions.include = options.include;\n if (options.maxFileSize !== undefined) scanOptions.maxFileSize = options.maxFileSize;\n if (options.concurrency !== undefined) scanOptions.concurrency = options.concurrency;\n if (options.disabledRules && options.disabledRules.length > 0) {\n scanOptions.disabledRules = options.disabledRules;\n }\n if (options.cacheFile) scanOptions.cacheFile = options.cacheFile;\n return scanOptions;\n}\n\n/**\n * Run a complete qScan pass: scan → baseline → threshold → render.\n *\n * This never touches `process` or stdout; the CLI is responsible for printing\n * `report`/writing `output` and calling `process.exit(exitCode)`. That keeps\n * the function pure enough to unit-test and to embed in the GitHub Action.\n *\n * Behavior:\n * - The walk is configured by `include` / `ignore` / `maxFileSize` /\n * `noDefaultIgnores` / `scanMinified`.\n * - With `changed` set, only the files git reports as changed (relative to\n * `since`, if given) are scanned via `ScanOptions.files`. A non-git tree\n * yields an empty list, so nothing is scanned.\n * - With `parallel` (or `concurrency`) set, the scan is routed through core's\n * `scanParallel`, which itself falls back to the serial path for small\n * inputs.\n * - When `opts.writeBaseline` is set, the scan runs, a baseline is built from\n * *all* findings, written to disk, and `exitCode` is {@link EXIT.OK}. No\n * report is rendered.\n * - When `opts.baseline` is set, its fingerprints are loaded and matching\n * findings are moved to `suppressed` (and removed from `result.findings`).\n * - `exitCode` is {@link EXIT.FINDINGS} when any *kept* finding meets the\n * severity threshold, else {@link EXIT.OK}.\n *\n * @throws {Error} Propagates scan / baseline I/O errors; the CLI maps these to\n * {@link EXIT.ERROR}.\n */\nexport async function runQscan(\n opts: Partial<QscanOptions> & { path: string },\n hooks: RunQscanHooks = {},\n): Promise<QscanRun> {\n const options: QscanOptions = { ...defaultOptions(), ...opts };\n // Route to the parallel pool when requested; both share the ScanOptions shape.\n const scanFn: ScanFn = hooks.scanFn ?? (options.parallel ? scanParallel : scan);\n const resolveChanged: ChangedFilesFn = hooks.changedFilesFn ?? changedFiles;\n\n const scanOptions = toScanOptions(options);\n\n // Incremental mode: restrict the scan to git-changed files.\n if (options.changed) {\n scanOptions.files = await resolveChanged(options.path, options.since);\n }\n\n const result = await scanFn(scanOptions);\n\n // --audit: opt-in supply-chain checks. Shell out to each present ecosystem's\n // advisory tool and verify the declared source repository resolves. Findings\n // merge into the result (so they count toward the report AND the exit code);\n // the inventory is rebuilt so the summary counts stay consistent. Both checks\n // degrade to diagnostics — never throw — so an offline run or a missing tool\n // can't fail the scan. The provenance HEAD request is injected (the networked\n // half lives in qScan; core stays offline per ADR-0005).\n let auditDiagnostics: string[] | undefined;\n if (options.audit) {\n const [advisories, provenance] = await Promise.all([\n scanAdvisories(options.path),\n checkProvenance(options.path, { network: true, head: repoHeadRequest }),\n ]);\n const extra = [...advisories.findings, ...provenance.findings];\n if (extra.length > 0) {\n result.findings = [...result.findings, ...extra].sort(compareFindings);\n result.inventory = buildInventory(result.findings);\n }\n auditDiagnostics = [...advisories.diagnostics, ...provenance.diagnostics];\n }\n\n // --write-baseline: snapshot every finding, persist, and exit cleanly.\n if (options.writeBaseline) {\n const baseline = await saveBaseline(options.writeBaseline, result.findings);\n return {\n result,\n suppressed: [],\n baselineWritten: baseline,\n ...(auditDiagnostics ? { auditDiagnostics } : {}),\n exitCode: EXIT.OK,\n };\n }\n\n // --baseline: suppress previously-accepted findings.\n //\n // The explicit `--baseline <path>` is read STRICTLY via `readBaseline`: a\n // missing or malformed file is an error (surfaced by the CLI as exit 2), not\n // silently treated as an empty baseline. Using core's tolerant `loadBaseline`\n // here would let a typo'd path (`--baseline typo.json`) suppress nothing and\n // still exit 0 — a CI footgun where a broken baseline reads as \"all clear\".\n let suppressed: Finding[] = [];\n if (options.baseline) {\n const fingerprints = await readBaseline(options.baseline);\n const split = applyBaseline(result.findings, fingerprints);\n result.findings = split.kept;\n suppressed = split.suppressed;\n }\n\n // --policy: the org cryptography policy for the evidence report's §4 verdicts.\n // Parsed strictly — a malformed policy fails loudly rather than silently\n // dropping the verdicts from the attested evidence.\n let policy: CryptoPolicy | undefined;\n if (options.policy) {\n policy = parseCryptoPolicy(JSON.parse(await readFile(options.policy, \"utf8\")));\n }\n\n // Exit code is computed from RAW severities, BEFORE triage runs, so the\n // (optional) LLM triage pass can never make a failing scan pass CI.\n let exitCode = result.findings.some((f) => meetsThreshold(f.severity, options.severityThreshold))\n ? EXIT.FINDINGS\n : EXIT.OK;\n\n // --mandate: policy-as-code compliance gate. Deadline-aware — reports every\n // mandate-prohibited finding with its named clause + deadline, but fails the build\n // only once a deadline has passed (or early with --lead-months / --fail-now). Uses\n // the same RAW findings as the exit code, so triage can never flip the gate.\n let mandateEval: MandateEvaluation | undefined;\n if (options.mandates.length > 0) {\n assertKnownMandates(options.mandates);\n mandateEval = evaluateMandates(result.findings, options.mandates, new Date());\n if (\n mandateGateFails(mandateEval, { leadMonths: options.leadMonths, failNow: options.failNow })\n ) {\n exitCode = EXIT.FINDINGS;\n }\n }\n\n // Optional BYOK triage: annotate + re-sort findings (never suppresses). The\n // agent (networked) package is loaded only here, via dynamic import.\n if (options.triage) {\n const { runTriage } = await import(\"./triage-run.js\");\n const triaged = await runTriage(result, {\n level: options.contextLevel ?? \"snippet\",\n floor: options.triageFloor,\n maxFindings: options.maxFindings,\n dryRun: options.dryRun,\n provider: options.llmProvider,\n model: options.llmModel,\n // The triage RESPONSE cache must not share a path with the scan cache —\n // they are different on-disk formats and would clobber each other every\n // run, defeating both (audit: arch #1). Derive a sibling path.\n cacheFile: options.cacheFile ? `${options.cacheFile}.responses.json` : undefined,\n root: options.path,\n triageFn: hooks.triageFn,\n });\n if (triaged.preflight !== undefined) {\n return {\n result,\n suppressed,\n report: triaged.preflight,\n ...(auditDiagnostics ? { auditDiagnostics } : {}),\n exitCode: EXIT.OK,\n };\n }\n }\n\n // `--merge` only has an effect on a `--cbom` output. If the user asked to merge but\n // the format is not cbom, that is almost certainly a mistake (a typo'd `--cbom`, or a\n // pipeline that forgot it) — the merge files would be silently ignored and the\n // combined bill of materials never produced. Fail loudly instead of dropping data.\n if (options.mergeCboms && options.mergeCboms.length > 0 && options.format !== \"cbom\") {\n throw new Error(`--merge requires --format cbom (got ${options.format ?? \"the human report\"})`);\n }\n\n // `--sign` / `--timestamp` fill the evidence attestation, so they only make sense\n // with `--format evidence`. Fail loudly rather than silently ignore the signer.\n if ((options.sign || options.timestamp) && options.format !== \"evidence\") {\n throw new Error(\n `--sign/--timestamp require --format evidence (got ${options.format ?? \"the human report\"})`,\n );\n }\n // HNDL exposure (`--hndl`): read the declared data map, score every finding\n // and build the repo summary. Computed AFTER the exit code so it can never\n // change CI pass/fail - it only annotates + ranks. A missing / malformed\n // hndl.yml fails loudly (the user opted in), surfaced by the CLI as exit 2.\n let hndl: HndlReport | undefined;\n if (options.hndl) {\n const { map } = await loadHndlMap(options.path);\n hndl = computeHndl(result.findings, map);\n }\n\n const signer: EvidenceSigner | undefined = options.sign ? commandSigner(options.sign) : undefined;\n const timestamper: EvidenceSigner | undefined = options.timestamp\n ? commandSigner(options.timestamp)\n : undefined;\n\n // Load any external CBOMs to merge into a `--cbom` output (combined\n // code + infrastructure bill of materials). Only relevant for the cbom format.\n let mergeCbomsData: CycloneDxBom[] | undefined;\n if (options.format === \"cbom\" && options.mergeCboms && options.mergeCboms.length > 0) {\n mergeCbomsData = [];\n for (const path of options.mergeCboms) {\n let text: string;\n try {\n text = await readFile(path, \"utf8\");\n } catch {\n throw new Error(`--merge: cannot read CBOM file \"${path}\"`);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n throw new Error(`--merge: \"${path}\" is not valid JSON`);\n }\n const bom = parsed as CycloneDxBom;\n if (bom?.bomFormat !== \"CycloneDX\") {\n throw new Error(`--merge: \"${path}\" is not a CycloneDX CBOM (missing bomFormat)`);\n }\n mergeCbomsData.push(bom);\n }\n }\n\n let report = renderReport(result, options.format, {\n color: hooks.color ?? false,\n redactSnippets: options.noSnippets,\n topN: options.topN,\n tier: options.tier,\n ...(options.profile ? { profile: options.profile } : {}),\n ...(policy ? { policy } : {}),\n ...(mergeCbomsData ? { mergeCboms: mergeCbomsData } : {}),\n ...(hndl ? { hndl } : {}),\n });\n // Evidence signing is orchestrated here (async: an external signer may be async),\n // after the synchronous renderer has produced the unsigned report (ADR-0004: the\n // tool orchestrates a signer, it does not implement crypto).\n if (options.format === \"evidence\" && (signer || timestamper)) {\n const signed = await signReadinessReport(JSON.parse(report) as ReadinessReport, {\n signer,\n timestamper,\n });\n report = JSON.stringify(signed, null, 2);\n }\n\n if (mandateEval && options.format === \"human\") {\n report += \"\\n\" + renderMandateBlock(mandateEval);\n }\n\n return {\n result,\n suppressed,\n report,\n ...(auditDiagnostics ? { auditDiagnostics } : {}),\n exitCode,\n };\n}\n\n/** A concise human compliance block appended to the default report for `--mandate`. */\nfunction renderMandateBlock(ev: MandateEvaluation): string {\n const lines: string[] = [];\n lines.push(`Compliance mandates: ${ev.mandates.join(\", \") || \"(none matched)\"}`);\n lines.push(\n ` ${ev.summary.violation} violation · ${ev.summary.deprecated} deprecated · ${ev.summary.due} due · ${ev.summary.conformant} conformant` +\n (ev.notInScope > 0 ? ` · ${ev.notInScope} out of scope` : \"\") +\n (ev.nextDeadline ? ` · next deadline ${ev.nextDeadline}` : \"\"),\n );\n const rank: Record<string, number> = { violation: 0, deprecated: 1, due: 2, conformant: 3 };\n const rows = [...ev.findings].sort(\n (a, b) =>\n (rank[a.status] ?? 9) - (rank[b.status] ?? 9) || a.effective.localeCompare(b.effective),\n );\n for (const r of rows.slice(0, 12)) {\n const when =\n r.status === \"violation\"\n ? `disallowed since ${r.effective}`\n : r.status === \"deprecated\"\n ? `deprecated since ${r.effective}${r.disallowEffective ? `, disallowed ${r.disallowEffective}` : \"\"}`\n : `due ${r.effective} (${r.monthsUntil} mo)`;\n lines.push(` [${r.status}] ${r.clause} · ${r.algorithm} ${r.file}:${r.line} — ${when}`);\n }\n if (rows.length > 12) lines.push(` … and ${rows.length - 12} more`);\n return lines.join(\"\\n\");\n}\n\n/** Outcome of {@link runHndlInit}: the scaffold plus where it should be written. */\nexport interface HndlInitResult {\n /** Absolute path the `hndl.yml` should be written to. */\n path: string;\n /** True when a file already exists there (the CLI refuses to overwrite). */\n exists: boolean;\n /** The generated `hndl.yml` content. */\n content: string;\n /** How many findings the seeding scan produced. */\n findingsScanned: number;\n /** How many distinct data-adjacent (config-scope, HNDL) findings seeded stubs. */\n seededFindings: number;\n}\n\n/**\n * Scaffold an `hndl.yml` for a repo (`qscan hndl init`). Runs a scan to seed the\n * template with detected data-adjacent findings, then returns the generated\n * content and its target path WITHOUT writing it - the CLI owns file I/O and the\n * refuse-to-overwrite decision.\n */\nexport async function runHndlInit(\n opts: Partial<QscanOptions> & { path: string },\n hooks: RunQscanHooks = {},\n): Promise<HndlInitResult> {\n const options: QscanOptions = { ...defaultOptions(), ...opts };\n const scanFn: ScanFn = hooks.scanFn ?? (options.parallel ? scanParallel : scan);\n const result = await scanFn(toScanOptions(options));\n\n const content = scaffoldHndlYaml(result.findings);\n const target = resolveHndlTarget(options.path);\n let exists = false;\n try {\n await stat(target);\n exists = true;\n } catch {\n exists = false;\n }\n const seededFindings = result.findings.filter(\n (f) => f.hndl && findingScope(f) === \"config\",\n ).length;\n return {\n path: target,\n exists,\n content,\n findingsScanned: result.findings.length,\n seededFindings,\n };\n}\n\n/** Resolve where `hndl init` writes: `<dir>/hndl.yml`, or an explicit `*.yml`. */\nfunction resolveHndlTarget(root: string): string {\n const base = nodePath.basename(root);\n if (base === HNDL_FILENAME || base.endsWith(\".yml\") || base.endsWith(\".yaml\")) {\n return nodePath.resolve(root);\n }\n return nodePath.resolve(root, HNDL_FILENAME);\n}\n\n/** Outcome of {@link runCryptoAgilityEmit}: the rendered manifest and the scan. */\nexport interface CryptoAgilityEmitResult {\n /** The scan result the manifest was derived from. */\n result: ScanResult;\n /** The pretty-printed crypto-agility manifest JSON (no trailing newline). */\n manifest: string;\n}\n\n/**\n * Emit a crypto-agility manifest for a repo (`qscan crypto-agility emit` /\n * `--crypto-agility`). Runs a scan and derives the manifest from its inventory +\n * CBOM. This is deliberately additive: it NEVER consults the severity threshold and\n * the CLI always exits 0 (publishing a posture manifest must not fail CI). The\n * generation timestamp is stamped here (the CLI runtime), keeping the core builder\n * pure. A `--policy` file overlays its `transitionDeadline`; `--attestation` records\n * a credential URL verbatim (never fetched); `--hybrid-kex` / `--no-hybrid-kex`\n * assert hybrid-KEX use.\n */\nexport async function runCryptoAgilityEmit(\n opts: Partial<QscanOptions> & { path: string },\n hooks: RunQscanHooks = {},\n): Promise<CryptoAgilityEmitResult> {\n const options: QscanOptions = { ...defaultOptions(), ...opts };\n const scanFn: ScanFn = hooks.scanFn ?? (options.parallel ? scanParallel : scan);\n const result = await scanFn(toScanOptions(options));\n\n let policy: CryptoPolicy | undefined;\n if (options.policy) {\n policy = parseCryptoPolicy(JSON.parse(await readFile(options.policy, \"utf8\")));\n }\n\n const manifest = buildCryptoAgilityManifest(result, {\n generatedAt: new Date().toISOString(),\n ...(options.attestation ? { attestationUrl: options.attestation } : {}),\n ...(options.hybridKexInUse !== undefined ? { hybridKexInUse: options.hybridKexInUse } : {}),\n ...(policy ? { policy } : {}),\n ...(process.env.GITHUB_REPOSITORY ? { repository: process.env.GITHUB_REPOSITORY } : {}),\n ...(process.env.GITHUB_SHA ? { commit: process.env.GITHUB_SHA } : {}),\n });\n return { result, manifest: JSON.stringify(manifest, null, 2) };\n}\n\n/**\n * Validate a LOCAL crypto-agility manifest file against the schema\n * (`qscan crypto-agility validate <file>`). Reads and parses the file, then defers\n * to core's {@link validateCryptoAgilityManifest}. Strictly offline: it never\n * fetches a URL (the attestation link and any remote manifest are a website-side\n * concern). Read / parse failures propagate to the CLI as an I/O error (exit 2); a\n * successfully-parsed but non-conforming manifest returns `{ valid: false }` and the\n * CLI exits non-zero.\n */\nexport async function runCryptoAgilityValidate(file: string): Promise<ManifestValidation> {\n const text = await readFile(file, \"utf8\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { valid: false, errors: [`not valid JSON: ${message}`] };\n }\n return validateCryptoAgilityManifest(parsed);\n}\n\n/** Rendering controls for {@link renderReport}. */\nexport interface RenderReportOptions {\n /** Emit raw ANSI color in the human report. Default: false. */\n color?: boolean;\n /** Omit code snippets from the JSON/SARIF report (`--no-snippets`). */\n redactSnippets?: boolean;\n /** How many findings the human report lists (`--top N`). */\n topN?: number;\n /** CNSA security tier for the migration-targets footer (`--tier`). */\n tier?: SecurityTier;\n /** Standards regime for the migration-targets footer (`--profile`). */\n profile?: string;\n /** Org cryptography policy for the evidence report's §4 verdicts (`--policy`). */\n policy?: CryptoPolicy;\n /** External CBOMs to merge into the `cbom` output (CycloneDX bom-link). */\n mergeCboms?: CycloneDxBom[];\n /** HNDL exposure analysis (`--hndl`); annotates JSON/SARIF/human output. */\n hndl?: HndlReport;\n}\n\n/** Render a scan result in the requested format. */\nexport function renderReport(\n result: ScanResult,\n format: QscanOptions[\"format\"],\n opts: RenderReportOptions | boolean = {},\n): string {\n // Back-compat: `renderReport(result, format, true)` used to mean \"color on\".\n const {\n color = false,\n redactSnippets = false,\n topN = undefined,\n tier = undefined,\n profile = undefined,\n policy = undefined,\n mergeCboms = undefined,\n hndl = undefined,\n } = typeof opts === \"boolean\" ? { color: opts, policy: undefined } : opts;\n switch (format) {\n case \"json\":\n return renderJson(result, { redactSnippets, ...(hndl ? { hndl } : {}) });\n case \"sarif\":\n return renderSarif(result, { redactSnippets, ...(hndl ? { hndl } : {}) });\n case \"cbom\":\n return renderCbom(result, mergeCboms);\n case \"vex\":\n return renderVex(result);\n case \"evidence\": {\n // ISO A.8.24 readiness report; repo/commit come from CI env when present.\n // A `--policy` file adds the §4 conformant/violation/transition verdicts. The\n // attestation is left unsigned here; signing is an async step in runQscan (an\n // external signer may be async), so this renderer stays synchronous.\n const report = buildReadinessReport(result, {\n repository: process.env.GITHUB_REPOSITORY,\n commit: process.env.GITHUB_SHA,\n ...(policy ? { policy } : {}),\n });\n return JSON.stringify(report, null, 2);\n }\n case \"human\":\n default:\n return renderHuman(result, { color, topN, tier, profile, ...(hndl ? { hndl } : {}) });\n }\n}\n\n/** Re-export the core result types consumers commonly need. */\nexport type { Finding, ScanResult, ScanOptions } from \"@quantakrypto/core\";\n"]} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAkBH,OAAO,KAAK,EACV,YAAY,EAEZ,UAAU,EACV,aAAa,EACb,UAAU,EACV,YAAY,EAGb,MAAM,oBAAoB,CAAC;AAqC5B;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAE3E;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAS5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,GAAE,SAAS,YAAY,EAAO,GAAG,MAAM,CAI1F;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAClB,IAAI,GAAE;IACJ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,UAAU,CAAC;CACd,GACL,MAAM,CAsIR"} | ||
| {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAoBH,OAAO,KAAK,EACV,YAAY,EAEZ,UAAU,EACV,aAAa,EACb,UAAU,EACV,YAAY,EAGb,MAAM,oBAAoB,CAAC;AAqC5B;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAE3E;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAkB5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,GAAE,SAAS,YAAY,EAAO,GAAG,MAAM,CAI1F;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAClB,IAAI,GAAE;IACJ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,UAAU,CAAC;CACd,GACL,MAAM,CAsIR"} |
+11
-2
@@ -13,3 +13,3 @@ /** | ||
| */ | ||
| import { ANALYZABLE_LANGUAGES_LABEL, defaultRegistry, DEP_VULNERABLE_RULE, formatProfileGuidance, getStandardsProfile, PQC_TRANSITION_NOTE, SEVERITY_ORDER, severityRank, STATEFUL_HBS_NOTE, toCbom, toJson, toOpenVex, toSarif, mergeCboms, } from "@quantakrypto/core"; | ||
| import { ANALYZABLE_LANGUAGES_LABEL, defaultRegistry, DEP_ADVISORY_RULE, DEP_VULNERABLE_RULE, formatProfileGuidance, PROVENANCE_RULES, getStandardsProfile, PQC_TRANSITION_NOTE, SEVERITY_ORDER, severityRank, STATEFUL_HBS_NOTE, toCbom, toJson, toOpenVex, toSarif, mergeCboms, } from "@quantakrypto/core"; | ||
| /** Map the legacy `--tier` to its equivalent standards profile (back-compat alias). */ | ||
@@ -61,3 +61,12 @@ const TIER_TO_PROFILE = { | ||
| // into the shared rule description. | ||
| const catalog = [...defaultRegistry.ruleCatalog(), DEP_VULNERABLE_RULE]; | ||
| // `dep-advisory` (from `--audit`'s advisory scan) and the two `provenance-*` | ||
| // rules likewise come from scanners rather than Detectors, so add their generic | ||
| // catalog entries too — otherwise SARIF would synthesise each from the first | ||
| // finding and leak one advisory's specifics into the shared rule description. | ||
| const catalog = [ | ||
| ...defaultRegistry.ruleCatalog(), | ||
| DEP_VULNERABLE_RULE, | ||
| DEP_ADVISORY_RULE, | ||
| ...PROVENANCE_RULES, | ||
| ]; | ||
| return JSON.stringify(toSarif(result, { catalog, ...opts }), null, 2); | ||
@@ -64,0 +73,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * qScan report rendering.\n *\n * Produces the three output formats the CLI supports:\n * - `human` — a tasteful plain-text banner (counts, top findings, readiness\n * score, and a one-line next step). Optional raw ANSI color.\n * - `json` — the structured scan result via core's `toJson`.\n * - `sarif` — SARIF 2.1.0 via core's `toSarif`.\n *\n * Only `human` lives here; `json`/`sarif` delegate to `@quantakrypto/core` so the\n * serialized shape stays consistent across every tool in the monorepo.\n */\n\nimport {\n ANALYZABLE_LANGUAGES_LABEL,\n defaultRegistry,\n DEP_VULNERABLE_RULE,\n formatProfileGuidance,\n getStandardsProfile,\n PQC_TRANSITION_NOTE,\n SEVERITY_ORDER,\n severityRank,\n STATEFUL_HBS_NOTE,\n toCbom,\n toJson,\n toOpenVex,\n toSarif,\n mergeCboms,\n} from \"@quantakrypto/core\";\nimport type {\n CycloneDxBom,\n Finding,\n HndlReport,\n ReportOptions,\n ScanResult,\n SecurityTier,\n Severity,\n StandardsProfile,\n} from \"@quantakrypto/core\";\n\n/** Map the legacy `--tier` to its equivalent standards profile (back-compat alias). */\nconst TIER_TO_PROFILE: Record<SecurityTier, string> = {\n \"category-3\": \"nist\",\n \"category-5\": \"cnsa-2.0\",\n};\n\n/** Resolve the effective standards profile from `--profile` or the `--tier` alias. */\nfunction resolveProfile(profileId?: string, tier?: SecurityTier): StandardsProfile | undefined {\n if (profileId) return getStandardsProfile(profileId);\n if (tier) return getStandardsProfile(TIER_TO_PROFILE[tier]);\n return undefined;\n}\n\n/** Minimal ANSI palette. Empty strings when color is disabled. */\ninterface Palette {\n reset: string;\n bold: string;\n dim: string;\n red: string;\n yellow: string;\n green: string;\n cyan: string;\n}\n\nconst PLAIN: Palette = { reset: \"\", bold: \"\", dim: \"\", red: \"\", yellow: \"\", green: \"\", cyan: \"\" };\nconst COLOR: Palette = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n red: \"\\x1b[31m\",\n yellow: \"\\x1b[33m\",\n green: \"\\x1b[32m\",\n cyan: \"\\x1b[36m\",\n};\n\n/**\n * Render the JSON report (pretty-printed, no trailing newline).\n *\n * Delegates to core's `toJson` for a monorepo-consistent shape. `opts` is passed\n * straight through (e.g. `{ redactSnippets: true }` for `--no-snippets`).\n */\nexport function renderJson(result: ScanResult, opts?: ReportOptions): string {\n return JSON.stringify(toJson(result, opts), null, 2);\n}\n\n/**\n * Render the SARIF 2.1.0 report (pretty-printed, no trailing newline).\n *\n * Delegates to core's `toSarif` — the monorepo's single source of truth for the\n * SARIF shape (schema, tool driver, rules, taxonomies). `opts` is passed through\n * (e.g. `{ redactSnippets: true }` for `--no-snippets`).\n */\nexport function renderSarif(result: ScanResult, opts?: ReportOptions): string {\n // Advertise the full rule catalog (not just the rules that fired) so SARIF\n // consumers see complete metadata for every rule qScan can emit. The detector\n // registry's catalog is source/config rules only; `dep-vulnerable` comes from\n // the manifest scanner, so add its generic entry — otherwise SARIF would build\n // that rule from the first dependency finding and leak one package's specifics\n // into the shared rule description.\n const catalog = [...defaultRegistry.ruleCatalog(), DEP_VULNERABLE_RULE];\n return JSON.stringify(toSarif(result, { catalog, ...opts }), null, 2);\n}\n\n/**\n * Render a CycloneDX 1.6 CBOM (cryptographic bill of materials) for the scan,\n * pretty-printed with no trailing newline. Delegates to core's `toCbom` so the\n * serialized shape stays consistent across every tool in the monorepo.\n *\n * When `extra` CBOMs are supplied (e.g. a qProbe endpoint CBOM), they are merged\n * with the scan CBOM via core's `mergeCboms`, producing a single combined\n * code + infrastructure bill of materials linked by CycloneDX bom-link.\n */\nexport function renderCbom(result: ScanResult, extra: readonly CycloneDxBom[] = []): string {\n const scanBom = toCbom(result);\n const bom = extra.length > 0 ? mergeCboms([scanBom, ...extra]) : scanBom;\n return JSON.stringify(bom, null, 2);\n}\n\n/**\n * Render an OpenVEX 0.2.0 document for the scan (pretty-printed, no trailing\n * newline). Delegates to core's `toOpenVex` so the VEX shape stays consistent\n * across the monorepo. Carries any `--triage` verdicts into `status_notes`.\n */\nexport function renderVex(result: ScanResult): string {\n return JSON.stringify(toOpenVex(result), null, 2);\n}\n\n/**\n * Render the human-readable banner.\n *\n * @param result The scan result.\n * @param opts.color Emit raw ANSI escapes (default: false / plain text).\n * @param opts.topN How many findings to list (default: 5).\n */\nexport function renderHuman(\n result: ScanResult,\n opts: {\n color?: boolean;\n topN?: number;\n tier?: SecurityTier;\n profile?: string;\n hndl?: HndlReport;\n } = {},\n): string {\n const c = opts.color ? COLOR : PLAIN;\n const topN = opts.topN ?? 5;\n const { findings, inventory, filesScanned } = result;\n // `analyzedFiles`: of the scanned files, how many were in a language the\n // scanner can actually inspect for crypto (JS/TS, Python, Go, Java). When it's 0 the\n // readiness score reflects no analyzable code — say so rather than imply safe.\n const analyzedFiles = result.analyzedFiles;\n const noAnalyzable = analyzedFiles === 0;\n // Partial-coverage honesty: when the analyzable subset is only a small slice of\n // what was scanned, a high score reflects that slice, not the whole tree. We\n // surface a one-line caveat next to the score so the number isn't over-trusted.\n // Skips the zero case (handled explicitly below) and normal repos where most\n // files are analyzable.\n const lowCoverage =\n analyzedFiles !== undefined &&\n analyzedFiles > 0 &&\n filesScanned > 0 &&\n analyzedFiles / filesScanned < 0.25;\n const coverageCaveat = lowCoverage\n ? `${c.dim}Note: the score covers only ${analyzedFiles} analyzable of ${filesScanned} scanned files (${ANALYZABLE_LANGUAGES_LABEL}); crypto in unsupported languages is not reflected.${c.reset}`\n : \"\";\n const lines: string[] = [];\n\n lines.push(`${c.bold}qScan — quantum-vulnerable cryptography report${c.reset}`);\n const coverage =\n analyzedFiles === undefined\n ? \"\"\n : ` • analyzed: ${analyzedFiles} (${ANALYZABLE_LANGUAGES_LABEL})`;\n lines.push(\n `${c.dim}root: ${result.root} • files scanned: ${filesScanned}${coverage} • qscan v${result.toolVersion}${c.reset}`,\n );\n // Coverage diagnostics: warn when files were skipped, so a low finding count\n // isn't mistaken for a clean scan of the whole tree.\n const diag = result.diagnostics;\n if (diag && (diag.unreadable > 0 || diag.skippedMinified > 0)) {\n const parts: string[] = [];\n if (diag.unreadable > 0) parts.push(`${diag.unreadable} unreadable`);\n if (diag.skippedMinified > 0) parts.push(`${diag.skippedMinified} skipped (minified)`);\n lines.push(`${c.yellow}Coverage: ${parts.join(\", \")} — results may be incomplete.${c.reset}`);\n }\n lines.push(\"\");\n\n if (findings.length === 0) {\n if (noAnalyzable && filesScanned > 0) {\n // Honesty guard: don't let a 100/100 read as \"safe\" when nothing the\n // scanner understands was analyzed — the crypto may live in an\n // unsupported language (Go, Java, Rust, C#, …).\n lines.push(\n `${c.yellow}No analyzable source found.${c.reset} Scanned ${filesScanned} file${\n filesScanned === 1 ? \"\" : \"s\"\n }, but none were in a supported language (${ANALYZABLE_LANGUAGES_LABEL}).`,\n );\n lines.push(\n `${c.dim}The score below covers only what qScan can read today — it is NOT a clean bill of health for this codebase.${c.reset}`,\n );\n lines.push(\n `${c.bold}Readiness score: ${readiness(inventory.readinessScore, c)}/100 (no analyzable source)${c.reset}`,\n );\n lines.push(\"\");\n lines.push(\n `${c.dim}Next step:${c.reset} multi-language support is expanding; track coverage before relying on the score.`,\n );\n return lines.join(\"\\n\");\n }\n lines.push(`${c.green}No quantum-vulnerable cryptography detected.${c.reset}`);\n lines.push(`${c.bold}Readiness score: ${readiness(inventory.readinessScore, c)}/100${c.reset}`);\n if (coverageCaveat) lines.push(coverageCaveat);\n lines.push(\"\");\n lines.push(`${c.dim}Next step:${c.reset} keep scanning in CI to catch regressions.`);\n return lines.join(\"\\n\");\n }\n\n // Severity counts, most-severe first.\n const counts = SEVERITY_ORDER.map((sev) => {\n const n = inventory.bySeverity[sev] ?? 0;\n return n > 0 ? `${severityColor(sev, c)}${n} ${sev}${c.reset}` : null;\n }).filter((s): s is string => s !== null);\n\n lines.push(\n `${c.bold}${findings.length} finding${findings.length === 1 ? \"\" : \"s\"}${c.reset} (${counts.join(\", \")})`,\n );\n if (inventory.hndlCount > 0) {\n lines.push(\n `${c.yellow}${inventory.hndlCount}${c.reset} exposed to harvest-now-decrypt-later (HNDL).`,\n );\n }\n lines.push(`${c.bold}Readiness score: ${readiness(inventory.readinessScore, c)}/100${c.reset}`);\n if (coverageCaveat) lines.push(coverageCaveat);\n lines.push(\"\");\n\n // Top findings, sorted by severity then file/line for determinism.\n const top = [...findings].sort(compareFindings).slice(0, topN);\n lines.push(`${c.bold}Top findings${c.reset}`);\n for (const f of top) {\n const loc = `${f.location.file}:${f.location.line}`;\n lines.push(\n ` ${severityColor(f.severity, c)}${f.severity.padEnd(8)}${c.reset} ${c.cyan}${f.ruleId}${c.reset} ${loc}`,\n );\n lines.push(` ${f.message}`);\n if (f.remediation) {\n lines.push(` ${c.dim}→ ${f.remediation}${c.reset}`);\n }\n }\n if (findings.length > top.length) {\n lines.push(` ${c.dim}…and ${findings.length - top.length} more${c.reset}`);\n }\n lines.push(\"\");\n lines.push(`${c.dim}Next step:${c.reset} ${nextStep(findings)}`);\n\n // Regime-tailored migration targets (`--profile`, or the `--tier` alias). Surfaces\n // the parameter sets AND the regime's hybrid stance so guidance isn't regime-wrong.\n const profile = resolveProfile(opts.profile, opts.tier);\n if (profile) {\n lines.push(\"\");\n const g = formatProfileGuidance(inventory.byAlgorithm, profile);\n lines.push(`${c.bold}${g[0]}${c.reset}`);\n for (const t of g.slice(1)) lines.push(`${c.cyan}${t}${c.reset}`);\n }\n\n // HNDL exposure ranking (`--hndl`): the risk-ranked view that reorders the\n // backlog by real exposure rather than finding count.\n if (opts.hndl) lines.push(\"\", ...hndlSection(opts.hndl, c));\n\n // Forward-looking standards + the IR 8547 migration deadline (HQC / FN-DSA /\n // X-Wing) — the long-horizon guidance behind anything flagged above.\n lines.push(\"\");\n lines.push(`${c.bold}Standards & timeline${c.reset}`);\n lines.push(`${c.dim}${PQC_TRANSITION_NOTE}${c.reset}`);\n if (findings.some((f) => f.category === \"signature\")) {\n lines.push(`${c.dim}${STATEFUL_HBS_NOTE}${c.reset}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Render the HNDL exposure section for the human report. */\nfunction hndlSection(hndl: HndlReport, c: Palette): string[] {\n const s = hndl.summary;\n const out: string[] = [`${c.bold}HNDL exposure${c.reset}`];\n out.push(\n `${c.dim}horizon: quantum threat ${hndl.horizon.quantumThreatYears}y · migration ${hndl.horizon.migrationHorizonYears}y · model v${hndl.modelVersion}${c.reset}`,\n );\n out.push(\n `max exposure ${exposureColor(s.maxExposure, c)}${s.maxExposure}/100${c.reset} • mean ${s.meanExposure}/100 • ${s.moscaBreaches} finding(s) breach Mosca's inequality`,\n );\n if (s.assetsDeclared > 0) {\n out.push(\n `${c.dim}${s.assetsWithFindings}/${s.assetsDeclared} declared assets carry findings; ${s.assetsOutlivingHorizon} have secrecy outliving the threat horizon.${c.reset}`,\n );\n }\n if (s.topExposures.length > 0) {\n out.push(`${c.bold}Top exposures${c.reset}`);\n for (const e of s.topExposures) {\n const asset = e.dataAsset ? e.dataAsset : `${c.dim}(unbound)${c.reset}`;\n out.push(\n ` ${exposureColor(e.exposureScore, c)}${String(e.exposureScore).padStart(3)}${c.reset} ${c.cyan}${e.ruleId}${c.reset} ${e.file} → ${asset}`,\n );\n }\n }\n return out;\n}\n\n/** Color an exposure score red/yellow/dim by band. */\nfunction exposureColor(score: number, c: Palette): string {\n return score >= 50 ? c.red : score >= 20 ? c.yellow : c.dim;\n}\n\n/** Suggest a single concrete next action based on the worst finding. */\nfunction nextStep(findings: Finding[]): string {\n const worst = [...findings].sort(compareFindings)[0];\n if (!worst) return \"review the findings above.\";\n // A dependency finding points at a manifest — you replace the *package*, not\n // \"migrate package.json\". Phrase it as a dependency swap.\n if (worst.category === \"dependency\") {\n return worst.remediation\n ? `replace the vulnerable dependency in ${worst.location.file} — ${worst.remediation}`\n : `replace the vulnerable dependency in ${worst.location.file}.`;\n }\n if (worst.remediation) {\n return `migrate ${worst.location.file} — ${worst.remediation}`;\n }\n return `triage ${worst.ruleId} in ${worst.location.file}:${worst.location.line}.`;\n}\n\n/** Deterministic ordering: most severe first, then file, then line. */\nfunction compareFindings(a: Finding, b: Finding): number {\n const bySev = severityRank(a.severity) - severityRank(b.severity);\n if (bySev !== 0) return bySev;\n const byFile = a.location.file.localeCompare(b.location.file);\n if (byFile !== 0) return byFile;\n return a.location.line - b.location.line;\n}\n\n/** Color the readiness score green/yellow/red by band. */\nfunction readiness(score: number, c: Palette): string {\n const color = score >= 80 ? c.green : score >= 50 ? c.yellow : c.red;\n return `${color}${score}${c.reset}`;\n}\n\n/** Map a severity to its palette color. */\nfunction severityColor(severity: Severity, c: Palette): string {\n switch (severity) {\n case \"critical\":\n case \"high\":\n return c.red;\n case \"medium\":\n return c.yellow;\n default:\n return c.dim;\n }\n}\n"]} | ||
| {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * qScan report rendering.\n *\n * Produces the three output formats the CLI supports:\n * - `human` — a tasteful plain-text banner (counts, top findings, readiness\n * score, and a one-line next step). Optional raw ANSI color.\n * - `json` — the structured scan result via core's `toJson`.\n * - `sarif` — SARIF 2.1.0 via core's `toSarif`.\n *\n * Only `human` lives here; `json`/`sarif` delegate to `@quantakrypto/core` so the\n * serialized shape stays consistent across every tool in the monorepo.\n */\n\nimport {\n ANALYZABLE_LANGUAGES_LABEL,\n defaultRegistry,\n DEP_ADVISORY_RULE,\n DEP_VULNERABLE_RULE,\n formatProfileGuidance,\n PROVENANCE_RULES,\n getStandardsProfile,\n PQC_TRANSITION_NOTE,\n SEVERITY_ORDER,\n severityRank,\n STATEFUL_HBS_NOTE,\n toCbom,\n toJson,\n toOpenVex,\n toSarif,\n mergeCboms,\n} from \"@quantakrypto/core\";\nimport type {\n CycloneDxBom,\n Finding,\n HndlReport,\n ReportOptions,\n ScanResult,\n SecurityTier,\n Severity,\n StandardsProfile,\n} from \"@quantakrypto/core\";\n\n/** Map the legacy `--tier` to its equivalent standards profile (back-compat alias). */\nconst TIER_TO_PROFILE: Record<SecurityTier, string> = {\n \"category-3\": \"nist\",\n \"category-5\": \"cnsa-2.0\",\n};\n\n/** Resolve the effective standards profile from `--profile` or the `--tier` alias. */\nfunction resolveProfile(profileId?: string, tier?: SecurityTier): StandardsProfile | undefined {\n if (profileId) return getStandardsProfile(profileId);\n if (tier) return getStandardsProfile(TIER_TO_PROFILE[tier]);\n return undefined;\n}\n\n/** Minimal ANSI palette. Empty strings when color is disabled. */\ninterface Palette {\n reset: string;\n bold: string;\n dim: string;\n red: string;\n yellow: string;\n green: string;\n cyan: string;\n}\n\nconst PLAIN: Palette = { reset: \"\", bold: \"\", dim: \"\", red: \"\", yellow: \"\", green: \"\", cyan: \"\" };\nconst COLOR: Palette = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n red: \"\\x1b[31m\",\n yellow: \"\\x1b[33m\",\n green: \"\\x1b[32m\",\n cyan: \"\\x1b[36m\",\n};\n\n/**\n * Render the JSON report (pretty-printed, no trailing newline).\n *\n * Delegates to core's `toJson` for a monorepo-consistent shape. `opts` is passed\n * straight through (e.g. `{ redactSnippets: true }` for `--no-snippets`).\n */\nexport function renderJson(result: ScanResult, opts?: ReportOptions): string {\n return JSON.stringify(toJson(result, opts), null, 2);\n}\n\n/**\n * Render the SARIF 2.1.0 report (pretty-printed, no trailing newline).\n *\n * Delegates to core's `toSarif` — the monorepo's single source of truth for the\n * SARIF shape (schema, tool driver, rules, taxonomies). `opts` is passed through\n * (e.g. `{ redactSnippets: true }` for `--no-snippets`).\n */\nexport function renderSarif(result: ScanResult, opts?: ReportOptions): string {\n // Advertise the full rule catalog (not just the rules that fired) so SARIF\n // consumers see complete metadata for every rule qScan can emit. The detector\n // registry's catalog is source/config rules only; `dep-vulnerable` comes from\n // the manifest scanner, so add its generic entry — otherwise SARIF would build\n // that rule from the first dependency finding and leak one package's specifics\n // into the shared rule description.\n // `dep-advisory` (from `--audit`'s advisory scan) and the two `provenance-*`\n // rules likewise come from scanners rather than Detectors, so add their generic\n // catalog entries too — otherwise SARIF would synthesise each from the first\n // finding and leak one advisory's specifics into the shared rule description.\n const catalog = [\n ...defaultRegistry.ruleCatalog(),\n DEP_VULNERABLE_RULE,\n DEP_ADVISORY_RULE,\n ...PROVENANCE_RULES,\n ];\n return JSON.stringify(toSarif(result, { catalog, ...opts }), null, 2);\n}\n\n/**\n * Render a CycloneDX 1.6 CBOM (cryptographic bill of materials) for the scan,\n * pretty-printed with no trailing newline. Delegates to core's `toCbom` so the\n * serialized shape stays consistent across every tool in the monorepo.\n *\n * When `extra` CBOMs are supplied (e.g. a qProbe endpoint CBOM), they are merged\n * with the scan CBOM via core's `mergeCboms`, producing a single combined\n * code + infrastructure bill of materials linked by CycloneDX bom-link.\n */\nexport function renderCbom(result: ScanResult, extra: readonly CycloneDxBom[] = []): string {\n const scanBom = toCbom(result);\n const bom = extra.length > 0 ? mergeCboms([scanBom, ...extra]) : scanBom;\n return JSON.stringify(bom, null, 2);\n}\n\n/**\n * Render an OpenVEX 0.2.0 document for the scan (pretty-printed, no trailing\n * newline). Delegates to core's `toOpenVex` so the VEX shape stays consistent\n * across the monorepo. Carries any `--triage` verdicts into `status_notes`.\n */\nexport function renderVex(result: ScanResult): string {\n return JSON.stringify(toOpenVex(result), null, 2);\n}\n\n/**\n * Render the human-readable banner.\n *\n * @param result The scan result.\n * @param opts.color Emit raw ANSI escapes (default: false / plain text).\n * @param opts.topN How many findings to list (default: 5).\n */\nexport function renderHuman(\n result: ScanResult,\n opts: {\n color?: boolean;\n topN?: number;\n tier?: SecurityTier;\n profile?: string;\n hndl?: HndlReport;\n } = {},\n): string {\n const c = opts.color ? COLOR : PLAIN;\n const topN = opts.topN ?? 5;\n const { findings, inventory, filesScanned } = result;\n // `analyzedFiles`: of the scanned files, how many were in a language the\n // scanner can actually inspect for crypto (JS/TS, Python, Go, Java). When it's 0 the\n // readiness score reflects no analyzable code — say so rather than imply safe.\n const analyzedFiles = result.analyzedFiles;\n const noAnalyzable = analyzedFiles === 0;\n // Partial-coverage honesty: when the analyzable subset is only a small slice of\n // what was scanned, a high score reflects that slice, not the whole tree. We\n // surface a one-line caveat next to the score so the number isn't over-trusted.\n // Skips the zero case (handled explicitly below) and normal repos where most\n // files are analyzable.\n const lowCoverage =\n analyzedFiles !== undefined &&\n analyzedFiles > 0 &&\n filesScanned > 0 &&\n analyzedFiles / filesScanned < 0.25;\n const coverageCaveat = lowCoverage\n ? `${c.dim}Note: the score covers only ${analyzedFiles} analyzable of ${filesScanned} scanned files (${ANALYZABLE_LANGUAGES_LABEL}); crypto in unsupported languages is not reflected.${c.reset}`\n : \"\";\n const lines: string[] = [];\n\n lines.push(`${c.bold}qScan — quantum-vulnerable cryptography report${c.reset}`);\n const coverage =\n analyzedFiles === undefined\n ? \"\"\n : ` • analyzed: ${analyzedFiles} (${ANALYZABLE_LANGUAGES_LABEL})`;\n lines.push(\n `${c.dim}root: ${result.root} • files scanned: ${filesScanned}${coverage} • qscan v${result.toolVersion}${c.reset}`,\n );\n // Coverage diagnostics: warn when files were skipped, so a low finding count\n // isn't mistaken for a clean scan of the whole tree.\n const diag = result.diagnostics;\n if (diag && (diag.unreadable > 0 || diag.skippedMinified > 0)) {\n const parts: string[] = [];\n if (diag.unreadable > 0) parts.push(`${diag.unreadable} unreadable`);\n if (diag.skippedMinified > 0) parts.push(`${diag.skippedMinified} skipped (minified)`);\n lines.push(`${c.yellow}Coverage: ${parts.join(\", \")} — results may be incomplete.${c.reset}`);\n }\n lines.push(\"\");\n\n if (findings.length === 0) {\n if (noAnalyzable && filesScanned > 0) {\n // Honesty guard: don't let a 100/100 read as \"safe\" when nothing the\n // scanner understands was analyzed — the crypto may live in an\n // unsupported language (Go, Java, Rust, C#, …).\n lines.push(\n `${c.yellow}No analyzable source found.${c.reset} Scanned ${filesScanned} file${\n filesScanned === 1 ? \"\" : \"s\"\n }, but none were in a supported language (${ANALYZABLE_LANGUAGES_LABEL}).`,\n );\n lines.push(\n `${c.dim}The score below covers only what qScan can read today — it is NOT a clean bill of health for this codebase.${c.reset}`,\n );\n lines.push(\n `${c.bold}Readiness score: ${readiness(inventory.readinessScore, c)}/100 (no analyzable source)${c.reset}`,\n );\n lines.push(\"\");\n lines.push(\n `${c.dim}Next step:${c.reset} multi-language support is expanding; track coverage before relying on the score.`,\n );\n return lines.join(\"\\n\");\n }\n lines.push(`${c.green}No quantum-vulnerable cryptography detected.${c.reset}`);\n lines.push(`${c.bold}Readiness score: ${readiness(inventory.readinessScore, c)}/100${c.reset}`);\n if (coverageCaveat) lines.push(coverageCaveat);\n lines.push(\"\");\n lines.push(`${c.dim}Next step:${c.reset} keep scanning in CI to catch regressions.`);\n return lines.join(\"\\n\");\n }\n\n // Severity counts, most-severe first.\n const counts = SEVERITY_ORDER.map((sev) => {\n const n = inventory.bySeverity[sev] ?? 0;\n return n > 0 ? `${severityColor(sev, c)}${n} ${sev}${c.reset}` : null;\n }).filter((s): s is string => s !== null);\n\n lines.push(\n `${c.bold}${findings.length} finding${findings.length === 1 ? \"\" : \"s\"}${c.reset} (${counts.join(\", \")})`,\n );\n if (inventory.hndlCount > 0) {\n lines.push(\n `${c.yellow}${inventory.hndlCount}${c.reset} exposed to harvest-now-decrypt-later (HNDL).`,\n );\n }\n lines.push(`${c.bold}Readiness score: ${readiness(inventory.readinessScore, c)}/100${c.reset}`);\n if (coverageCaveat) lines.push(coverageCaveat);\n lines.push(\"\");\n\n // Top findings, sorted by severity then file/line for determinism.\n const top = [...findings].sort(compareFindings).slice(0, topN);\n lines.push(`${c.bold}Top findings${c.reset}`);\n for (const f of top) {\n const loc = `${f.location.file}:${f.location.line}`;\n lines.push(\n ` ${severityColor(f.severity, c)}${f.severity.padEnd(8)}${c.reset} ${c.cyan}${f.ruleId}${c.reset} ${loc}`,\n );\n lines.push(` ${f.message}`);\n if (f.remediation) {\n lines.push(` ${c.dim}→ ${f.remediation}${c.reset}`);\n }\n }\n if (findings.length > top.length) {\n lines.push(` ${c.dim}…and ${findings.length - top.length} more${c.reset}`);\n }\n lines.push(\"\");\n lines.push(`${c.dim}Next step:${c.reset} ${nextStep(findings)}`);\n\n // Regime-tailored migration targets (`--profile`, or the `--tier` alias). Surfaces\n // the parameter sets AND the regime's hybrid stance so guidance isn't regime-wrong.\n const profile = resolveProfile(opts.profile, opts.tier);\n if (profile) {\n lines.push(\"\");\n const g = formatProfileGuidance(inventory.byAlgorithm, profile);\n lines.push(`${c.bold}${g[0]}${c.reset}`);\n for (const t of g.slice(1)) lines.push(`${c.cyan}${t}${c.reset}`);\n }\n\n // HNDL exposure ranking (`--hndl`): the risk-ranked view that reorders the\n // backlog by real exposure rather than finding count.\n if (opts.hndl) lines.push(\"\", ...hndlSection(opts.hndl, c));\n\n // Forward-looking standards + the IR 8547 migration deadline (HQC / FN-DSA /\n // X-Wing) — the long-horizon guidance behind anything flagged above.\n lines.push(\"\");\n lines.push(`${c.bold}Standards & timeline${c.reset}`);\n lines.push(`${c.dim}${PQC_TRANSITION_NOTE}${c.reset}`);\n if (findings.some((f) => f.category === \"signature\")) {\n lines.push(`${c.dim}${STATEFUL_HBS_NOTE}${c.reset}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Render the HNDL exposure section for the human report. */\nfunction hndlSection(hndl: HndlReport, c: Palette): string[] {\n const s = hndl.summary;\n const out: string[] = [`${c.bold}HNDL exposure${c.reset}`];\n out.push(\n `${c.dim}horizon: quantum threat ${hndl.horizon.quantumThreatYears}y · migration ${hndl.horizon.migrationHorizonYears}y · model v${hndl.modelVersion}${c.reset}`,\n );\n out.push(\n `max exposure ${exposureColor(s.maxExposure, c)}${s.maxExposure}/100${c.reset} • mean ${s.meanExposure}/100 • ${s.moscaBreaches} finding(s) breach Mosca's inequality`,\n );\n if (s.assetsDeclared > 0) {\n out.push(\n `${c.dim}${s.assetsWithFindings}/${s.assetsDeclared} declared assets carry findings; ${s.assetsOutlivingHorizon} have secrecy outliving the threat horizon.${c.reset}`,\n );\n }\n if (s.topExposures.length > 0) {\n out.push(`${c.bold}Top exposures${c.reset}`);\n for (const e of s.topExposures) {\n const asset = e.dataAsset ? e.dataAsset : `${c.dim}(unbound)${c.reset}`;\n out.push(\n ` ${exposureColor(e.exposureScore, c)}${String(e.exposureScore).padStart(3)}${c.reset} ${c.cyan}${e.ruleId}${c.reset} ${e.file} → ${asset}`,\n );\n }\n }\n return out;\n}\n\n/** Color an exposure score red/yellow/dim by band. */\nfunction exposureColor(score: number, c: Palette): string {\n return score >= 50 ? c.red : score >= 20 ? c.yellow : c.dim;\n}\n\n/** Suggest a single concrete next action based on the worst finding. */\nfunction nextStep(findings: Finding[]): string {\n const worst = [...findings].sort(compareFindings)[0];\n if (!worst) return \"review the findings above.\";\n // A dependency finding points at a manifest — you replace the *package*, not\n // \"migrate package.json\". Phrase it as a dependency swap.\n if (worst.category === \"dependency\") {\n return worst.remediation\n ? `replace the vulnerable dependency in ${worst.location.file} — ${worst.remediation}`\n : `replace the vulnerable dependency in ${worst.location.file}.`;\n }\n if (worst.remediation) {\n return `migrate ${worst.location.file} — ${worst.remediation}`;\n }\n return `triage ${worst.ruleId} in ${worst.location.file}:${worst.location.line}.`;\n}\n\n/** Deterministic ordering: most severe first, then file, then line. */\nfunction compareFindings(a: Finding, b: Finding): number {\n const bySev = severityRank(a.severity) - severityRank(b.severity);\n if (bySev !== 0) return bySev;\n const byFile = a.location.file.localeCompare(b.location.file);\n if (byFile !== 0) return byFile;\n return a.location.line - b.location.line;\n}\n\n/** Color the readiness score green/yellow/red by band. */\nfunction readiness(score: number, c: Palette): string {\n const color = score >= 80 ? c.green : score >= 50 ? c.yellow : c.red;\n return `${color}${score}${c.reset}`;\n}\n\n/** Map a severity to its palette color. */\nfunction severityColor(severity: Severity, c: Palette): string {\n switch (severity) {\n case \"critical\":\n case \"high\":\n return c.red;\n case \"medium\":\n return c.yellow;\n default:\n return c.dim;\n }\n}\n"]} |
+3
-3
| { | ||
| "name": "@quantakrypto/qscan", | ||
| "version": "0.7.0", | ||
| "version": "0.8.0", | ||
| "description": "qScan — find quantum-vulnerable cryptography in any codebase (CLI). Zero runtime dependencies.", | ||
@@ -40,4 +40,4 @@ "license": "Apache-2.0", | ||
| "dependencies": { | ||
| "@quantakrypto/agent": "0.7.0", | ||
| "@quantakrypto/core": "0.7.0" | ||
| "@quantakrypto/agent": "0.8.0", | ||
| "@quantakrypto/core": "0.8.0" | ||
| }, | ||
@@ -44,0 +44,0 @@ "scripts": { |
+47
-0
@@ -83,2 +83,3 @@ # @quantakrypto/qscan | ||
| | `--concurrency <n>` | Worker count for `--parallel` (implies `--parallel`). `0`/`1` forces serial. | CPU count | | ||
| | `--audit` | Opt-in supply-chain checks (see below): dependency advisories via each ecosystem's own audit tool, plus a declared-source-repository (provenance) check. Findings merge into the report and the exit code; a missing tool or network hiccup degrades to a stderr diagnostic. | off | | ||
| | `--triage` | BYOK LLM pass that re-ranks findings by real exposure and explains them. Never suppresses; never changes the exit code. Needs an API key. | off | | ||
@@ -201,2 +202,48 @@ | `--triage-floor <level>` | With `--triage`, only triage findings at/above this level. | `medium` | | ||
| ## Supply-chain audit (`--audit`, opt-in) | ||
| `--audit` layers three supply-chain checks on top of the normal scan. It is | ||
| **opt-in** because two of them shell out (dependency advisories) or make a network | ||
| request (provenance); a default `qscan .` stays offline. Every check **degrades | ||
| gracefully** — a missing tool, an unparseable output, or a network hiccup becomes | ||
| a `qscan: audit: …` diagnostic on stderr, never a hard failure. Any findings it | ||
| does produce merge into the report **and the exit code**, so a known-vulnerable | ||
| dependency can gate CI. | ||
| ```bash | ||
| qscan . --audit # add advisory + provenance checks | ||
| qscan . --audit --format sarif -o qscan.sarif | ||
| ``` | ||
| 1. **Dependency advisories.** For each ecosystem present at the scan root, qScan | ||
| runs that ecosystem's own audit tool and turns its advisories into | ||
| `dependency` findings (`ruleId: dep-advisory`, severity from the advisory, | ||
| `<pkg>@<ver>: <summary> (<ID>)`, remediation = the patched version): | ||
| - Rust — `Cargo.toml` / `Cargo.lock` → `cargo audit --json` | ||
| - Python — `requirements*.txt` / `pyproject.toml` → `pip-audit --format json` | ||
| - npm — `package-lock.json` → `npm audit --json` | ||
| The tool must be on `PATH`; if it is not, that ecosystem is skipped with a | ||
| diagnostic (`cargo audit not available, skipped`). This complements the | ||
| built-in **quantum-vulnerable-dependency** database (which flags packages whose | ||
| *purpose* is classical public-key crypto) with **known-CVE** coverage. | ||
| 2. **PQC parameter / size verification** *(a default detector, always on — not | ||
| gated behind `--audit`)*. Flags code that has already reached for a | ||
| post-quantum KEM but got it subtly wrong: a **pre-standard round-3 Kyber** | ||
| (`pqc_kyber`, `pqcrypto-kyber`, `Kyber768`, …) used where FIPS 203 ML-KEM is | ||
| intended (`pqc-prestandard-kem`, confidence raised when a FIPS-203/ML-KEM/NIST | ||
| claim is in the same file), and an **ML-KEM/Kyber byte size that names a | ||
| different parameter set** than the code advertises (`pqc-parameter-mismatch`, | ||
| conservative — fires only on an exact size against a conflicting advertised | ||
| level). | ||
| 3. **Provenance / declared source repository.** Reads the root manifest's | ||
| repository URL (`package.json` `repository`, `Cargo.toml` `repository`, | ||
| `pyproject.toml` `[project.urls]`). A manifest that declares **no** repository | ||
| yields an info finding (`provenance-repo-missing`); with `--audit`, a declared | ||
| URL that **404s or does not resolve** yields `provenance-repo-unresolved` | ||
| (medium). The HEAD request is the only network call qScan itself makes; | ||
| transient network errors are skipped silently. | ||
| ## CBOM (CycloneDX) | ||
@@ -203,0 +250,0 @@ |
Network access
Supply chain riskThis module accesses the network.
Found 2 instances
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
426872
4.97%55
7.84%3264
4.55%410
12.95%4
100%+ Added
+ Added
- Removed
- Removed
Updated
Updated