@quantakrypto/qscan
Advanced tools
+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 --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"; | ||
| 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. With\n --mandate, permitted/in-transition families are\n acknowledged and exempt from --fail-now/--lead-months\n (a passed disallow deadline still fails)\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 disallow deadline has passed\n (a passed deprecate date warns). The\n verdicts also ride in --format json (mandateMapping),\n sarif (run.properties.mandate), and evidence (hashed)\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,4sTA8IrB,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,isUAoJrB,CAAC;AAEF,4BAA4B;AAC5B,wBAAgB,WAAW,IAAI,MAAM,CAEpC"} |
+8
-2
@@ -35,3 +35,6 @@ /** | ||
| --policy <file> Crypto-policy JSON; adds conformant/violation/ | ||
| transition verdicts to the evidence report | ||
| transition verdicts to the evidence report. With | ||
| --mandate, permitted/in-transition families are | ||
| acknowledged and exempt from --fail-now/--lead-months | ||
| (a passed disallow deadline still fails) | ||
| --sign <command> Sign the evidence report: its contentHash is | ||
@@ -73,3 +76,6 @@ piped to <command> on stdin; stdout is recorded | ||
| each prohibited finding with its clause + deadline; | ||
| fails the build only once a deadline has passed | ||
| fails the build only once a disallow deadline has passed | ||
| (a passed deprecate date warns). The | ||
| verdicts also ride in --format json (mandateMapping), | ||
| sarif (run.properties.mandate), and evidence (hashed) | ||
| --lead-months <n> Fail early when a --mandate deadline is within n months | ||
@@ -76,0 +82,0 @@ --fail-now Fail on any --mandate-prohibited finding, ignoring the date |
+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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"]} | ||
| {"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoJxB,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. With\n --mandate, permitted/in-transition families are\n acknowledged and exempt from --fail-now/--lead-months\n (a passed disallow deadline still fails)\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 disallow deadline has passed\n (a passed deprecate date warns). The\n verdicts also ride in --format json (mandateMapping),\n sarif (run.properties.mandate), and evidence (hashed)\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"]} |
+8
-0
@@ -13,2 +13,3 @@ /** | ||
| import type { Baseline, CryptoPolicy, CycloneDxBom, Finding, HndlReport, ManifestValidation, ParallelScanOptions, ScanResult, SecurityTier } from "@quantakrypto/core"; | ||
| import type { MandateEvaluation } from "@quantakrypto/core"; | ||
| import type { QscanOptions } from "./args.js"; | ||
@@ -178,2 +179,9 @@ export type { QscanOptions, ParsedArgs, ParsedRun, QscanFormat } from "./args.js"; | ||
| hndl?: HndlReport; | ||
| /** | ||
| * Compliance-mandate evaluation (`--mandate`). Carried into the machine-readable | ||
| * JSON (`mandateMapping`), SARIF (`run.properties.mandate`), and evidence | ||
| * (date-pinned, hashed) output. The human block is appended separately by | ||
| * {@link runQscan}. | ||
| */ | ||
| mandate?: MandateEvaluation; | ||
| } | ||
@@ -180,0 +188,0 @@ /** Render a scan result in the requested format. */ |
@@ -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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"} |
+39
-10
@@ -161,8 +161,17 @@ /** | ||
| // mandate-prohibited finding with its named clause + deadline, but fails the build | ||
| // only once a deadline has passed (or early with --lead-months / --fail-now). Uses | ||
| // the same RAW findings as the exit code, so triage can never flip the gate. | ||
| // only once a deadline has passed (or early with --lead-months / --fail-now). | ||
| // | ||
| // Evaluated on the PRE-baseline findings (kept + suppressed), matching the GitHub | ||
| // Action: a `--baseline` accepts a finding for the SEVERITY gate, but a regulatory | ||
| // deadline must never be waivable by baselining — otherwise `--write-baseline` | ||
| // then `--baseline` would be a self-service deadline waiver. Triage runs later, so | ||
| // it can never flip the gate either. | ||
| let mandateEval; | ||
| if (options.mandates.length > 0) { | ||
| assertKnownMandates(options.mandates); | ||
| mandateEval = evaluateMandates(result.findings, options.mandates, new Date()); | ||
| // Compose the org `--policy` in when one was supplied: acknowledged families | ||
| // (permitted / in-transition) are annotated and exempt from the EARLY gates, | ||
| // though a passed DISALLOW deadline still fails. | ||
| const mandateFindings = [...result.findings, ...suppressed]; | ||
| mandateEval = evaluateMandates(mandateFindings, options.mandates, new Date(), policy); | ||
| if (mandateGateFails(mandateEval, { leadMonths: options.leadMonths, failNow: options.failNow })) { | ||
@@ -261,2 +270,5 @@ exitCode = EXIT.FINDINGS; | ||
| ...(hndl ? { hndl } : {}), | ||
| // The `--mandate` evaluation feeds the machine-readable JSON/SARIF/evidence | ||
| // output too (not just the human block appended below). | ||
| ...(mandateEval ? { mandate: mandateEval } : {}), | ||
| }); | ||
@@ -290,2 +302,6 @@ // Evidence signing is orchestrated here (async: an external signer may be async), | ||
| (ev.notInScope > 0 ? ` · ${ev.notInScope} out of scope` : "") + | ||
| // Policy composition: how many of the above the org is knowingly managing. | ||
| (ev.acknowledged > 0 | ||
| ? ` · ${ev.acknowledged} acknowledged${ev.policyName ? ` (${ev.policyName})` : ""}` | ||
| : "") + | ||
| (ev.nextDeadline ? ` · next deadline ${ev.nextDeadline}` : "")); | ||
@@ -300,3 +316,6 @@ const rank = { violation: 0, deprecated: 1, due: 2, conformant: 3 }; | ||
| : `due ${r.effective} (${r.monthsUntil} mo)`; | ||
| lines.push(` [${r.status}] ${r.clause} · ${r.algorithm} ${r.file}:${r.line} — ${when}`); | ||
| // Flag policy-acknowledged rows so the reader sees why the gate may not fire | ||
| // on them (exempt from --fail-now / --lead-months, never from a violation). | ||
| const ack = r.acknowledged ? ` · policy: ${r.policyVerdict ?? "acknowledged"}` : ""; | ||
| lines.push(` [${r.status}] ${r.clause} · ${r.algorithm} ${r.file}:${r.line} — ${when}${ack}`); | ||
| } | ||
@@ -396,8 +415,16 @@ if (rows.length > 12) | ||
| // Back-compat: `renderReport(result, format, true)` used to mean "color on". | ||
| const { color = false, redactSnippets = false, topN = undefined, tier = undefined, profile = undefined, policy = undefined, mergeCboms = undefined, hndl = undefined, } = typeof opts === "boolean" ? { color: opts, policy: undefined } : opts; | ||
| const { color = false, redactSnippets = false, topN = undefined, tier = undefined, profile = undefined, policy = undefined, mergeCboms = undefined, hndl = undefined, mandate = undefined, } = typeof opts === "boolean" ? { color: opts, policy: undefined } : opts; | ||
| switch (format) { | ||
| case "json": | ||
| return renderJson(result, { redactSnippets, ...(hndl ? { hndl } : {}) }); | ||
| return renderJson(result, { | ||
| redactSnippets, | ||
| ...(hndl ? { hndl } : {}), | ||
| ...(mandate ? { mandate } : {}), | ||
| }); | ||
| case "sarif": | ||
| return renderSarif(result, { redactSnippets, ...(hndl ? { hndl } : {}) }); | ||
| return renderSarif(result, { | ||
| redactSnippets, | ||
| ...(hndl ? { hndl } : {}), | ||
| ...(mandate ? { mandate } : {}), | ||
| }); | ||
| case "cbom": | ||
@@ -409,5 +436,6 @@ return renderCbom(result, mergeCboms); | ||
| // ISO A.8.24 readiness report; repo/commit come from CI env when present. | ||
| // A `--policy` file adds the §4 conformant/violation/transition verdicts. The | ||
| // attestation is left unsigned here; signing is an async step in runQscan (an | ||
| // external signer may be async), so this renderer stays synchronous. | ||
| // A `--policy` file adds the §4 conformant/violation/transition verdicts, and | ||
| // `--mandate` adds the date-pinned, hashed `mandateMapping`. The attestation | ||
| // is left unsigned here; signing is an async step in runQscan (an external | ||
| // signer may be async), so this renderer stays synchronous. | ||
| const report = buildReadinessReport(result, { | ||
@@ -417,2 +445,3 @@ repository: process.env.GITHUB_REPOSITORY, | ||
| ...(policy ? { policy } : {}), | ||
| ...(mandate ? { mandate } : {}), | ||
| }); | ||
@@ -419,0 +448,0 @@ return JSON.stringify(report, null, 2); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,QAAQ,MAAM,WAAW,CAAC;AACtC,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EACL,0BAA0B,EAC1B,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,eAAe,EACf,eAAe,EACf,WAAW,EACX,YAAY,EACZ,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,IAAI,EACJ,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,6BAA6B,GAC9B,MAAM,oBAAoB,CAAC;AAe5B,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI1F,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,UAAU,EACV,cAAc,EACd,cAAc,EACd,SAAS,EACT,YAAY,EACZ,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,cAAc,EACd,cAAc,GACf,MAAM,oBAAoB,CAAC;AAO5B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIzD,2CAA2C;AAC3C,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,iEAAiE;IACjE,EAAE,EAAE,CAAC;IACL,4DAA4D;IAC5D,QAAQ,EAAE,CAAC;IACX,kCAAkC;IAClC,KAAK,EAAE,CAAC;CACA,CAAC;AAiDX;;;GAGG;AACH,SAAS,aAAa,CAAC,OAAqB;IAC1C,MAAM,WAAW,GAAwB;QACvC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;QAC1C,YAAY,EAAE,OAAO,CAAC,YAAY;KACnC,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IACpE,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACtE,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS;QAAE,WAAW,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACrF,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS;QAAE,WAAW,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACrF,IAAI,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9D,WAAW,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IACpD,CAAC;IACD,IAAI,OAAO,CAAC,SAAS;QAAE,WAAW,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACjE,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAA8C,EAC9C,QAAuB,EAAE;IAEzB,MAAM,OAAO,GAAiB,EAAE,GAAG,cAAc,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;IAC/D,+EAA+E;IAC/E,MAAM,MAAM,GAAW,KAAK,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChF,MAAM,cAAc,GAAmB,KAAK,CAAC,cAAc,IAAI,YAAY,CAAC;IAE5E,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAE3C,4DAA4D;IAC5D,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,WAAW,CAAC,KAAK,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IAEzC,6EAA6E;IAC7E,6EAA6E;IAC7E,6EAA6E;IAC7E,8EAA8E;IAC9E,6EAA6E;IAC7E,8EAA8E;IAC9E,yDAAyD;IACzD,IAAI,gBAAsC,CAAC;IAC3C,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACjD,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;YAC5B,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;SACxE,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,CAAC,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC/D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,QAAQ,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YACvE,MAAM,CAAC,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACrD,CAAC;QACD,gBAAgB,GAAG,CAAC,GAAG,UAAU,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IAC5E,CAAC;IAED,uEAAuE;IACvE,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5E,OAAO;YACL,MAAM;YACN,UAAU,EAAE,EAAE;YACd,eAAe,EAAE,QAAQ;YACzB,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,QAAQ,EAAE,IAAI,CAAC,EAAE;SAClB,CAAC;IACJ,CAAC;IAED,qDAAqD;IACrD,EAAE;IACF,0EAA0E;IAC1E,6EAA6E;IAC7E,8EAA8E;IAC9E,6EAA6E;IAC7E,4EAA4E;IAC5E,IAAI,UAAU,GAAc,EAAE,CAAC;IAC/B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC3D,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC;QAC7B,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IAChC,CAAC;IAED,+EAA+E;IAC/E,yEAAyE;IACzE,oDAAoD;IACpD,IAAI,MAAgC,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,wEAAwE;IACxE,oEAAoE;IACpE,IAAI,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAC/F,CAAC,CAAC,IAAI,CAAC,QAAQ;QACf,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IAEZ,4EAA4E;IAC5E,mFAAmF;IACnF,mFAAmF;IACnF,6EAA6E;IAC7E,IAAI,WAA0C,CAAC;IAC/C,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,mBAAmB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtC,WAAW,GAAG,gBAAgB,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;QAC9E,IACE,gBAAgB,CAAC,WAAW,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,EAC3F,CAAC;YACD,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,qEAAqE;IACrE,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE;YACtC,KAAK,EAAE,OAAO,CAAC,YAAY,IAAI,SAAS;YACxC,KAAK,EAAE,OAAO,CAAC,WAAW;YAC1B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,QAAQ,EAAE,OAAO,CAAC,WAAW;YAC7B,KAAK,EAAE,OAAO,CAAC,QAAQ;YACvB,wEAAwE;YACxE,wEAAwE;YACxE,+DAA+D;YAC/D,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,iBAAiB,CAAC,CAAC,CAAC,SAAS;YAChF,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACpC,OAAO;gBACL,MAAM;gBACN,UAAU;gBACV,MAAM,EAAE,OAAO,CAAC,SAAS;gBACzB,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjD,QAAQ,EAAE,IAAI,CAAC,EAAE;aAClB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,oFAAoF;IACpF,sFAAsF;IACtF,+EAA+E;IAC/E,mFAAmF;IACnF,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QACrF,MAAM,IAAI,KAAK,CAAC,uCAAuC,OAAO,CAAC,MAAM,IAAI,kBAAkB,GAAG,CAAC,CAAC;IAClG,CAAC;IAED,kFAAkF;IAClF,gFAAgF;IAChF,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACzE,MAAM,IAAI,KAAK,CACb,qDAAqD,OAAO,CAAC,MAAM,IAAI,kBAAkB,GAAG,CAC7F,CAAC;IACJ,CAAC;IACD,4EAA4E;IAC5E,2EAA2E;IAC3E,yEAAyE;IACzE,4EAA4E;IAC5E,IAAI,IAA4B,CAAC;IACjC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,MAAM,GAA+B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClG,MAAM,WAAW,GAA+B,OAAO,CAAC,SAAS;QAC/D,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;QAClC,CAAC,CAAC,SAAS,CAAC;IAEd,oEAAoE;IACpE,+EAA+E;IAC/E,IAAI,cAA0C,CAAC;IAC/C,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrF,cAAc,GAAG,EAAE,CAAC;QACpB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACtC,IAAI,IAAY,CAAC;YACjB,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACtC,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,GAAG,CAAC,CAAC;YAC9D,CAAC;YACD,IAAI,MAAe,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,qBAAqB,CAAC,CAAC;YAC1D,CAAC;YACD,MAAM,GAAG,GAAG,MAAsB,CAAC;YACnC,IAAI,GAAG,EAAE,SAAS,KAAK,WAAW,EAAE,CAAC;gBACnC,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,+CAA+C,CAAC,CAAC;YACpF,CAAC;YACD,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,IAAI,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;QAChD,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK;QAC3B,cAAc,EAAE,OAAO,CAAC,UAAU;QAClC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1B,CAAC,CAAC;IACH,kFAAkF;IAClF,iFAAiF;IACjF,6DAA6D;IAC7D,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,EAAE,CAAC;QAC7D,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAoB,EAAE;YAC9E,MAAM;YACN,WAAW;SACZ,CAAC,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,WAAW,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC9C,MAAM,IAAI,IAAI,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC;IAED,OAAO;QACL,MAAM;QACN,UAAU;QACV,MAAM;QACN,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,uFAAuF;AACvF,SAAS,kBAAkB,CAAC,EAAqB;IAC/C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC;IACjF,KAAK,CAAC,IAAI,CACR,KAAK,EAAE,CAAC,OAAO,CAAC,SAAS,gBAAgB,EAAE,CAAC,OAAO,CAAC,UAAU,iBAAiB,EAAE,CAAC,OAAO,CAAC,GAAG,UAAU,EAAE,CAAC,OAAO,CAAC,UAAU,aAAa;QACvI,CAAC,EAAE,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,oBAAoB,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACjE,CAAC;IACF,MAAM,IAAI,GAA2B,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IAC5F,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAC1F,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,GACR,CAAC,CAAC,MAAM,KAAK,WAAW;YACtB,CAAC,CAAC,oBAAoB,CAAC,CAAC,SAAS,EAAE;YACnC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,YAAY;gBACzB,CAAC,CAAC,oBAAoB,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;gBACtG,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,WAAW,MAAM,CAAC;QACnD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI,EAAE,CAAC,CAAC;IAC3F,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;IACrE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAgBD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAA8C,EAC9C,QAAuB,EAAE;IAEzB,MAAM,OAAO,GAAiB,EAAE,GAAG,cAAc,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;IAC/D,MAAM,MAAM,GAAW,KAAK,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAEpD,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;QACnB,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,KAAK,CAAC;IACjB,CAAC;IACD,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,YAAY,CAAC,CAAC,CAAC,KAAK,QAAQ,CAC9C,CAAC,MAAM,CAAC;IACT,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,MAAM;QACN,OAAO;QACP,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM;QACvC,cAAc;KACf,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9E,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AAC/C,CAAC;AAUD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAA8C,EAC9C,QAAuB,EAAE;IAEzB,MAAM,OAAO,GAAiB,EAAE,GAAG,cAAc,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;IAC/D,MAAM,MAAM,GAAW,KAAK,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAEpD,IAAI,MAAgC,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,QAAQ,GAAG,0BAA0B,CAAC,MAAM,EAAE;QAClD,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,GAAG,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3F,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvF,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtE,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;AACjE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,IAAY;IACzD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,mBAAmB,OAAO,EAAE,CAAC,EAAE,CAAC;IAClE,CAAC;IACD,OAAO,6BAA6B,CAAC,MAAM,CAAC,CAAC;AAC/C,CAAC;AAsBD,oDAAoD;AACpD,MAAM,UAAU,YAAY,CAC1B,MAAkB,EAClB,MAA8B,EAC9B,OAAsC,EAAE;IAExC,6EAA6E;IAC7E,MAAM,EACJ,KAAK,GAAG,KAAK,EACb,cAAc,GAAG,KAAK,EACtB,IAAI,GAAG,SAAS,EAChB,IAAI,GAAG,SAAS,EAChB,OAAO,GAAG,SAAS,EACnB,MAAM,GAAG,SAAS,EAClB,UAAU,GAAG,SAAS,EACtB,IAAI,GAAG,SAAS,GACjB,GAAG,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM;YACT,OAAO,UAAU,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3E,KAAK,OAAO;YACV,OAAO,WAAW,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5E,KAAK,MAAM;YACT,OAAO,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACxC,KAAK,KAAK;YACR,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC;QAC3B,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,0EAA0E;YAC1E,8EAA8E;YAC9E,8EAA8E;YAC9E,qEAAqE;YACrE,MAAM,MAAM,GAAG,oBAAoB,CAAC,MAAM,EAAE;gBAC1C,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;gBACzC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;gBAC9B,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC9B,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACzC,CAAC;QACD,KAAK,OAAO,CAAC;QACb;YACE,OAAO,WAAW,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC","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"]} | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,QAAQ,MAAM,WAAW,CAAC;AACtC,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EACL,0BAA0B,EAC1B,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,eAAe,EACf,eAAe,EACf,WAAW,EACX,YAAY,EACZ,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,IAAI,EACJ,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,6BAA6B,GAC9B,MAAM,oBAAoB,CAAC;AAe5B,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI1F,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,UAAU,EACV,cAAc,EACd,cAAc,EACd,SAAS,EACT,YAAY,EACZ,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,cAAc,EACd,cAAc,GACf,MAAM,oBAAoB,CAAC;AAO5B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIzD,2CAA2C;AAC3C,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,iEAAiE;IACjE,EAAE,EAAE,CAAC;IACL,4DAA4D;IAC5D,QAAQ,EAAE,CAAC;IACX,kCAAkC;IAClC,KAAK,EAAE,CAAC;CACA,CAAC;AAiDX;;;GAGG;AACH,SAAS,aAAa,CAAC,OAAqB;IAC1C,MAAM,WAAW,GAAwB;QACvC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;QAC1C,YAAY,EAAE,OAAO,CAAC,YAAY;KACnC,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IACpE,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACtE,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS;QAAE,WAAW,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACrF,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS;QAAE,WAAW,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACrF,IAAI,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9D,WAAW,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IACpD,CAAC;IACD,IAAI,OAAO,CAAC,SAAS;QAAE,WAAW,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACjE,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAA8C,EAC9C,QAAuB,EAAE;IAEzB,MAAM,OAAO,GAAiB,EAAE,GAAG,cAAc,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;IAC/D,+EAA+E;IAC/E,MAAM,MAAM,GAAW,KAAK,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChF,MAAM,cAAc,GAAmB,KAAK,CAAC,cAAc,IAAI,YAAY,CAAC;IAE5E,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAE3C,4DAA4D;IAC5D,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,WAAW,CAAC,KAAK,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IAEzC,6EAA6E;IAC7E,6EAA6E;IAC7E,6EAA6E;IAC7E,8EAA8E;IAC9E,6EAA6E;IAC7E,8EAA8E;IAC9E,yDAAyD;IACzD,IAAI,gBAAsC,CAAC;IAC3C,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACjD,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;YAC5B,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;SACxE,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,CAAC,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC/D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,QAAQ,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YACvE,MAAM,CAAC,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACrD,CAAC;QACD,gBAAgB,GAAG,CAAC,GAAG,UAAU,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IAC5E,CAAC;IAED,uEAAuE;IACvE,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5E,OAAO;YACL,MAAM;YACN,UAAU,EAAE,EAAE;YACd,eAAe,EAAE,QAAQ;YACzB,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,QAAQ,EAAE,IAAI,CAAC,EAAE;SAClB,CAAC;IACJ,CAAC;IAED,qDAAqD;IACrD,EAAE;IACF,0EAA0E;IAC1E,6EAA6E;IAC7E,8EAA8E;IAC9E,6EAA6E;IAC7E,4EAA4E;IAC5E,IAAI,UAAU,GAAc,EAAE,CAAC;IAC/B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC3D,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC;QAC7B,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IAChC,CAAC;IAED,+EAA+E;IAC/E,yEAAyE;IACzE,oDAAoD;IACpD,IAAI,MAAgC,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,wEAAwE;IACxE,oEAAoE;IACpE,IAAI,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAC/F,CAAC,CAAC,IAAI,CAAC,QAAQ;QACf,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IAEZ,4EAA4E;IAC5E,mFAAmF;IACnF,8EAA8E;IAC9E,EAAE;IACF,kFAAkF;IAClF,mFAAmF;IACnF,+EAA+E;IAC/E,mFAAmF;IACnF,qCAAqC;IACrC,IAAI,WAA0C,CAAC;IAC/C,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,mBAAmB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtC,6EAA6E;QAC7E,6EAA6E;QAC7E,iDAAiD;QACjD,MAAM,eAAe,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,CAAC;QAC5D,WAAW,GAAG,gBAAgB,CAAC,eAAe,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC;QACtF,IACE,gBAAgB,CAAC,WAAW,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,EAC3F,CAAC;YACD,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,qEAAqE;IACrE,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE;YACtC,KAAK,EAAE,OAAO,CAAC,YAAY,IAAI,SAAS;YACxC,KAAK,EAAE,OAAO,CAAC,WAAW;YAC1B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,QAAQ,EAAE,OAAO,CAAC,WAAW;YAC7B,KAAK,EAAE,OAAO,CAAC,QAAQ;YACvB,wEAAwE;YACxE,wEAAwE;YACxE,+DAA+D;YAC/D,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,iBAAiB,CAAC,CAAC,CAAC,SAAS;YAChF,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACpC,OAAO;gBACL,MAAM;gBACN,UAAU;gBACV,MAAM,EAAE,OAAO,CAAC,SAAS;gBACzB,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjD,QAAQ,EAAE,IAAI,CAAC,EAAE;aAClB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,oFAAoF;IACpF,sFAAsF;IACtF,+EAA+E;IAC/E,mFAAmF;IACnF,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QACrF,MAAM,IAAI,KAAK,CAAC,uCAAuC,OAAO,CAAC,MAAM,IAAI,kBAAkB,GAAG,CAAC,CAAC;IAClG,CAAC;IAED,kFAAkF;IAClF,gFAAgF;IAChF,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACzE,MAAM,IAAI,KAAK,CACb,qDAAqD,OAAO,CAAC,MAAM,IAAI,kBAAkB,GAAG,CAC7F,CAAC;IACJ,CAAC;IACD,4EAA4E;IAC5E,2EAA2E;IAC3E,yEAAyE;IACzE,4EAA4E;IAC5E,IAAI,IAA4B,CAAC;IACjC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,MAAM,GAA+B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClG,MAAM,WAAW,GAA+B,OAAO,CAAC,SAAS;QAC/D,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;QAClC,CAAC,CAAC,SAAS,CAAC;IAEd,oEAAoE;IACpE,+EAA+E;IAC/E,IAAI,cAA0C,CAAC;IAC/C,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrF,cAAc,GAAG,EAAE,CAAC;QACpB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACtC,IAAI,IAAY,CAAC;YACjB,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACtC,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,GAAG,CAAC,CAAC;YAC9D,CAAC;YACD,IAAI,MAAe,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,qBAAqB,CAAC,CAAC;YAC1D,CAAC;YACD,MAAM,GAAG,GAAG,MAAsB,CAAC;YACnC,IAAI,GAAG,EAAE,SAAS,KAAK,WAAW,EAAE,CAAC;gBACnC,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,+CAA+C,CAAC,CAAC;YACpF,CAAC;YACD,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,IAAI,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;QAChD,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK;QAC3B,cAAc,EAAE,OAAO,CAAC,UAAU;QAClC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzB,4EAA4E;QAC5E,wDAAwD;QACxD,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjD,CAAC,CAAC;IACH,kFAAkF;IAClF,iFAAiF;IACjF,6DAA6D;IAC7D,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,EAAE,CAAC;QAC7D,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAoB,EAAE;YAC9E,MAAM;YACN,WAAW;SACZ,CAAC,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,WAAW,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC9C,MAAM,IAAI,IAAI,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC;IAED,OAAO;QACL,MAAM;QACN,UAAU;QACV,MAAM;QACN,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,uFAAuF;AACvF,SAAS,kBAAkB,CAAC,EAAqB;IAC/C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC;IACjF,KAAK,CAAC,IAAI,CACR,KAAK,EAAE,CAAC,OAAO,CAAC,SAAS,gBAAgB,EAAE,CAAC,OAAO,CAAC,UAAU,iBAAiB,EAAE,CAAC,OAAO,CAAC,GAAG,UAAU,EAAE,CAAC,OAAO,CAAC,UAAU,aAAa;QACvI,CAAC,EAAE,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,2EAA2E;QAC3E,CAAC,EAAE,CAAC,YAAY,GAAG,CAAC;YAClB,CAAC,CAAC,MAAM,EAAE,CAAC,YAAY,gBAAgB,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACnF,CAAC,CAAC,EAAE,CAAC;QACP,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,oBAAoB,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACjE,CAAC;IACF,MAAM,IAAI,GAA2B,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IAC5F,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAC1F,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,GACR,CAAC,CAAC,MAAM,KAAK,WAAW;YACtB,CAAC,CAAC,oBAAoB,CAAC,CAAC,SAAS,EAAE;YACnC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,YAAY;gBACzB,CAAC,CAAC,oBAAoB,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;gBACtG,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,WAAW,MAAM,CAAC;QACnD,6EAA6E;QAC7E,4EAA4E;QAC5E,MAAM,GAAG,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,aAAa,IAAI,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC;IACjG,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;IACrE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAgBD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAA8C,EAC9C,QAAuB,EAAE;IAEzB,MAAM,OAAO,GAAiB,EAAE,GAAG,cAAc,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;IAC/D,MAAM,MAAM,GAAW,KAAK,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAEpD,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;QACnB,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,KAAK,CAAC;IACjB,CAAC;IACD,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,YAAY,CAAC,CAAC,CAAC,KAAK,QAAQ,CAC9C,CAAC,MAAM,CAAC;IACT,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,MAAM;QACN,OAAO;QACP,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM;QACvC,cAAc;KACf,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9E,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AAC/C,CAAC;AAUD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAA8C,EAC9C,QAAuB,EAAE;IAEzB,MAAM,OAAO,GAAiB,EAAE,GAAG,cAAc,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;IAC/D,MAAM,MAAM,GAAW,KAAK,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAEpD,IAAI,MAAgC,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,QAAQ,GAAG,0BAA0B,CAAC,MAAM,EAAE;QAClD,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,GAAG,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3F,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvF,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtE,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;AACjE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,IAAY;IACzD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,mBAAmB,OAAO,EAAE,CAAC,EAAE,CAAC;IAClE,CAAC;IACD,OAAO,6BAA6B,CAAC,MAAM,CAAC,CAAC;AAC/C,CAAC;AA6BD,oDAAoD;AACpD,MAAM,UAAU,YAAY,CAC1B,MAAkB,EAClB,MAA8B,EAC9B,OAAsC,EAAE;IAExC,6EAA6E;IAC7E,MAAM,EACJ,KAAK,GAAG,KAAK,EACb,cAAc,GAAG,KAAK,EACtB,IAAI,GAAG,SAAS,EAChB,IAAI,GAAG,SAAS,EAChB,OAAO,GAAG,SAAS,EACnB,MAAM,GAAG,SAAS,EAClB,UAAU,GAAG,SAAS,EACtB,IAAI,GAAG,SAAS,EAChB,OAAO,GAAG,SAAS,GACpB,GAAG,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM;YACT,OAAO,UAAU,CAAC,MAAM,EAAE;gBACxB,cAAc;gBACd,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChC,CAAC,CAAC;QACL,KAAK,OAAO;YACV,OAAO,WAAW,CAAC,MAAM,EAAE;gBACzB,cAAc;gBACd,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChC,CAAC,CAAC;QACL,KAAK,MAAM;YACT,OAAO,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACxC,KAAK,KAAK;YACR,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC;QAC3B,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,0EAA0E;YAC1E,8EAA8E;YAC9E,6EAA6E;YAC7E,2EAA2E;YAC3E,4DAA4D;YAC5D,MAAM,MAAM,GAAG,oBAAoB,CAAC,MAAM,EAAE;gBAC1C,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;gBACzC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;gBAC9B,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7B,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChC,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACzC,CAAC;QACD,KAAK,OAAO,CAAC;QACb;YACE,OAAO,WAAW,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC","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).\n //\n // Evaluated on the PRE-baseline findings (kept + suppressed), matching the GitHub\n // Action: a `--baseline` accepts a finding for the SEVERITY gate, but a regulatory\n // deadline must never be waivable by baselining — otherwise `--write-baseline`\n // then `--baseline` would be a self-service deadline waiver. Triage runs later, so\n // it can never flip the gate either.\n let mandateEval: MandateEvaluation | undefined;\n if (options.mandates.length > 0) {\n assertKnownMandates(options.mandates);\n // Compose the org `--policy` in when one was supplied: acknowledged families\n // (permitted / in-transition) are annotated and exempt from the EARLY gates,\n // though a passed DISALLOW deadline still fails.\n const mandateFindings = [...result.findings, ...suppressed];\n mandateEval = evaluateMandates(mandateFindings, options.mandates, new Date(), policy);\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 // The `--mandate` evaluation feeds the machine-readable JSON/SARIF/evidence\n // output too (not just the human block appended below).\n ...(mandateEval ? { mandate: mandateEval } : {}),\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 // Policy composition: how many of the above the org is knowingly managing.\n (ev.acknowledged > 0\n ? ` · ${ev.acknowledged} acknowledged${ev.policyName ? ` (${ev.policyName})` : \"\"}`\n : \"\") +\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 // Flag policy-acknowledged rows so the reader sees why the gate may not fire\n // on them (exempt from --fail-now / --lead-months, never from a violation).\n const ack = r.acknowledged ? ` · policy: ${r.policyVerdict ?? \"acknowledged\"}` : \"\";\n lines.push(` [${r.status}] ${r.clause} · ${r.algorithm} ${r.file}:${r.line} — ${when}${ack}`);\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 * Compliance-mandate evaluation (`--mandate`). Carried into the machine-readable\n * JSON (`mandateMapping`), SARIF (`run.properties.mandate`), and evidence\n * (date-pinned, hashed) output. The human block is appended separately by\n * {@link runQscan}.\n */\n mandate?: MandateEvaluation;\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 mandate = undefined,\n } = typeof opts === \"boolean\" ? { color: opts, policy: undefined } : opts;\n switch (format) {\n case \"json\":\n return renderJson(result, {\n redactSnippets,\n ...(hndl ? { hndl } : {}),\n ...(mandate ? { mandate } : {}),\n });\n case \"sarif\":\n return renderSarif(result, {\n redactSnippets,\n ...(hndl ? { hndl } : {}),\n ...(mandate ? { mandate } : {}),\n });\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, and\n // `--mandate` adds the date-pinned, hashed `mandateMapping`. The attestation\n // is left unsigned here; signing is an async step in runQscan (an external\n // 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 ...(mandate ? { mandate } : {}),\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"]} |
+3
-3
| { | ||
| "name": "@quantakrypto/qscan", | ||
| "version": "0.8.0", | ||
| "version": "0.9.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.8.0", | ||
| "@quantakrypto/core": "0.8.0" | ||
| "@quantakrypto/agent": "0.9.0", | ||
| "@quantakrypto/core": "0.9.0" | ||
| }, | ||
@@ -44,0 +44,0 @@ "scripts": { |
+18
-5
@@ -84,9 +84,16 @@ # @quantakrypto/qscan | ||
| | `--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 | | ||
| | `--mandate <id>` | Gate findings against a compliance mandate's dated clauses (`cnsa-2.0`, `nist-ir-8547`; repeatable). Reports each prohibited finding with its clause + deadline; fails the build only once a disallow deadline has passed. Verdicts also ride in `--format json` (`mandateMapping`), `sarif` (`run.properties.mandate`), and `evidence` (hashed). | off | | ||
| | `--lead-months <n>` | Fail early when a `--mandate` disallow deadline is within `n` months. | — | | ||
| | `--fail-now` | Fail on any `--mandate`-prohibited finding, ignoring the deadline. | off | | ||
| | `--policy <file>` | Org crypto-policy JSON: adds §4 verdicts to `--format evidence`; with `--mandate`, permitted/in-transition families are acknowledged and exempt from the early gate (`--fail-now`/`--lead-months`), but a passed disallow deadline still fails. | — | | ||
| | `--profile <id>` | Standards regime for the migration-targets footer: `nist`, `cnsa-2.0`, `bsi-tr-02102`, `anssi`, `uk-ncsc`. | `nist` | | ||
| | `--tier <id>` | CNSA security tier for migration targets: `category-3`, `category-5` (alias for a profile). | — | | ||
| | `--hndl` | Score findings by harvest-now-decrypt-later exposure (reads `hndl.yml`; `qscan hndl init` scaffolds one). Annotates only; never changes the exit code. | 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 | | ||
| | `--triage-floor <level>` | With `--triage`, only triage findings at/above this level. | `medium` | | ||
| | `--context <level>` | How much source is shared with the LLM: `metadata`, `snippet`, `function`, `file` (secrets always redacted). | `snippet` | | ||
| | `--context <level>` | How much source is shared with the LLM: `metadata`, `snippet`, `function`, `file` (key material redacted, best-effort — review with `--dry-run`). | `snippet` | | ||
| | `--dry-run` | With `--triage`, print the exact payload that would be sent and exit without contacting the provider. | off | | ||
| | `--llm-provider <name>` | BYOK provider: `anthropic` or `openai-compatible`. | `anthropic` | | ||
| | `--llm-model <id>` | Model id for the BYOK provider. | provider default | | ||
| | `--baseline <file>` | Suppress findings whose fingerprint is in the baseline file. | — | | ||
| | `--baseline <file>` | Suppress findings whose fingerprint is in the baseline file (severity gate only — the `--mandate` gate is evaluated on pre-baseline findings, so a baseline can't waive a regulatory deadline). | — | | ||
| | `--write-baseline <file>` | Write current findings as a baseline, then exit 0. | — | | ||
@@ -97,2 +104,7 @@ | `--quiet` | Suppress the human summary banner. | off | | ||
| This table covers the common flags. Run `qscan --help` for the authoritative, | ||
| complete list (including `--sign`/`--timestamp`, `--crypto-agility`, `--merge`, | ||
| `--cache`, `--top`, `--max-findings`, `--no-snippets`, `--color`), plus the | ||
| subcommands `qscan hndl init` and `qscan crypto-agility emit|validate`. | ||
| ### Exit codes | ||
@@ -308,5 +320,6 @@ | ||
| `--context` controls how much source leaves the machine (`metadata` | `snippet` | | ||
| `function` | `file`, default `snippet`); secrets are always redacted. `--dry-run` | ||
| prints the exact, redacted payload and exits **without contacting the provider**, | ||
| so you can review what triage would send before enabling it. | ||
| `function` | `file`, default `snippet`); key material is redacted on every payload | ||
| (best-effort — pattern-based, so review with `--dry-run`). `--dry-run` prints the | ||
| exact, redacted payload and exits **without contacting the provider**, so you can | ||
| review what triage would send before enabling it. | ||
@@ -313,0 +326,0 @@ ## Remediation (`qremediate`) |
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.
435107
1.93%3309
1.38%423
3.17%+ Added
+ Added
- Removed
- Removed
Updated
Updated