@quantakrypto/core 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/crypto-agility.d.ts +158 -0
- package/dist/crypto-agility.d.ts.map +1 -0
- package/dist/crypto-agility.js +285 -0
- package/dist/crypto-agility.js.map +1 -0
- package/dist/dependencies.d.ts.map +1 -1
- package/dist/dependencies.js +180 -18
- package/dist/dependencies.js.map +1 -1
- package/dist/detectors/source.d.ts.map +1 -1
- package/dist/detectors/source.js +52 -0
- package/dist/detectors/source.js.map +1 -1
- package/dist/hndl.d.ts +241 -0
- package/dist/hndl.d.ts.map +1 -0
- package/dist/hndl.js +752 -0
- package/dist/hndl.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/parallel.d.ts.map +1 -1
- package/dist/parallel.js +22 -23
- package/dist/parallel.js.map +1 -1
- package/dist/report.d.ts +8 -0
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +75 -19
- package/dist/report.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/walk.d.ts +31 -1
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +30 -9
- package/dist/walk.js.map +1 -1
- package/package.json +1 -1
- package/src/crypto-agility.ts +407 -0
- package/src/dependencies.ts +182 -16
- package/src/detectors/source.ts +62 -0
- package/src/hndl.ts +1012 -0
- package/src/index.ts +52 -0
- package/src/parallel.ts +21 -20
- package/src/report.ts +84 -19
- package/src/types.ts +9 -1
- package/src/version.ts +1 -1
- package/src/walk.ts +47 -10
package/dist/report.js
CHANGED
|
@@ -3,6 +3,22 @@ import { SEVERITY_ORDER, sarifLevel } from "./severity.js";
|
|
|
3
3
|
import { ANALYZABLE_LANGUAGES_LABEL } from "./detect-utils.js";
|
|
4
4
|
import { remediationFor, remediationForTier, remediationForProfile } from "./remediation.js";
|
|
5
5
|
import { fingerprintFinding } from "./baseline.js";
|
|
6
|
+
import { findingFingerprint } from "./hndl.js";
|
|
7
|
+
/** The per-finding exposure block emitted in JSON / SARIF, or undefined. */
|
|
8
|
+
function exposureFor(f, hndl) {
|
|
9
|
+
if (!hndl)
|
|
10
|
+
return undefined;
|
|
11
|
+
return hndl.byFingerprint.get(findingFingerprint(f));
|
|
12
|
+
}
|
|
13
|
+
/** The repo HNDL summary block shared by JSON output and the SARIF run. */
|
|
14
|
+
function hndlSummaryBlock(hndl) {
|
|
15
|
+
return {
|
|
16
|
+
modelVersion: hndl.modelVersion,
|
|
17
|
+
horizon: hndl.horizon,
|
|
18
|
+
summary: hndl.summary,
|
|
19
|
+
assets: hndl.assets,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
6
22
|
const SARIF_SCHEMA = "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json";
|
|
7
23
|
const INFORMATION_URI = "https://github.com/quantakrypto/pqc-tools";
|
|
8
24
|
/**
|
|
@@ -55,6 +71,16 @@ function sarifRule(spec) {
|
|
|
55
71
|
: {}),
|
|
56
72
|
};
|
|
57
73
|
}
|
|
74
|
+
/** SARIF result.properties fragment for a finding's HNDL exposure, or empty. */
|
|
75
|
+
function exposureProperties(exposure) {
|
|
76
|
+
if (!exposure)
|
|
77
|
+
return {};
|
|
78
|
+
return {
|
|
79
|
+
exposureScore: exposure.exposureScore,
|
|
80
|
+
dataAsset: exposure.dataAsset,
|
|
81
|
+
exposureRationale: exposure.rationale,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
58
84
|
/** Serialize a scan result as SARIF 2.1.0. */
|
|
59
85
|
export function toSarif(result, opts) {
|
|
60
86
|
const redactSnippets = opts?.redactSnippets ?? false;
|
|
@@ -119,6 +145,10 @@ export function toSarif(result, opts) {
|
|
|
119
145
|
// edit above it. `quantakrypto/v1` names our scheme.
|
|
120
146
|
partialFingerprints: { "quantakrypto/v1": fingerprintFinding(f) },
|
|
121
147
|
properties: {
|
|
148
|
+
// Same stable identity mirrored into properties so non-GitHub SARIF
|
|
149
|
+
// consumers (our platform ingest) can read one uniform `fingerprint`
|
|
150
|
+
// field across JSON and SARIF without reaching into partialFingerprints.
|
|
151
|
+
fingerprint: fingerprintFinding(f),
|
|
122
152
|
category: f.category,
|
|
123
153
|
severity: f.severity,
|
|
124
154
|
confidence: f.confidence,
|
|
@@ -126,6 +156,7 @@ export function toSarif(result, opts) {
|
|
|
126
156
|
...(f.algorithm ? { algorithm: f.algorithm } : {}),
|
|
127
157
|
...(f.remediation ? { remediation: f.remediation } : {}),
|
|
128
158
|
...(f.cwe ? { cwe: f.cwe } : {}),
|
|
159
|
+
...exposureProperties(exposureFor(f, opts?.hndl)),
|
|
129
160
|
},
|
|
130
161
|
...(f.cwe
|
|
131
162
|
? {
|
|
@@ -178,6 +209,7 @@ export function toSarif(result, opts) {
|
|
|
178
209
|
},
|
|
179
210
|
},
|
|
180
211
|
...(taxonomies.length > 0 ? { taxonomies } : {}),
|
|
212
|
+
...(opts?.hndl ? { properties: { hndl: hndlSummaryBlock(opts.hndl) } } : {}),
|
|
181
213
|
results,
|
|
182
214
|
},
|
|
183
215
|
],
|
|
@@ -201,6 +233,7 @@ function securitySeverity(severity) {
|
|
|
201
233
|
/** Serialize a scan result as a plain JSON-friendly object. */
|
|
202
234
|
export function toJson(result, opts) {
|
|
203
235
|
const redactSnippets = opts?.redactSnippets ?? false;
|
|
236
|
+
const hndl = opts?.hndl;
|
|
204
237
|
return {
|
|
205
238
|
toolVersion: result.toolVersion,
|
|
206
239
|
root: result.root,
|
|
@@ -216,25 +249,48 @@ export function toJson(result, opts) {
|
|
|
216
249
|
byCategory: result.inventory.byCategory,
|
|
217
250
|
byAlgorithm: result.inventory.byAlgorithm,
|
|
218
251
|
},
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
252
|
+
...(hndl ? { hndl: hndlSummaryBlock(hndl) } : {}),
|
|
253
|
+
findings: result.findings.map((f) => {
|
|
254
|
+
const exposure = exposureFor(f, hndl);
|
|
255
|
+
return {
|
|
256
|
+
// Stable, line-INSENSITIVE identity of the finding: sha256 of
|
|
257
|
+
// ruleId | normalized-POSIX-repo-relative-path | normalized-snippet
|
|
258
|
+
// (the SARIF partialFingerprints trick, line number deliberately
|
|
259
|
+
// excluded). Reused verbatim from the baseline module so JSON identity,
|
|
260
|
+
// SARIF partialFingerprints, and the baseline suppression set are one and
|
|
261
|
+
// the same value. A line move does NOT change it; when no snippet context
|
|
262
|
+
// exists it falls back to ruleId|path. This is the cross-run identity the
|
|
263
|
+
// platform keys posture drift on.
|
|
264
|
+
fingerprint: fingerprintFinding(f),
|
|
265
|
+
ruleId: f.ruleId,
|
|
266
|
+
title: f.title,
|
|
267
|
+
category: f.category,
|
|
268
|
+
severity: f.severity,
|
|
269
|
+
confidence: f.confidence,
|
|
270
|
+
algorithm: f.algorithm,
|
|
271
|
+
hndl: f.hndl,
|
|
272
|
+
message: f.message,
|
|
273
|
+
remediation: f.remediation,
|
|
274
|
+
cwe: f.cwe,
|
|
275
|
+
location: {
|
|
276
|
+
file: f.location.file,
|
|
277
|
+
line: f.location.line,
|
|
278
|
+
column: f.location.column,
|
|
279
|
+
endLine: f.location.endLine,
|
|
280
|
+
snippet: emittedSnippet(f, redactSnippets),
|
|
281
|
+
},
|
|
282
|
+
...(exposure
|
|
283
|
+
? {
|
|
284
|
+
exposure: {
|
|
285
|
+
fingerprint: exposure.fingerprint,
|
|
286
|
+
exposureScore: exposure.exposureScore,
|
|
287
|
+
dataAsset: exposure.dataAsset,
|
|
288
|
+
rationale: exposure.rationale,
|
|
289
|
+
},
|
|
290
|
+
}
|
|
291
|
+
: {}),
|
|
292
|
+
};
|
|
293
|
+
}),
|
|
238
294
|
};
|
|
239
295
|
}
|
|
240
296
|
/* -------------------------------------------------------------------------- */
|
package/dist/report.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Reporters: turn a {@link ScanResult} into SARIF 2.1.0, a clean JSON object,\n * or a human-readable text summary. No third-party dependencies — ANSI colour\n * is emitted with raw escape codes and is off by default.\n */\nimport type { AlgorithmFamily, Finding, RuleMeta, ScanResult, Severity } from \"./types.js\";\nimport { VERSION } from \"./version.js\";\nimport { SEVERITY_ORDER, sarifLevel } from \"./severity.js\";\nimport { ANALYZABLE_LANGUAGES_LABEL } from \"./detect-utils.js\";\nimport { remediationFor, remediationForTier, remediationForProfile } from \"./remediation.js\";\nimport type { SecurityTier } from \"./remediation.js\";\nimport type { StandardsProfile } from \"./standards-profiles.js\";\nimport { fingerprintFinding } from \"./baseline.js\";\n\n/** Minimal SARIF 2.1.0 log shape (kept permissive on purpose). */\nexport interface SarifLog {\n $schema: string;\n version: \"2.1.0\";\n runs: unknown[];\n}\n\n/** Options shared by the structured reporters ({@link toSarif} / {@link toJson}). */\nexport interface ReportOptions {\n /**\n * Omit `location.snippet` from every finding in the output. Defaults to false\n * (snippets are included). Snippets of `sensitive` findings (e.g. PEM key\n * blocks, SSH public keys) are ALWAYS omitted regardless of this flag — the\n * snippet there IS the sensitive value.\n */\n redactSnippets?: boolean;\n /**\n * Full rule catalog to advertise in SARIF `tool.driver.rules[]`, even for\n * rules that produced no finding in this run. Pass\n * `defaultRegistry.ruleCatalog()`. When omitted, only the rules that actually\n * fired are emitted (the historical behaviour). SARIF-only; ignored by\n * {@link toJson}.\n */\n catalog?: RuleMeta[];\n}\n\nconst SARIF_SCHEMA =\n \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\";\n\nconst INFORMATION_URI = \"https://github.com/quantakrypto/pqc-tools\";\n\n/**\n * Resolve the snippet to emit for a finding, honouring redaction. Sensitive\n * findings (key material) never expose their snippet; otherwise the snippet is\n * dropped only when `redactSnippets` is set.\n */\nfunction emittedSnippet(f: Finding, redactSnippets: boolean): string | undefined {\n if (redactSnippets || f.sensitive) return undefined;\n return f.location.snippet;\n}\n\n/** Map our severity to a SARIF rule-level default (used in rules[].defaultConfiguration). */\nfunction sarifRank(severity: Severity): number {\n switch (severity) {\n case \"critical\":\n return 100;\n case \"high\":\n return 80;\n case \"medium\":\n return 50;\n case \"low\":\n return 20;\n default:\n return 5;\n }\n}\n\n/** Build a SARIF `rules[]` entry from a rule's severity/title/message/etc. */\nfunction sarifRule(spec: {\n id: string;\n title: string;\n message: string;\n severity: Severity;\n category: string;\n algorithm?: string;\n hndl: boolean;\n cwe?: string;\n remediation?: string;\n}): Record<string, unknown> {\n return {\n id: spec.id,\n name: spec.id,\n shortDescription: { text: spec.title },\n fullDescription: { text: spec.message },\n defaultConfiguration: { level: sarifLevel(spec.severity), rank: sarifRank(spec.severity) },\n ...(spec.remediation ? { help: { text: `Remediation: ${spec.remediation}` } } : {}),\n properties: {\n category: spec.category,\n ...(spec.algorithm ? { algorithm: spec.algorithm } : {}),\n hndl: spec.hndl,\n ...(spec.cwe ? { cwe: spec.cwe, \"security-severity\": securitySeverity(spec.severity) } : {}),\n ...(spec.cwe ? { tags: [\"security\", spec.cwe] } : {}),\n },\n ...(spec.cwe\n ? {\n relationships: [\n { target: { id: spec.cwe, toolComponent: { name: \"CWE\" } }, kinds: [\"relevant\"] },\n ],\n }\n : {}),\n };\n}\n\n/** Serialize a scan result as SARIF 2.1.0. */\nexport function toSarif(result: ScanResult, opts?: ReportOptions): SarifLog {\n const redactSnippets = opts?.redactSnippets ?? false;\n // Build the rule set and collect the CWE taxa referenced by any rule. When a\n // full catalog is supplied, advertise every rule (even ones that didn't fire);\n // otherwise emit one rule per ruleId encountered (the historical behaviour).\n const ruleIndex = new Map<string, number>();\n const rules: Array<Record<string, unknown>> = [];\n const cweTaxa = new Set<string>();\n\n for (const r of opts?.catalog ?? []) {\n if (ruleIndex.has(r.id)) continue;\n if (r.cwe) cweTaxa.add(r.cwe);\n ruleIndex.set(r.id, rules.length);\n rules.push(\n sarifRule({\n id: r.id,\n title: r.title,\n message: r.message,\n severity: r.severity,\n category: r.category,\n algorithm: r.algorithm,\n hndl: r.hndl,\n cwe: r.cwe,\n remediation: r.remediation,\n }),\n );\n }\n\n for (const f of result.findings) {\n if (f.cwe) cweTaxa.add(f.cwe);\n if (ruleIndex.has(f.ruleId)) continue;\n ruleIndex.set(f.ruleId, rules.length);\n rules.push(\n sarifRule({\n id: f.ruleId,\n title: f.title,\n message: f.message,\n severity: f.severity,\n category: f.category,\n algorithm: f.algorithm,\n hndl: f.hndl,\n cwe: f.cwe,\n remediation: f.remediation,\n }),\n );\n }\n\n const results = result.findings.map((f) => {\n const region: Record<string, number> = { startLine: f.location.line };\n if (typeof f.location.column === \"number\") region.startColumn = f.location.column;\n if (typeof f.location.endLine === \"number\") region.endLine = f.location.endLine;\n const snippet = emittedSnippet(f, redactSnippets);\n\n return {\n ruleId: f.ruleId,\n ruleIndex: ruleIndex.get(f.ruleId),\n level: sarifLevel(f.severity),\n message: { text: f.message },\n // Line-INSENSITIVE fingerprint (the same one the baseline uses:\n // sha256 of ruleId|file|normalizedSnippet). GitHub code scanning keys\n // alert identity + dedup off partialFingerprints, so a finding survives\n // line shifts and reformatting instead of re-alerting as \"new\" on every\n // edit above it. `quantakrypto/v1` names our scheme.\n partialFingerprints: { \"quantakrypto/v1\": fingerprintFinding(f) },\n properties: {\n category: f.category,\n severity: f.severity,\n confidence: f.confidence,\n hndl: f.hndl,\n ...(f.algorithm ? { algorithm: f.algorithm } : {}),\n ...(f.remediation ? { remediation: f.remediation } : {}),\n ...(f.cwe ? { cwe: f.cwe } : {}),\n },\n ...(f.cwe\n ? {\n taxa: [\n {\n target: { id: f.cwe, toolComponent: { name: \"CWE\" } },\n },\n ],\n }\n : {}),\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: f.location.file },\n region: {\n ...region,\n ...(snippet ? { snippet: { text: snippet } } : {}),\n },\n },\n },\n ],\n };\n });\n\n // CWE taxonomy component (SARIF taxonomies), referenced by rules + results.\n const taxonomies =\n cweTaxa.size > 0\n ? [\n {\n name: \"CWE\",\n informationUri: \"https://cwe.mitre.org/\",\n organization: \"MITRE\",\n shortDescription: { text: \"The MITRE Common Weakness Enumeration\" },\n taxa: [...cweTaxa].sort().map((id) => ({\n id,\n helpUri: `https://cwe.mitre.org/data/definitions/${id.replace(/^CWE-/, \"\")}.html`,\n })),\n },\n ]\n : [];\n\n return {\n $schema: SARIF_SCHEMA,\n version: \"2.1.0\",\n runs: [\n {\n tool: {\n driver: {\n name: \"qScan\",\n informationUri: INFORMATION_URI,\n version: result.toolVersion || VERSION,\n rules,\n },\n },\n ...(taxonomies.length > 0 ? { taxonomies } : {}),\n results,\n },\n ],\n };\n}\n\n/** GitHub-code-scanning `security-severity` (0–10) derived from our severity. */\nfunction securitySeverity(severity: Severity): string {\n switch (severity) {\n case \"critical\":\n return \"9.5\";\n case \"high\":\n return \"8.0\";\n case \"medium\":\n return \"5.0\";\n case \"low\":\n return \"3.0\";\n default:\n return \"1.0\";\n }\n}\n\n/** Serialize a scan result as a plain JSON-friendly object. */\nexport function toJson(result: ScanResult, opts?: ReportOptions): Record<string, unknown> {\n const redactSnippets = opts?.redactSnippets ?? false;\n return {\n toolVersion: result.toolVersion,\n root: result.root,\n startedAt: result.startedAt,\n finishedAt: result.finishedAt,\n filesScanned: result.filesScanned,\n ...(result.analyzedFiles !== undefined ? { analyzedFiles: result.analyzedFiles } : {}),\n ...(result.diagnostics ? { diagnostics: result.diagnostics } : {}),\n inventory: {\n readinessScore: result.inventory.readinessScore,\n hndlCount: result.inventory.hndlCount,\n bySeverity: result.inventory.bySeverity,\n byCategory: result.inventory.byCategory,\n byAlgorithm: result.inventory.byAlgorithm,\n },\n findings: result.findings.map((f) => ({\n ruleId: f.ruleId,\n title: f.title,\n category: f.category,\n severity: f.severity,\n confidence: f.confidence,\n algorithm: f.algorithm,\n hndl: f.hndl,\n message: f.message,\n remediation: f.remediation,\n cwe: f.cwe,\n location: {\n file: f.location.file,\n line: f.location.line,\n column: f.location.column,\n endLine: f.location.endLine,\n snippet: emittedSnippet(f, redactSnippets),\n },\n })),\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Human-readable summary */\n/* -------------------------------------------------------------------------- */\n\n/** Raw ANSI codes (no chalk). Disabled when colour is off. */\nconst ANSI = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n blue: \"\\x1b[34m\",\n magenta: \"\\x1b[35m\",\n cyan: \"\\x1b[36m\",\n} as const;\n\nfunction severityColor(sev: Severity): string {\n switch (sev) {\n case \"critical\":\n return ANSI.magenta;\n case \"high\":\n return ANSI.red;\n case \"medium\":\n return ANSI.yellow;\n case \"low\":\n return ANSI.blue;\n default:\n return ANSI.dim;\n }\n}\n\nfunction scoreColor(score: number): string {\n if (score >= 80) return ANSI.green;\n if (score >= 50) return ANSI.yellow;\n return ANSI.red;\n}\n\n/**\n * Render a human-readable summary of a scan result. Colour is off by default;\n * pass `{ color: true }` to emit ANSI escape codes.\n */\nexport function formatSummary(\n result: ScanResult,\n options?: { color?: boolean; tier?: SecurityTier },\n): string {\n const color = options?.color ?? false;\n const c = (code: string, text: string): string => (color ? `${code}${text}${ANSI.reset}` : text);\n\n const lines: string[] = [];\n const inv = result.inventory;\n\n lines.push(c(ANSI.bold, \"qScan — post-quantum readiness report\"));\n lines.push(c(ANSI.dim, `tool v${result.toolVersion} · root: ${result.root}`));\n lines.push(\"\");\n\n // Readiness score banner.\n lines.push(\n `Readiness score: ${c(`${ANSI.bold}${scoreColor(inv.readinessScore)}`, `${inv.readinessScore}/100`)}`,\n );\n const analyzed =\n result.analyzedFiles !== undefined\n ? ` Analyzed (${ANALYZABLE_LANGUAGES_LABEL}): ${result.analyzedFiles}`\n : \"\";\n lines.push(\n `Files scanned: ${result.filesScanned}${analyzed} Findings: ${result.findings.length} HNDL-exposed: ${c(\n inv.hndlCount > 0 ? ANSI.red : ANSI.green,\n String(inv.hndlCount),\n )}`,\n );\n // Coverage honesty: a score over zero analyzable files is not a clean bill of health.\n if (result.analyzedFiles === 0 && result.filesScanned > 0) {\n lines.push(\n c(\n ANSI.yellow,\n `Note: 0 files were in a supported source language (${ANALYZABLE_LANGUAGES_LABEL}) — the readiness score does not reflect this codebase.`,\n ),\n );\n }\n // Coverage diagnostics: skipped files mean the finding count may be incomplete.\n const diag = result.diagnostics;\n if (diag && (diag.unreadable > 0 || diag.skippedMinified > 0)) {\n lines.push(\n c(\n ANSI.yellow,\n `Coverage: ${diag.unreadable} unreadable, ${diag.skippedMinified} skipped as minified — results may be incomplete.`,\n ),\n );\n }\n lines.push(\"\");\n\n // Severity breakdown.\n const sevParts = SEVERITY_ORDER.filter((s) => inv.bySeverity[s] > 0).map((s) =>\n c(severityColor(s), `${s}: ${inv.bySeverity[s]}`),\n );\n lines.push(`By severity: ${sevParts.length ? sevParts.join(\" \") : c(ANSI.green, \"none\")}`);\n\n // Algorithm breakdown.\n const algoParts = Object.entries(inv.byAlgorithm)\n .sort((a, b) => b[1] - a[1])\n .map(([k, v]) => `${k}: ${v}`);\n if (algoParts.length) lines.push(`By algorithm: ${algoParts.join(\" \")}`);\n lines.push(\"\");\n\n if (result.findings.length === 0) {\n lines.push(c(ANSI.green, \"No classical asymmetric cryptography detected. ✓\"));\n return lines.join(\"\\n\");\n }\n\n // Top findings, grouped by severity (most severe first), capped for readability.\n const sorted = [...result.findings].sort(\n (a, b) => SEVERITY_ORDER.indexOf(a.severity) - SEVERITY_ORDER.indexOf(b.severity),\n );\n const MAX_SHOWN = 25;\n lines.push(\n c(ANSI.bold, `Top findings (${Math.min(MAX_SHOWN, sorted.length)} of ${sorted.length}):`),\n );\n\n for (const f of sorted.slice(0, MAX_SHOWN)) {\n const loc = `${f.location.file}:${f.location.line}${\n f.location.column ? `:${f.location.column}` : \"\"\n }`;\n const tag = c(severityColor(f.severity), `[${f.severity}]`);\n const hndl = f.hndl ? c(ANSI.red, \" (HNDL)\") : \"\";\n lines.push(` ${tag} ${f.title}${hndl}`);\n lines.push(c(ANSI.dim, ` ${loc} — ${f.message}`));\n if (f.remediation) lines.push(c(ANSI.cyan, ` → ${f.remediation}`));\n }\n\n if (sorted.length > MAX_SHOWN) {\n lines.push(c(ANSI.dim, ` …and ${sorted.length - MAX_SHOWN} more.`));\n }\n\n lines.push(\"\");\n if (inv.hndlCount > 0) {\n lines.push(\n c(\n ANSI.yellow,\n `Note: ${inv.hndlCount} finding(s) are exposed to \"harvest now, decrypt later\" — ` +\n \"encrypted traffic captured today can be decrypted once a quantum computer exists. \" +\n \"Prioritise migrating key exchange / encryption to hybrid PQC (X25519MLKEM768).\",\n ),\n );\n }\n\n if (options?.tier) {\n lines.push(\"\", ...formatTierGuidance(inv.byAlgorithm, options.tier));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Per-family migration targets for a CNSA security tier — surfaces the otherwise\n * library-only {@link remediationForTier} in human reports. Category 5 shows the\n * ML-KEM-1024 / ML-DSA-87 sets CNSA 2.0 mandates for national-security systems and\n * long-lived secrets. Returns plain (un-coloured) lines; the caller styles them.\n */\nexport function formatTierGuidance(\n byAlgorithm: Record<string, number>,\n tier: SecurityTier,\n): string[] {\n const label = tier === \"category-5\" ? \"CNSA 2.0 (Category 5)\" : \"Category 3 (commercial)\";\n const out: string[] = [`${label} migration targets:`];\n const seen = new Set<string>();\n for (const [k, n] of Object.entries(byAlgorithm)) {\n if (n <= 0) continue;\n const fam = k as AlgorithmFamily;\n if (fam === \"unknown\" || !remediationFor(fam)) continue; // skip unmapped families\n const rem = remediationForTier(fam, tier);\n if (seen.has(rem.recommendation)) continue;\n seen.add(rem.recommendation);\n out.push(` ${fam} → ${rem.recommendation}`);\n }\n if (tier === \"category-5\") {\n out.push(\n \" CNSA 2.0 mandates ML-KEM-1024 / ML-DSA-87 for national-security systems and long-lived secrets (2030/2033 milestones).\",\n );\n }\n return out;\n}\n\n/**\n * Per-family migration targets tailored to a selected {@link StandardsProfile}\n * (`--profile`). Unlike {@link formatTierGuidance} (CNSA-tier only), this surfaces the\n * regime's parameter sets AND its hybrid stance — required (ANSSI/BSI) vs recommended\n * (NIST/NCSC) vs optional (CNSA 2.0) — so guidance isn't regime-wrong. Returns plain\n * (un-coloured) lines; the caller styles them.\n */\nexport function formatProfileGuidance(\n byAlgorithm: Record<string, number>,\n profile: StandardsProfile,\n): string[] {\n const out: string[] = [`${profile.name} migration targets:`];\n const seen = new Set<string>();\n for (const [k, n] of Object.entries(byAlgorithm)) {\n if (n <= 0) continue;\n const fam = k as AlgorithmFamily;\n if (fam === \"unknown\" || !remediationFor(fam)) continue; // skip unmapped families\n const rem = remediationForProfile(fam, profile);\n if (seen.has(rem.recommendation)) continue;\n seen.add(rem.recommendation);\n out.push(` ${fam} → ${rem.recommendation}`);\n }\n const stance =\n profile.hybridStance === \"required\"\n ? \"requires classical+PQC hybridization\"\n : profile.hybridStance === \"recommended\"\n ? \"recommends hybridization\"\n : \"does not require hybridization\";\n out.push(\n ` ${profile.authority} ${stance}; classical public-key crypto disallowed after ${profile.disallowAfter} (${profile.citation}).`,\n );\n return out;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Reporters: turn a {@link ScanResult} into SARIF 2.1.0, a clean JSON object,\n * or a human-readable text summary. No third-party dependencies — ANSI colour\n * is emitted with raw escape codes and is off by default.\n */\nimport type { AlgorithmFamily, Finding, RuleMeta, ScanResult, Severity } from \"./types.js\";\nimport { VERSION } from \"./version.js\";\nimport { SEVERITY_ORDER, sarifLevel } from \"./severity.js\";\nimport { ANALYZABLE_LANGUAGES_LABEL } from \"./detect-utils.js\";\nimport { remediationFor, remediationForTier, remediationForProfile } from \"./remediation.js\";\nimport type { SecurityTier } from \"./remediation.js\";\nimport type { StandardsProfile } from \"./standards-profiles.js\";\nimport { fingerprintFinding } from \"./baseline.js\";\nimport { findingFingerprint } from \"./hndl.js\";\nimport type { FindingExposure, HndlReport } from \"./hndl.js\";\n\n/** Minimal SARIF 2.1.0 log shape (kept permissive on purpose). */\nexport interface SarifLog {\n $schema: string;\n version: \"2.1.0\";\n runs: unknown[];\n}\n\n/** Options shared by the structured reporters ({@link toSarif} / {@link toJson}). */\nexport interface ReportOptions {\n /**\n * Omit `location.snippet` from every finding in the output. Defaults to false\n * (snippets are included). Snippets of `sensitive` findings (e.g. PEM key\n * blocks, SSH public keys) are ALWAYS omitted regardless of this flag — the\n * snippet there IS the sensitive value.\n */\n redactSnippets?: boolean;\n /**\n * Full rule catalog to advertise in SARIF `tool.driver.rules[]`, even for\n * rules that produced no finding in this run. Pass\n * `defaultRegistry.ruleCatalog()`. When omitted, only the rules that actually\n * fired are emitted (the historical behaviour). SARIF-only; ignored by\n * {@link toJson}.\n */\n catalog?: RuleMeta[];\n /**\n * Optional HNDL exposure analysis ({@link computeHndl}). When supplied, each\n * finding gains its `exposure` fields (score, bound data asset, rationale)\n * keyed by fingerprint, and the report carries the repo-level HNDL summary.\n * Purely additive: it never changes finding identity, ordering, or exit codes.\n */\n hndl?: HndlReport;\n}\n\n/** The per-finding exposure block emitted in JSON / SARIF, or undefined. */\nfunction exposureFor(f: Finding, hndl: HndlReport | undefined): FindingExposure | undefined {\n if (!hndl) return undefined;\n return hndl.byFingerprint.get(findingFingerprint(f));\n}\n\n/** The repo HNDL summary block shared by JSON output and the SARIF run. */\nfunction hndlSummaryBlock(hndl: HndlReport): Record<string, unknown> {\n return {\n modelVersion: hndl.modelVersion,\n horizon: hndl.horizon,\n summary: hndl.summary,\n assets: hndl.assets,\n };\n}\n\nconst SARIF_SCHEMA =\n \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json\";\n\nconst INFORMATION_URI = \"https://github.com/quantakrypto/pqc-tools\";\n\n/**\n * Resolve the snippet to emit for a finding, honouring redaction. Sensitive\n * findings (key material) never expose their snippet; otherwise the snippet is\n * dropped only when `redactSnippets` is set.\n */\nfunction emittedSnippet(f: Finding, redactSnippets: boolean): string | undefined {\n if (redactSnippets || f.sensitive) return undefined;\n return f.location.snippet;\n}\n\n/** Map our severity to a SARIF rule-level default (used in rules[].defaultConfiguration). */\nfunction sarifRank(severity: Severity): number {\n switch (severity) {\n case \"critical\":\n return 100;\n case \"high\":\n return 80;\n case \"medium\":\n return 50;\n case \"low\":\n return 20;\n default:\n return 5;\n }\n}\n\n/** Build a SARIF `rules[]` entry from a rule's severity/title/message/etc. */\nfunction sarifRule(spec: {\n id: string;\n title: string;\n message: string;\n severity: Severity;\n category: string;\n algorithm?: string;\n hndl: boolean;\n cwe?: string;\n remediation?: string;\n}): Record<string, unknown> {\n return {\n id: spec.id,\n name: spec.id,\n shortDescription: { text: spec.title },\n fullDescription: { text: spec.message },\n defaultConfiguration: { level: sarifLevel(spec.severity), rank: sarifRank(spec.severity) },\n ...(spec.remediation ? { help: { text: `Remediation: ${spec.remediation}` } } : {}),\n properties: {\n category: spec.category,\n ...(spec.algorithm ? { algorithm: spec.algorithm } : {}),\n hndl: spec.hndl,\n ...(spec.cwe ? { cwe: spec.cwe, \"security-severity\": securitySeverity(spec.severity) } : {}),\n ...(spec.cwe ? { tags: [\"security\", spec.cwe] } : {}),\n },\n ...(spec.cwe\n ? {\n relationships: [\n { target: { id: spec.cwe, toolComponent: { name: \"CWE\" } }, kinds: [\"relevant\"] },\n ],\n }\n : {}),\n };\n}\n\n/** SARIF result.properties fragment for a finding's HNDL exposure, or empty. */\nfunction exposureProperties(exposure: FindingExposure | undefined): Record<string, unknown> {\n if (!exposure) return {};\n return {\n exposureScore: exposure.exposureScore,\n dataAsset: exposure.dataAsset,\n exposureRationale: exposure.rationale,\n };\n}\n\n/** Serialize a scan result as SARIF 2.1.0. */\nexport function toSarif(result: ScanResult, opts?: ReportOptions): SarifLog {\n const redactSnippets = opts?.redactSnippets ?? false;\n // Build the rule set and collect the CWE taxa referenced by any rule. When a\n // full catalog is supplied, advertise every rule (even ones that didn't fire);\n // otherwise emit one rule per ruleId encountered (the historical behaviour).\n const ruleIndex = new Map<string, number>();\n const rules: Array<Record<string, unknown>> = [];\n const cweTaxa = new Set<string>();\n\n for (const r of opts?.catalog ?? []) {\n if (ruleIndex.has(r.id)) continue;\n if (r.cwe) cweTaxa.add(r.cwe);\n ruleIndex.set(r.id, rules.length);\n rules.push(\n sarifRule({\n id: r.id,\n title: r.title,\n message: r.message,\n severity: r.severity,\n category: r.category,\n algorithm: r.algorithm,\n hndl: r.hndl,\n cwe: r.cwe,\n remediation: r.remediation,\n }),\n );\n }\n\n for (const f of result.findings) {\n if (f.cwe) cweTaxa.add(f.cwe);\n if (ruleIndex.has(f.ruleId)) continue;\n ruleIndex.set(f.ruleId, rules.length);\n rules.push(\n sarifRule({\n id: f.ruleId,\n title: f.title,\n message: f.message,\n severity: f.severity,\n category: f.category,\n algorithm: f.algorithm,\n hndl: f.hndl,\n cwe: f.cwe,\n remediation: f.remediation,\n }),\n );\n }\n\n const results = result.findings.map((f) => {\n const region: Record<string, number> = { startLine: f.location.line };\n if (typeof f.location.column === \"number\") region.startColumn = f.location.column;\n if (typeof f.location.endLine === \"number\") region.endLine = f.location.endLine;\n const snippet = emittedSnippet(f, redactSnippets);\n\n return {\n ruleId: f.ruleId,\n ruleIndex: ruleIndex.get(f.ruleId),\n level: sarifLevel(f.severity),\n message: { text: f.message },\n // Line-INSENSITIVE fingerprint (the same one the baseline uses:\n // sha256 of ruleId|file|normalizedSnippet). GitHub code scanning keys\n // alert identity + dedup off partialFingerprints, so a finding survives\n // line shifts and reformatting instead of re-alerting as \"new\" on every\n // edit above it. `quantakrypto/v1` names our scheme.\n partialFingerprints: { \"quantakrypto/v1\": fingerprintFinding(f) },\n properties: {\n // Same stable identity mirrored into properties so non-GitHub SARIF\n // consumers (our platform ingest) can read one uniform `fingerprint`\n // field across JSON and SARIF without reaching into partialFingerprints.\n fingerprint: fingerprintFinding(f),\n category: f.category,\n severity: f.severity,\n confidence: f.confidence,\n hndl: f.hndl,\n ...(f.algorithm ? { algorithm: f.algorithm } : {}),\n ...(f.remediation ? { remediation: f.remediation } : {}),\n ...(f.cwe ? { cwe: f.cwe } : {}),\n ...exposureProperties(exposureFor(f, opts?.hndl)),\n },\n ...(f.cwe\n ? {\n taxa: [\n {\n target: { id: f.cwe, toolComponent: { name: \"CWE\" } },\n },\n ],\n }\n : {}),\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: f.location.file },\n region: {\n ...region,\n ...(snippet ? { snippet: { text: snippet } } : {}),\n },\n },\n },\n ],\n };\n });\n\n // CWE taxonomy component (SARIF taxonomies), referenced by rules + results.\n const taxonomies =\n cweTaxa.size > 0\n ? [\n {\n name: \"CWE\",\n informationUri: \"https://cwe.mitre.org/\",\n organization: \"MITRE\",\n shortDescription: { text: \"The MITRE Common Weakness Enumeration\" },\n taxa: [...cweTaxa].sort().map((id) => ({\n id,\n helpUri: `https://cwe.mitre.org/data/definitions/${id.replace(/^CWE-/, \"\")}.html`,\n })),\n },\n ]\n : [];\n\n return {\n $schema: SARIF_SCHEMA,\n version: \"2.1.0\",\n runs: [\n {\n tool: {\n driver: {\n name: \"qScan\",\n informationUri: INFORMATION_URI,\n version: result.toolVersion || VERSION,\n rules,\n },\n },\n ...(taxonomies.length > 0 ? { taxonomies } : {}),\n ...(opts?.hndl ? { properties: { hndl: hndlSummaryBlock(opts.hndl) } } : {}),\n results,\n },\n ],\n };\n}\n\n/** GitHub-code-scanning `security-severity` (0–10) derived from our severity. */\nfunction securitySeverity(severity: Severity): string {\n switch (severity) {\n case \"critical\":\n return \"9.5\";\n case \"high\":\n return \"8.0\";\n case \"medium\":\n return \"5.0\";\n case \"low\":\n return \"3.0\";\n default:\n return \"1.0\";\n }\n}\n\n/** Serialize a scan result as a plain JSON-friendly object. */\nexport function toJson(result: ScanResult, opts?: ReportOptions): Record<string, unknown> {\n const redactSnippets = opts?.redactSnippets ?? false;\n const hndl = opts?.hndl;\n return {\n toolVersion: result.toolVersion,\n root: result.root,\n startedAt: result.startedAt,\n finishedAt: result.finishedAt,\n filesScanned: result.filesScanned,\n ...(result.analyzedFiles !== undefined ? { analyzedFiles: result.analyzedFiles } : {}),\n ...(result.diagnostics ? { diagnostics: result.diagnostics } : {}),\n inventory: {\n readinessScore: result.inventory.readinessScore,\n hndlCount: result.inventory.hndlCount,\n bySeverity: result.inventory.bySeverity,\n byCategory: result.inventory.byCategory,\n byAlgorithm: result.inventory.byAlgorithm,\n },\n ...(hndl ? { hndl: hndlSummaryBlock(hndl) } : {}),\n findings: result.findings.map((f) => {\n const exposure = exposureFor(f, hndl);\n return {\n // Stable, line-INSENSITIVE identity of the finding: sha256 of\n // ruleId | normalized-POSIX-repo-relative-path | normalized-snippet\n // (the SARIF partialFingerprints trick, line number deliberately\n // excluded). Reused verbatim from the baseline module so JSON identity,\n // SARIF partialFingerprints, and the baseline suppression set are one and\n // the same value. A line move does NOT change it; when no snippet context\n // exists it falls back to ruleId|path. This is the cross-run identity the\n // platform keys posture drift on.\n fingerprint: fingerprintFinding(f),\n ruleId: f.ruleId,\n title: f.title,\n category: f.category,\n severity: f.severity,\n confidence: f.confidence,\n algorithm: f.algorithm,\n hndl: f.hndl,\n message: f.message,\n remediation: f.remediation,\n cwe: f.cwe,\n location: {\n file: f.location.file,\n line: f.location.line,\n column: f.location.column,\n endLine: f.location.endLine,\n snippet: emittedSnippet(f, redactSnippets),\n },\n ...(exposure\n ? {\n exposure: {\n fingerprint: exposure.fingerprint,\n exposureScore: exposure.exposureScore,\n dataAsset: exposure.dataAsset,\n rationale: exposure.rationale,\n },\n }\n : {}),\n };\n }),\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Human-readable summary */\n/* -------------------------------------------------------------------------- */\n\n/** Raw ANSI codes (no chalk). Disabled when colour is off. */\nconst ANSI = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n blue: \"\\x1b[34m\",\n magenta: \"\\x1b[35m\",\n cyan: \"\\x1b[36m\",\n} as const;\n\nfunction severityColor(sev: Severity): string {\n switch (sev) {\n case \"critical\":\n return ANSI.magenta;\n case \"high\":\n return ANSI.red;\n case \"medium\":\n return ANSI.yellow;\n case \"low\":\n return ANSI.blue;\n default:\n return ANSI.dim;\n }\n}\n\nfunction scoreColor(score: number): string {\n if (score >= 80) return ANSI.green;\n if (score >= 50) return ANSI.yellow;\n return ANSI.red;\n}\n\n/**\n * Render a human-readable summary of a scan result. Colour is off by default;\n * pass `{ color: true }` to emit ANSI escape codes.\n */\nexport function formatSummary(\n result: ScanResult,\n options?: { color?: boolean; tier?: SecurityTier },\n): string {\n const color = options?.color ?? false;\n const c = (code: string, text: string): string => (color ? `${code}${text}${ANSI.reset}` : text);\n\n const lines: string[] = [];\n const inv = result.inventory;\n\n lines.push(c(ANSI.bold, \"qScan — post-quantum readiness report\"));\n lines.push(c(ANSI.dim, `tool v${result.toolVersion} · root: ${result.root}`));\n lines.push(\"\");\n\n // Readiness score banner.\n lines.push(\n `Readiness score: ${c(`${ANSI.bold}${scoreColor(inv.readinessScore)}`, `${inv.readinessScore}/100`)}`,\n );\n const analyzed =\n result.analyzedFiles !== undefined\n ? ` Analyzed (${ANALYZABLE_LANGUAGES_LABEL}): ${result.analyzedFiles}`\n : \"\";\n lines.push(\n `Files scanned: ${result.filesScanned}${analyzed} Findings: ${result.findings.length} HNDL-exposed: ${c(\n inv.hndlCount > 0 ? ANSI.red : ANSI.green,\n String(inv.hndlCount),\n )}`,\n );\n // Coverage honesty: a score over zero analyzable files is not a clean bill of health.\n if (result.analyzedFiles === 0 && result.filesScanned > 0) {\n lines.push(\n c(\n ANSI.yellow,\n `Note: 0 files were in a supported source language (${ANALYZABLE_LANGUAGES_LABEL}) — the readiness score does not reflect this codebase.`,\n ),\n );\n }\n // Coverage diagnostics: skipped files mean the finding count may be incomplete.\n const diag = result.diagnostics;\n if (diag && (diag.unreadable > 0 || diag.skippedMinified > 0)) {\n lines.push(\n c(\n ANSI.yellow,\n `Coverage: ${diag.unreadable} unreadable, ${diag.skippedMinified} skipped as minified — results may be incomplete.`,\n ),\n );\n }\n lines.push(\"\");\n\n // Severity breakdown.\n const sevParts = SEVERITY_ORDER.filter((s) => inv.bySeverity[s] > 0).map((s) =>\n c(severityColor(s), `${s}: ${inv.bySeverity[s]}`),\n );\n lines.push(`By severity: ${sevParts.length ? sevParts.join(\" \") : c(ANSI.green, \"none\")}`);\n\n // Algorithm breakdown.\n const algoParts = Object.entries(inv.byAlgorithm)\n .sort((a, b) => b[1] - a[1])\n .map(([k, v]) => `${k}: ${v}`);\n if (algoParts.length) lines.push(`By algorithm: ${algoParts.join(\" \")}`);\n lines.push(\"\");\n\n if (result.findings.length === 0) {\n lines.push(c(ANSI.green, \"No classical asymmetric cryptography detected. ✓\"));\n return lines.join(\"\\n\");\n }\n\n // Top findings, grouped by severity (most severe first), capped for readability.\n const sorted = [...result.findings].sort(\n (a, b) => SEVERITY_ORDER.indexOf(a.severity) - SEVERITY_ORDER.indexOf(b.severity),\n );\n const MAX_SHOWN = 25;\n lines.push(\n c(ANSI.bold, `Top findings (${Math.min(MAX_SHOWN, sorted.length)} of ${sorted.length}):`),\n );\n\n for (const f of sorted.slice(0, MAX_SHOWN)) {\n const loc = `${f.location.file}:${f.location.line}${\n f.location.column ? `:${f.location.column}` : \"\"\n }`;\n const tag = c(severityColor(f.severity), `[${f.severity}]`);\n const hndl = f.hndl ? c(ANSI.red, \" (HNDL)\") : \"\";\n lines.push(` ${tag} ${f.title}${hndl}`);\n lines.push(c(ANSI.dim, ` ${loc} — ${f.message}`));\n if (f.remediation) lines.push(c(ANSI.cyan, ` → ${f.remediation}`));\n }\n\n if (sorted.length > MAX_SHOWN) {\n lines.push(c(ANSI.dim, ` …and ${sorted.length - MAX_SHOWN} more.`));\n }\n\n lines.push(\"\");\n if (inv.hndlCount > 0) {\n lines.push(\n c(\n ANSI.yellow,\n `Note: ${inv.hndlCount} finding(s) are exposed to \"harvest now, decrypt later\" — ` +\n \"encrypted traffic captured today can be decrypted once a quantum computer exists. \" +\n \"Prioritise migrating key exchange / encryption to hybrid PQC (X25519MLKEM768).\",\n ),\n );\n }\n\n if (options?.tier) {\n lines.push(\"\", ...formatTierGuidance(inv.byAlgorithm, options.tier));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Per-family migration targets for a CNSA security tier — surfaces the otherwise\n * library-only {@link remediationForTier} in human reports. Category 5 shows the\n * ML-KEM-1024 / ML-DSA-87 sets CNSA 2.0 mandates for national-security systems and\n * long-lived secrets. Returns plain (un-coloured) lines; the caller styles them.\n */\nexport function formatTierGuidance(\n byAlgorithm: Record<string, number>,\n tier: SecurityTier,\n): string[] {\n const label = tier === \"category-5\" ? \"CNSA 2.0 (Category 5)\" : \"Category 3 (commercial)\";\n const out: string[] = [`${label} migration targets:`];\n const seen = new Set<string>();\n for (const [k, n] of Object.entries(byAlgorithm)) {\n if (n <= 0) continue;\n const fam = k as AlgorithmFamily;\n if (fam === \"unknown\" || !remediationFor(fam)) continue; // skip unmapped families\n const rem = remediationForTier(fam, tier);\n if (seen.has(rem.recommendation)) continue;\n seen.add(rem.recommendation);\n out.push(` ${fam} → ${rem.recommendation}`);\n }\n if (tier === \"category-5\") {\n out.push(\n \" CNSA 2.0 mandates ML-KEM-1024 / ML-DSA-87 for national-security systems and long-lived secrets (2030/2033 milestones).\",\n );\n }\n return out;\n}\n\n/**\n * Per-family migration targets tailored to a selected {@link StandardsProfile}\n * (`--profile`). Unlike {@link formatTierGuidance} (CNSA-tier only), this surfaces the\n * regime's parameter sets AND its hybrid stance — required (ANSSI/BSI) vs recommended\n * (NIST/NCSC) vs optional (CNSA 2.0) — so guidance isn't regime-wrong. Returns plain\n * (un-coloured) lines; the caller styles them.\n */\nexport function formatProfileGuidance(\n byAlgorithm: Record<string, number>,\n profile: StandardsProfile,\n): string[] {\n const out: string[] = [`${profile.name} migration targets:`];\n const seen = new Set<string>();\n for (const [k, n] of Object.entries(byAlgorithm)) {\n if (n <= 0) continue;\n const fam = k as AlgorithmFamily;\n if (fam === \"unknown\" || !remediationFor(fam)) continue; // skip unmapped families\n const rem = remediationForProfile(fam, profile);\n if (seen.has(rem.recommendation)) continue;\n seen.add(rem.recommendation);\n out.push(` ${fam} → ${rem.recommendation}`);\n }\n const stance =\n profile.hybridStance === \"required\"\n ? \"requires classical+PQC hybridization\"\n : profile.hybridStance === \"recommended\"\n ? \"recommends hybridization\"\n : \"does not require hybridization\";\n out.push(\n ` ${profile.authority} ${stance}; classical public-key crypto disallowed after ${profile.disallowAfter} (${profile.citation}).`,\n );\n return out;\n}\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -68,7 +68,7 @@ export interface Finding {
|
|
|
68
68
|
location: SourceLocation;
|
|
69
69
|
}
|
|
70
70
|
/** Package ecosystems the dependency scanner understands. */
|
|
71
|
-
export type DependencyEcosystem = "npm" | "pypi" | "cargo" | "go" | "maven" | "rubygems" | "nuget";
|
|
71
|
+
export type DependencyEcosystem = "npm" | "pypi" | "cargo" | "go" | "maven" | "rubygems" | "nuget" | "composer";
|
|
72
72
|
/** A known quantum-vulnerable dependency entry. */
|
|
73
73
|
export interface VulnerableDependency {
|
|
74
74
|
/** Package name (as written in the ecosystem's manifest). */
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,6DAA6D;AAC7D,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEvE,gFAAgF;AAChF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEnD,+DAA+D;AAC/D,MAAM,MAAM,eAAe,GACvB,KAAK,GACL,cAAc,GACd,WAAW,GACX,KAAK,GACL,aAAa,GACb,YAAY,GACZ,MAAM,GACN,KAAK,CAAC;AAEV,yEAAyE;AACzE,MAAM,MAAM,eAAe,GACvB,KAAK,GACL,MAAM,GACN,OAAO,GACP,OAAO,GACP,IAAI,GACJ,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,SAAS,CAAC;AAEd,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AAEtD;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,cAAc,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,iCAAiC;AACjC,MAAM,WAAW,OAAO;IACtB,uGAAuG;IACvG,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,yDAAyD;IACzD,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,iEAAiE;IACjE,IAAI,EAAE,OAAO,CAAC;IACd,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kFAAkF;IAClF,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,6DAA6D;AAC7D,MAAM,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * @quantakrypto/core — shared types (the locked public contract).\n *\n * These types are the stable interface between every tool in the monorepo\n * (qScan, the MCP server, the GitHub Action). Treat additions as backwards\n * compatible; treat renames/removals as breaking.\n */\n\n/** How serious a finding is, ordered most → least severe. */\nexport type Severity = \"critical\" | \"high\" | \"medium\" | \"low\" | \"info\";\n\n/** How sure the detector is that the finding is a real use of the algorithm. */\nexport type Confidence = \"high\" | \"medium\" | \"low\";\n\n/** What kind of cryptographic concern a finding represents. */\nexport type FindingCategory =\n | \"kem\" // key encapsulation / public-key encryption (e.g. RSA-OAEP)\n | \"key-exchange\" // (EC)DH\n | \"signature\" // RSA/ECDSA/EdDSA signing\n | \"tls\" // transport configuration\n | \"certificate\" // X.509 / PKI material\n | \"dependency\" // a quantum-vulnerable library in the dependency tree\n | \"hash\" // weak / pre-quantum hash usage\n | \"rng\"; // randomness concerns\n\n/** Classical asymmetric algorithm families that are not quantum-safe. */\nexport type AlgorithmFamily =\n | \"RSA\"\n | \"ECDH\"\n | \"ECDSA\"\n | \"EdDSA\"\n | \"DH\"\n | \"DSA\"\n | \"X25519\"\n | \"X448\"\n | \"ECIES\"\n | \"unknown\";\n\n/** A precise location inside a scanned file. */\nexport interface SourceLocation {\n /** Path relative to the scan root, using POSIX separators. */\n file: string;\n /** 1-based line number. */\n line: number;\n /** 1-based column number, if known. */\n column?: number;\n /** 1-based end line, for multi-line matches. */\n endLine?: number;\n /** The matched source text (trimmed, single line). */\n snippet?: string;\n}\n\n/** Relative urgency an LLM triage pass assigns to a finding. */\nexport type TriagePriority = \"now\" | \"soon\" | \"later\";\n\n/**\n * Optional LLM triage annotation attached to a finding by `qscan --triage`.\n * Purely additive: it re-ranks and explains, it never suppresses a finding and\n * never influences the exit code (which is computed from `severity` alone).\n */\nexport interface TriageAnnotation {\n /** 0–100 real-world exposure/exploitability estimate. */\n exposureScore: number;\n priority: TriagePriority;\n rationale: string;\n}\n\n/** A single detected concern. */\nexport interface Finding {\n /** Stable rule identifier, e.g. \"rsa-keygen\", \"ecdh-usage\", \"tls-legacy-version\", \"dep-vulnerable\". */\n ruleId: string;\n title: string;\n category: FindingCategory;\n severity: Severity;\n confidence: Confidence;\n /** The classical algorithm involved, when applicable. */\n algorithm?: AlgorithmFamily;\n /** True when this is exposed to \"harvest now, decrypt later\". */\n hndl: boolean;\n /** One-line human explanation of the concern. */\n message: string;\n /** Suggested post-quantum remediation (e.g. ML-KEM, hybrid X25519MLKEM768). */\n remediation?: string;\n /** Associated CWE identifier, e.g. \"CWE-327\" (broken crypto), \"CWE-326\" (weak strength). */\n cwe?: string;\n /**\n * True when the matched snippet IS the sensitive value (e.g. a PEM private/\n * public key block, an `ssh-rsa AAAA…` public key). Reporters ALWAYS drop the\n * snippet for such findings, regardless of any redaction flag.\n */\n sensitive?: boolean;\n /** Optional LLM triage annotation (`qscan --triage`); never affects exit code. */\n triage?: TriageAnnotation;\n location: SourceLocation;\n}\n\n/** Package ecosystems the dependency scanner understands. */\nexport type DependencyEcosystem = \"npm\" | \"pypi\" | \"cargo\" | \"go\" | \"maven\" | \"rubygems\" | \"nuget\";\n\n/** A known quantum-vulnerable dependency entry. */\nexport interface VulnerableDependency {\n /** Package name (as written in the ecosystem's manifest). */\n name: string;\n ecosystem: DependencyEcosystem;\n /** Why it's flagged (what classical crypto it provides). */\n reason: string;\n /** Algorithm families the package primarily exposes. */\n algorithms: AlgorithmFamily[];\n severity: Severity;\n /**\n * Explicit harvest-now-decrypt-later override. When omitted, HNDL is inferred\n * from whether any listed family is a confidentiality family. Set `false` for\n * signing-only packages (e.g. JWS/JWT libraries) that list RSA/EC as families\n * but never do key transport or key agreement — signatures are not HNDL-exposed.\n */\n hndl?: boolean;\n}\n\n/**\n * Which logical scope a detector belongs to. Drives the source/config scope\n * toggles in {@link ScanOptions} (replacing the old ruleId-prefix inference).\n */\nexport type DetectorScope = \"source\" | \"config\";\n\n/**\n * The programming language / surface a detector targets. `\"any\"` means the\n * detector is language-agnostic (e.g. PEM material, config files).\n */\nexport type DetectorLanguage =\n | \"js\"\n | \"python\"\n | \"go\"\n | \"java\"\n | \"csharp\"\n | \"rust\"\n | \"ruby\"\n | \"php\"\n | \"elixir\"\n | \"c\"\n | \"swift\"\n | \"objc\"\n | \"dart\"\n | \"solidity\"\n | \"any\";\n\n/**\n * Declarative metadata for a single rule a detector can emit. This is the\n * catalog entry: the stable, queryable description of a rule keyed by the\n * `ruleId` it stamps onto findings. It is the single source of truth for a\n * rule's title / severity / category / remediation, consumed by the SARIF\n * `rules[]` block, the MCP `explain_finding` resolver, and future per-rule\n * enable/disable + language-pack work.\n *\n * For most rules the metadata is fixed and `detect()` builds findings straight\n * from it (see `findingFromRule`). A few rules are inherently multi-variant\n * (e.g. `node-crypto-keygen` spans RSA/EC/DSA/DH/Ed25519 at different\n * severities); for those the metadata here is a REPRESENTATIVE umbrella and\n * `detect()` refines the per-finding fields at match time. The catalog always\n * enumerates every emittable ruleId regardless.\n */\nexport interface RuleMeta {\n /** Stable rule id — matches {@link Finding.ruleId}. Unique across the catalog. */\n id: string;\n /** Canonical human title. */\n title: string;\n category: FindingCategory;\n severity: Severity;\n /** Default confidence for findings of this rule. */\n confidence: Confidence;\n /** Harvest-now-decrypt-later exposure. */\n hndl: boolean;\n /** Representative classical algorithm family; refined per-finding when it varies. */\n algorithm?: AlgorithmFamily;\n /** Associated CWE identifier (e.g. \"CWE-327\"). */\n cwe?: string;\n /** Suggested post-quantum remediation. When omitted, derived from {@link algorithm}. */\n remediation?: string;\n /** Canonical one-line human explanation; may be refined per-finding. */\n message: string;\n /** True when this rule's matched snippet IS sensitive key material. */\n sensitive?: boolean;\n /** Short description of what the rule detects (for catalog / MCP surfaces). */\n description?: string;\n}\n\n/** A pluggable source detector. Detectors are pure and stateless. */\nexport interface Detector {\n /** Unique id, used as the Finding.ruleId prefix space. */\n id: string;\n /** Human description of what the detector looks for. */\n description: string;\n /**\n * Logical scope of this detector's findings. Used by `scan()` to honour the\n * `config` / `source` toggles. Defaults to `\"source\"` when omitted (for\n * backward compatibility with externally-defined detectors).\n */\n scope?: DetectorScope;\n /**\n * Language this detector targets, for documentation / registry filtering.\n * Defaults to `\"js\"` when omitted.\n */\n language?: DetectorLanguage;\n /**\n * The rules this detector can emit, as declarative metadata. Together across\n * all detectors these form the rule catalog ({@link DetectorRegistry.ruleCatalog}).\n * Optional for backward compatibility with externally-defined detectors, but\n * all built-in detectors declare it.\n */\n rules?: RuleMeta[];\n /** Whether this detector should run against the given file path. */\n appliesTo(filePath: string): boolean;\n /** Inspect a single file's contents and return zero or more findings. */\n detect(input: DetectorInput): Finding[];\n}\n\nexport interface DetectorInput {\n /** Path relative to the scan root (POSIX). */\n file: string;\n /** Full file contents. */\n content: string;\n}\n\n/** Options controlling a scan. */\nexport interface ScanOptions {\n /** Absolute or relative directory (or single file) to scan. */\n root: string;\n /**\n * Restrict the walk to paths matching one of these include patterns\n * (substring or relative-path-prefix match). When omitted, all non-excluded\n * files are scanned. Wired into the walker.\n */\n include?: string[];\n /** Extra exclude patterns (in addition to the built-in defaults). */\n exclude?: string[];\n /** Disable the built-in ignore list (node_modules, .git, dist, …). */\n noDefaultIgnores?: boolean;\n /** Scan source files for inline crypto usage. Default: true. */\n source?: boolean;\n /** Scan dependency manifests/lockfiles for vulnerable libraries. Default: true. */\n dependencies?: boolean;\n /** Scan config files (TLS, certificates). Default: true. */\n config?: boolean;\n /** Max file size to read, in bytes. Default: 2 MiB. */\n maxFileSize?: number;\n /**\n * Scan minified / generated / bundled files (large single-line content)\n * instead of skipping them. Default: false (skip them for speed).\n */\n scanMinified?: boolean;\n /**\n * Explicit relative file list (POSIX, relative to `root`) to scan instead of\n * walking the tree. Used for incremental / changed-files scans. Each path is\n * still subject to the binary / size filters. When set, the directory walk is\n * bypassed entirely.\n */\n files?: string[];\n /**\n * Override / extend the built-in detector set. When omitted, the default\n * registry's detectors are used.\n */\n detectors?: Detector[];\n /**\n * Rule ids to suppress. Any finding whose `ruleId` is listed here is dropped\n * after detection. Serializable (a plain string array), so it is honoured on\n * both the serial and the worker-thread (`scanParallel`) paths. See the rule\n * catalog ({@link DetectorRegistry.ruleCatalog}) for the valid ids.\n */\n disabledRules?: string[];\n /**\n * Path to an on-disk scan cache. When set, unchanged files (same content hash)\n * reuse their previous findings instead of re-running detectors, and the cache\n * is rewritten after the scan. Invalidated wholesale when the tool version,\n * detector set, or `disabledRules` change. Optional; omitted = no caching.\n * The cache forces the in-process (serial) path.\n */\n cacheFile?: string;\n /** Optional progress callback. */\n onFile?: (file: string) => void;\n /**\n * Optional abort signal. When it fires mid-walk the scan stops cooperatively\n * and rejects with an `AbortError` (a `DOMException`-like error with\n * `name === \"AbortError\"`).\n */\n signal?: AbortSignal;\n /**\n * Work budget: maximum number of files to scan. When exceeded mid-walk the\n * scan stops and throws a `BudgetExceededError`. Unlimited when omitted.\n */\n maxFiles?: number;\n /**\n * Work budget: maximum cumulative bytes of scanned file content. When\n * exceeded mid-walk the scan stops and throws a `BudgetExceededError`.\n * Unlimited when omitted.\n */\n maxBytes?: number;\n}\n\n/** Extra options for {@link scanParallel}, layered onto {@link ScanOptions}. */\nexport interface ParallelScanOptions extends ScanOptions {\n /**\n * Number of worker threads. Default: `os.availableParallelism()`. A value of\n * 0 or 1 forces the in-process serial path.\n */\n concurrency?: number;\n /**\n * Combined-size floor (bytes) below which the scan always runs in-process.\n * Default: 2 MiB. Also stays serial below `parallelFileThreshold` files.\n */\n parallelThresholdBytes?: number;\n /** File-count floor below which the scan always runs in-process. Default: 200. */\n parallelFileThreshold?: number;\n /** Target bytes per worker chunk. Default: 4 MiB. */\n chunkBytes?: number;\n}\n\n/** Aggregated counts produced from a scan's findings. */\nexport interface CryptoInventory {\n byAlgorithm: Partial<Record<AlgorithmFamily, number>>;\n byCategory: Partial<Record<FindingCategory, number>>;\n bySeverity: Record<Severity, number>;\n /** Number of findings exposed to harvest-now-decrypt-later. */\n hndlCount: number;\n /** 0–100 readiness score (100 = no classical asymmetric crypto found). */\n readinessScore: number;\n}\n\n/**\n * Non-fatal things that happened during a scan that reduce coverage. Surfaced so\n * a silent under-scan (e.g. half the tree was unreadable) can't masquerade as a\n * clean \"0 findings\" result — reporters warn when any count is non-zero.\n */\nexport interface ScanDiagnostics {\n /** Files that could not be read (permissions, vanished, decode failure) and were skipped. */\n unreadable: number;\n /** Files skipped because they look machine-minified / generated (scan with `scanMinified` to include). */\n skippedMinified: number;\n}\n\n/** The full result of a scan. */\nexport interface ScanResult {\n /** The scan root (as provided). */\n root: string;\n findings: Finding[];\n filesScanned: number;\n /**\n * Coverage diagnostics: counts of files skipped as unreadable or minified.\n * Optional for backward compatibility with hand-built results.\n */\n diagnostics?: ScanDiagnostics;\n /**\n * Of `filesScanned`, how many were in a source language the scanner can actually\n * analyze for inline crypto (the 13 packs: JS/TS, Python, Go, Java/Kotlin/Scala,\n * C#, Rust, Ruby, PHP, Elixir, C/C++, Swift, Objective-C, Dart). When this is 0\n * but `filesScanned` > 0, the readiness score reflects NO analyzable code — the\n * crypto likely lives in an unsupported language (Lua, Perl, …) — and\n * reporters surface that so a bare 100/100 can't read as \"safe\". Optional for\n * backward compatibility with hand-built results.\n */\n analyzedFiles?: number;\n inventory: CryptoInventory;\n /** ISO timestamps. */\n startedAt: string;\n finishedAt: string;\n /** Tool version that produced the result. */\n toolVersion: string;\n}\n\n/** Output formats qScan / reporters can emit. */\nexport type ReportFormat = \"human\" | \"json\" | \"sarif\";\n\n/** A remediation recommendation for a classical algorithm. */\nexport interface Remediation {\n algorithm: AlgorithmFamily;\n /** Short recommended replacement, e.g. \"ML-KEM-768 (hybrid X25519MLKEM768)\". */\n recommendation: string;\n /** Longer rationale. */\n detail: string;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * @quantakrypto/core — shared types (the locked public contract).\n *\n * These types are the stable interface between every tool in the monorepo\n * (qScan, the MCP server, the GitHub Action). Treat additions as backwards\n * compatible; treat renames/removals as breaking.\n */\n\n/** How serious a finding is, ordered most → least severe. */\nexport type Severity = \"critical\" | \"high\" | \"medium\" | \"low\" | \"info\";\n\n/** How sure the detector is that the finding is a real use of the algorithm. */\nexport type Confidence = \"high\" | \"medium\" | \"low\";\n\n/** What kind of cryptographic concern a finding represents. */\nexport type FindingCategory =\n | \"kem\" // key encapsulation / public-key encryption (e.g. RSA-OAEP)\n | \"key-exchange\" // (EC)DH\n | \"signature\" // RSA/ECDSA/EdDSA signing\n | \"tls\" // transport configuration\n | \"certificate\" // X.509 / PKI material\n | \"dependency\" // a quantum-vulnerable library in the dependency tree\n | \"hash\" // weak / pre-quantum hash usage\n | \"rng\"; // randomness concerns\n\n/** Classical asymmetric algorithm families that are not quantum-safe. */\nexport type AlgorithmFamily =\n | \"RSA\"\n | \"ECDH\"\n | \"ECDSA\"\n | \"EdDSA\"\n | \"DH\"\n | \"DSA\"\n | \"X25519\"\n | \"X448\"\n | \"ECIES\"\n | \"unknown\";\n\n/** A precise location inside a scanned file. */\nexport interface SourceLocation {\n /** Path relative to the scan root, using POSIX separators. */\n file: string;\n /** 1-based line number. */\n line: number;\n /** 1-based column number, if known. */\n column?: number;\n /** 1-based end line, for multi-line matches. */\n endLine?: number;\n /** The matched source text (trimmed, single line). */\n snippet?: string;\n}\n\n/** Relative urgency an LLM triage pass assigns to a finding. */\nexport type TriagePriority = \"now\" | \"soon\" | \"later\";\n\n/**\n * Optional LLM triage annotation attached to a finding by `qscan --triage`.\n * Purely additive: it re-ranks and explains, it never suppresses a finding and\n * never influences the exit code (which is computed from `severity` alone).\n */\nexport interface TriageAnnotation {\n /** 0–100 real-world exposure/exploitability estimate. */\n exposureScore: number;\n priority: TriagePriority;\n rationale: string;\n}\n\n/** A single detected concern. */\nexport interface Finding {\n /** Stable rule identifier, e.g. \"rsa-keygen\", \"ecdh-usage\", \"tls-legacy-version\", \"dep-vulnerable\". */\n ruleId: string;\n title: string;\n category: FindingCategory;\n severity: Severity;\n confidence: Confidence;\n /** The classical algorithm involved, when applicable. */\n algorithm?: AlgorithmFamily;\n /** True when this is exposed to \"harvest now, decrypt later\". */\n hndl: boolean;\n /** One-line human explanation of the concern. */\n message: string;\n /** Suggested post-quantum remediation (e.g. ML-KEM, hybrid X25519MLKEM768). */\n remediation?: string;\n /** Associated CWE identifier, e.g. \"CWE-327\" (broken crypto), \"CWE-326\" (weak strength). */\n cwe?: string;\n /**\n * True when the matched snippet IS the sensitive value (e.g. a PEM private/\n * public key block, an `ssh-rsa AAAA…` public key). Reporters ALWAYS drop the\n * snippet for such findings, regardless of any redaction flag.\n */\n sensitive?: boolean;\n /** Optional LLM triage annotation (`qscan --triage`); never affects exit code. */\n triage?: TriageAnnotation;\n location: SourceLocation;\n}\n\n/** Package ecosystems the dependency scanner understands. */\nexport type DependencyEcosystem =\n | \"npm\"\n | \"pypi\"\n | \"cargo\"\n | \"go\"\n | \"maven\"\n | \"rubygems\"\n | \"nuget\"\n | \"composer\";\n\n/** A known quantum-vulnerable dependency entry. */\nexport interface VulnerableDependency {\n /** Package name (as written in the ecosystem's manifest). */\n name: string;\n ecosystem: DependencyEcosystem;\n /** Why it's flagged (what classical crypto it provides). */\n reason: string;\n /** Algorithm families the package primarily exposes. */\n algorithms: AlgorithmFamily[];\n severity: Severity;\n /**\n * Explicit harvest-now-decrypt-later override. When omitted, HNDL is inferred\n * from whether any listed family is a confidentiality family. Set `false` for\n * signing-only packages (e.g. JWS/JWT libraries) that list RSA/EC as families\n * but never do key transport or key agreement — signatures are not HNDL-exposed.\n */\n hndl?: boolean;\n}\n\n/**\n * Which logical scope a detector belongs to. Drives the source/config scope\n * toggles in {@link ScanOptions} (replacing the old ruleId-prefix inference).\n */\nexport type DetectorScope = \"source\" | \"config\";\n\n/**\n * The programming language / surface a detector targets. `\"any\"` means the\n * detector is language-agnostic (e.g. PEM material, config files).\n */\nexport type DetectorLanguage =\n | \"js\"\n | \"python\"\n | \"go\"\n | \"java\"\n | \"csharp\"\n | \"rust\"\n | \"ruby\"\n | \"php\"\n | \"elixir\"\n | \"c\"\n | \"swift\"\n | \"objc\"\n | \"dart\"\n | \"solidity\"\n | \"any\";\n\n/**\n * Declarative metadata for a single rule a detector can emit. This is the\n * catalog entry: the stable, queryable description of a rule keyed by the\n * `ruleId` it stamps onto findings. It is the single source of truth for a\n * rule's title / severity / category / remediation, consumed by the SARIF\n * `rules[]` block, the MCP `explain_finding` resolver, and future per-rule\n * enable/disable + language-pack work.\n *\n * For most rules the metadata is fixed and `detect()` builds findings straight\n * from it (see `findingFromRule`). A few rules are inherently multi-variant\n * (e.g. `node-crypto-keygen` spans RSA/EC/DSA/DH/Ed25519 at different\n * severities); for those the metadata here is a REPRESENTATIVE umbrella and\n * `detect()` refines the per-finding fields at match time. The catalog always\n * enumerates every emittable ruleId regardless.\n */\nexport interface RuleMeta {\n /** Stable rule id — matches {@link Finding.ruleId}. Unique across the catalog. */\n id: string;\n /** Canonical human title. */\n title: string;\n category: FindingCategory;\n severity: Severity;\n /** Default confidence for findings of this rule. */\n confidence: Confidence;\n /** Harvest-now-decrypt-later exposure. */\n hndl: boolean;\n /** Representative classical algorithm family; refined per-finding when it varies. */\n algorithm?: AlgorithmFamily;\n /** Associated CWE identifier (e.g. \"CWE-327\"). */\n cwe?: string;\n /** Suggested post-quantum remediation. When omitted, derived from {@link algorithm}. */\n remediation?: string;\n /** Canonical one-line human explanation; may be refined per-finding. */\n message: string;\n /** True when this rule's matched snippet IS sensitive key material. */\n sensitive?: boolean;\n /** Short description of what the rule detects (for catalog / MCP surfaces). */\n description?: string;\n}\n\n/** A pluggable source detector. Detectors are pure and stateless. */\nexport interface Detector {\n /** Unique id, used as the Finding.ruleId prefix space. */\n id: string;\n /** Human description of what the detector looks for. */\n description: string;\n /**\n * Logical scope of this detector's findings. Used by `scan()` to honour the\n * `config` / `source` toggles. Defaults to `\"source\"` when omitted (for\n * backward compatibility with externally-defined detectors).\n */\n scope?: DetectorScope;\n /**\n * Language this detector targets, for documentation / registry filtering.\n * Defaults to `\"js\"` when omitted.\n */\n language?: DetectorLanguage;\n /**\n * The rules this detector can emit, as declarative metadata. Together across\n * all detectors these form the rule catalog ({@link DetectorRegistry.ruleCatalog}).\n * Optional for backward compatibility with externally-defined detectors, but\n * all built-in detectors declare it.\n */\n rules?: RuleMeta[];\n /** Whether this detector should run against the given file path. */\n appliesTo(filePath: string): boolean;\n /** Inspect a single file's contents and return zero or more findings. */\n detect(input: DetectorInput): Finding[];\n}\n\nexport interface DetectorInput {\n /** Path relative to the scan root (POSIX). */\n file: string;\n /** Full file contents. */\n content: string;\n}\n\n/** Options controlling a scan. */\nexport interface ScanOptions {\n /** Absolute or relative directory (or single file) to scan. */\n root: string;\n /**\n * Restrict the walk to paths matching one of these include patterns\n * (substring or relative-path-prefix match). When omitted, all non-excluded\n * files are scanned. Wired into the walker.\n */\n include?: string[];\n /** Extra exclude patterns (in addition to the built-in defaults). */\n exclude?: string[];\n /** Disable the built-in ignore list (node_modules, .git, dist, …). */\n noDefaultIgnores?: boolean;\n /** Scan source files for inline crypto usage. Default: true. */\n source?: boolean;\n /** Scan dependency manifests/lockfiles for vulnerable libraries. Default: true. */\n dependencies?: boolean;\n /** Scan config files (TLS, certificates). Default: true. */\n config?: boolean;\n /** Max file size to read, in bytes. Default: 2 MiB. */\n maxFileSize?: number;\n /**\n * Scan minified / generated / bundled files (large single-line content)\n * instead of skipping them. Default: false (skip them for speed).\n */\n scanMinified?: boolean;\n /**\n * Explicit relative file list (POSIX, relative to `root`) to scan instead of\n * walking the tree. Used for incremental / changed-files scans. Each path is\n * still subject to the binary / size filters. When set, the directory walk is\n * bypassed entirely.\n */\n files?: string[];\n /**\n * Override / extend the built-in detector set. When omitted, the default\n * registry's detectors are used.\n */\n detectors?: Detector[];\n /**\n * Rule ids to suppress. Any finding whose `ruleId` is listed here is dropped\n * after detection. Serializable (a plain string array), so it is honoured on\n * both the serial and the worker-thread (`scanParallel`) paths. See the rule\n * catalog ({@link DetectorRegistry.ruleCatalog}) for the valid ids.\n */\n disabledRules?: string[];\n /**\n * Path to an on-disk scan cache. When set, unchanged files (same content hash)\n * reuse their previous findings instead of re-running detectors, and the cache\n * is rewritten after the scan. Invalidated wholesale when the tool version,\n * detector set, or `disabledRules` change. Optional; omitted = no caching.\n * The cache forces the in-process (serial) path.\n */\n cacheFile?: string;\n /** Optional progress callback. */\n onFile?: (file: string) => void;\n /**\n * Optional abort signal. When it fires mid-walk the scan stops cooperatively\n * and rejects with an `AbortError` (a `DOMException`-like error with\n * `name === \"AbortError\"`).\n */\n signal?: AbortSignal;\n /**\n * Work budget: maximum number of files to scan. When exceeded mid-walk the\n * scan stops and throws a `BudgetExceededError`. Unlimited when omitted.\n */\n maxFiles?: number;\n /**\n * Work budget: maximum cumulative bytes of scanned file content. When\n * exceeded mid-walk the scan stops and throws a `BudgetExceededError`.\n * Unlimited when omitted.\n */\n maxBytes?: number;\n}\n\n/** Extra options for {@link scanParallel}, layered onto {@link ScanOptions}. */\nexport interface ParallelScanOptions extends ScanOptions {\n /**\n * Number of worker threads. Default: `os.availableParallelism()`. A value of\n * 0 or 1 forces the in-process serial path.\n */\n concurrency?: number;\n /**\n * Combined-size floor (bytes) below which the scan always runs in-process.\n * Default: 2 MiB. Also stays serial below `parallelFileThreshold` files.\n */\n parallelThresholdBytes?: number;\n /** File-count floor below which the scan always runs in-process. Default: 200. */\n parallelFileThreshold?: number;\n /** Target bytes per worker chunk. Default: 4 MiB. */\n chunkBytes?: number;\n}\n\n/** Aggregated counts produced from a scan's findings. */\nexport interface CryptoInventory {\n byAlgorithm: Partial<Record<AlgorithmFamily, number>>;\n byCategory: Partial<Record<FindingCategory, number>>;\n bySeverity: Record<Severity, number>;\n /** Number of findings exposed to harvest-now-decrypt-later. */\n hndlCount: number;\n /** 0–100 readiness score (100 = no classical asymmetric crypto found). */\n readinessScore: number;\n}\n\n/**\n * Non-fatal things that happened during a scan that reduce coverage. Surfaced so\n * a silent under-scan (e.g. half the tree was unreadable) can't masquerade as a\n * clean \"0 findings\" result — reporters warn when any count is non-zero.\n */\nexport interface ScanDiagnostics {\n /** Files that could not be read (permissions, vanished, decode failure) and were skipped. */\n unreadable: number;\n /** Files skipped because they look machine-minified / generated (scan with `scanMinified` to include). */\n skippedMinified: number;\n}\n\n/** The full result of a scan. */\nexport interface ScanResult {\n /** The scan root (as provided). */\n root: string;\n findings: Finding[];\n filesScanned: number;\n /**\n * Coverage diagnostics: counts of files skipped as unreadable or minified.\n * Optional for backward compatibility with hand-built results.\n */\n diagnostics?: ScanDiagnostics;\n /**\n * Of `filesScanned`, how many were in a source language the scanner can actually\n * analyze for inline crypto (the 13 packs: JS/TS, Python, Go, Java/Kotlin/Scala,\n * C#, Rust, Ruby, PHP, Elixir, C/C++, Swift, Objective-C, Dart). When this is 0\n * but `filesScanned` > 0, the readiness score reflects NO analyzable code — the\n * crypto likely lives in an unsupported language (Lua, Perl, …) — and\n * reporters surface that so a bare 100/100 can't read as \"safe\". Optional for\n * backward compatibility with hand-built results.\n */\n analyzedFiles?: number;\n inventory: CryptoInventory;\n /** ISO timestamps. */\n startedAt: string;\n finishedAt: string;\n /** Tool version that produced the result. */\n toolVersion: string;\n}\n\n/** Output formats qScan / reporters can emit. */\nexport type ReportFormat = \"human\" | \"json\" | \"sarif\";\n\n/** A remediation recommendation for a classical algorithm. */\nexport interface Remediation {\n algorithm: AlgorithmFamily;\n /** Short recommended replacement, e.g. \"ML-KEM-768 (hybrid X25519MLKEM768)\". */\n recommendation: string;\n /** Longer rationale. */\n detail: string;\n}\n"]}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC","sourcesContent":["/**\n * The tool version surfaced in reports. Kept in its own module so reporters and\n * the scan orchestrator can import it without creating a cycle through index.ts.\n * Keep in sync with packages/core/package.json.\n */\nexport const VERSION = \"0.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC","sourcesContent":["/**\n * The tool version surfaced in reports. Kept in its own module so reporters and\n * the scan orchestrator can import it without creating a cycle through index.ts.\n * Keep in sync with packages/core/package.json.\n */\nexport const VERSION = \"0.6.0\";\n"]}
|
package/dist/walk.d.ts
CHANGED
|
@@ -39,11 +39,41 @@ export declare function isGeneratedPath(rel: string): boolean;
|
|
|
39
39
|
* ~50 KB, in the first ~64 KB sampled. Used at read time, not in the walker.
|
|
40
40
|
*/
|
|
41
41
|
export declare function looksMinified(content: string): boolean;
|
|
42
|
+
/** A scannable file plus the byte size the walker already stat'd for it. */
|
|
43
|
+
export interface WalkedFile {
|
|
44
|
+
/** Relative POSIX path from the walk root. */
|
|
45
|
+
rel: string;
|
|
46
|
+
/** File size in bytes (from the walker's own stat; never re-stat downstream). */
|
|
47
|
+
size: number;
|
|
48
|
+
}
|
|
42
49
|
/**
|
|
43
50
|
* Recursively yield scannable file paths (relative to `root`, POSIX) under a
|
|
44
51
|
* directory. If `root` points at a single file, yields just that file's
|
|
45
|
-
* basename (subject to the size / binary filters).
|
|
52
|
+
* basename (subject to the size / binary filters). Thin wrapper over
|
|
53
|
+
* {@link walkFilesSized} that drops the size (the historical string-yielding API).
|
|
46
54
|
*/
|
|
47
55
|
export declare function walkFiles(root: string, options?: WalkOptions): AsyncGenerator<string>;
|
|
56
|
+
/**
|
|
57
|
+
* Like {@link walkFiles} but yields each file WITH the byte size the walker
|
|
58
|
+
* already obtained while applying the size limit. Callers that need sizes (the
|
|
59
|
+
* parallel scanner's byte-balanced chunking) consume this directly so they do
|
|
60
|
+
* not stat every file a second time (P2 double-stat elimination).
|
|
61
|
+
*/
|
|
62
|
+
export declare function walkFilesSized(root: string, options?: WalkOptions): AsyncGenerator<WalkedFile>;
|
|
63
|
+
/**
|
|
64
|
+
* Manifests bypass the normal file-size cap (they carry the whole dependency
|
|
65
|
+
* tree and must not be dropped), but still get a generous hard ceiling so a
|
|
66
|
+
* pathological or hostile lockfile can't be read unbounded and OOM the scan.
|
|
67
|
+
* 16 MiB comfortably covers real monorepo lockfiles (npm's own is well under 5).
|
|
68
|
+
*/
|
|
69
|
+
export declare const MANIFEST_MAX_BYTES: number;
|
|
70
|
+
/**
|
|
71
|
+
* True if a file passes the size limit. Dependency manifests (package.json /
|
|
72
|
+
* package-lock.json / yarn.lock / …) get the larger {@link MANIFEST_MAX_BYTES}
|
|
73
|
+
* ceiling instead of the ordinary cap, so large lockfiles still get scanned for
|
|
74
|
+
* vulnerable dependencies without letting an enormous one exhaust memory.
|
|
75
|
+
* Exported for unit testing.
|
|
76
|
+
*/
|
|
77
|
+
export declare function passesSizeLimit(rel: string, size: number, maxFileSize: number): boolean;
|
|
48
78
|
export {};
|
|
49
79
|
//# sourceMappingURL=walk.d.ts.map
|
package/dist/walk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"AA0BA,gDAAgD;AAChD,eAAO,MAAM,qBAAqB,QAAkB,CAAC;AAyErD,6CAA6C;AAC7C,UAAU,WAAW;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,0DAA0D;AAC1D,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AA6DD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAc5E;AAgBD,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMjD;AAsBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAInD;AASD,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAmBtD;AAED
|
|
1
|
+
{"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"AA0BA,gDAAgD;AAChD,eAAO,MAAM,qBAAqB,QAAkB,CAAC;AAyErD,6CAA6C;AAC7C,UAAU,WAAW;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,0DAA0D;AAC1D,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AA6DD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAc5E;AAgBD,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMjD;AAsBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAInD;AASD,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAmBtD;AAED,4EAA4E;AAC5E,MAAM,WAAW,UAAU;IACzB,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAuB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,cAAc,CAAC,MAAM,CAAC,CAEhG;AAED;;;;;GAKG;AACH,wBAAuB,cAAc,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,cAAc,CAAC,UAAU,CAAC,CAsB5B;AASD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAmB,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAIvF"}
|
package/dist/walk.js
CHANGED
|
@@ -279,9 +279,20 @@ export function looksMinified(content) {
|
|
|
279
279
|
/**
|
|
280
280
|
* Recursively yield scannable file paths (relative to `root`, POSIX) under a
|
|
281
281
|
* directory. If `root` points at a single file, yields just that file's
|
|
282
|
-
* basename (subject to the size / binary filters).
|
|
282
|
+
* basename (subject to the size / binary filters). Thin wrapper over
|
|
283
|
+
* {@link walkFilesSized} that drops the size (the historical string-yielding API).
|
|
283
284
|
*/
|
|
284
285
|
export async function* walkFiles(root, options = {}) {
|
|
286
|
+
for await (const f of walkFilesSized(root, options))
|
|
287
|
+
yield f.rel;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Like {@link walkFiles} but yields each file WITH the byte size the walker
|
|
291
|
+
* already obtained while applying the size limit. Callers that need sizes (the
|
|
292
|
+
* parallel scanner's byte-balanced chunking) consume this directly so they do
|
|
293
|
+
* not stat every file a second time (P2 double-stat elimination).
|
|
294
|
+
*/
|
|
295
|
+
export async function* walkFilesSized(root, options = {}) {
|
|
285
296
|
const include = options.include ?? [];
|
|
286
297
|
const exclude = options.exclude ?? [];
|
|
287
298
|
const maxFileSize = options.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
@@ -293,22 +304,30 @@ export async function* walkFiles(root, options = {}) {
|
|
|
293
304
|
if (!isBinaryPath(name) &&
|
|
294
305
|
isIncluded(name, include) &&
|
|
295
306
|
passesSizeLimit(name, rootStat.size, maxFileSize)) {
|
|
296
|
-
yield name;
|
|
307
|
+
yield { rel: name, size: rootStat.size };
|
|
297
308
|
}
|
|
298
309
|
return;
|
|
299
310
|
}
|
|
300
311
|
yield* walkDir(root, "", { include, exclude, maxFileSize, ignores });
|
|
301
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* Manifests bypass the normal file-size cap (they carry the whole dependency
|
|
315
|
+
* tree and must not be dropped), but still get a generous hard ceiling so a
|
|
316
|
+
* pathological or hostile lockfile can't be read unbounded and OOM the scan.
|
|
317
|
+
* 16 MiB comfortably covers real monorepo lockfiles (npm's own is well under 5).
|
|
318
|
+
*/
|
|
319
|
+
export const MANIFEST_MAX_BYTES = 16 * 1024 * 1024;
|
|
302
320
|
/**
|
|
303
321
|
* True if a file passes the size limit. Dependency manifests (package.json /
|
|
304
|
-
* package-lock.json
|
|
305
|
-
*
|
|
322
|
+
* package-lock.json / yarn.lock / …) get the larger {@link MANIFEST_MAX_BYTES}
|
|
323
|
+
* ceiling instead of the ordinary cap, so large lockfiles still get scanned for
|
|
324
|
+
* vulnerable dependencies without letting an enormous one exhaust memory.
|
|
325
|
+
* Exported for unit testing.
|
|
306
326
|
*/
|
|
307
|
-
function passesSizeLimit(rel, size, maxFileSize) {
|
|
308
|
-
//
|
|
309
|
-
// the whole dependency tree). Uses the single {@link isManifestFile} definition.
|
|
327
|
+
export function passesSizeLimit(rel, size, maxFileSize) {
|
|
328
|
+
// Uses the single {@link isManifestFile} definition.
|
|
310
329
|
if (isManifestFile(rel))
|
|
311
|
-
return
|
|
330
|
+
return size <= MANIFEST_MAX_BYTES;
|
|
312
331
|
return size <= maxFileSize;
|
|
313
332
|
}
|
|
314
333
|
/** Internal recursive directory walker. `relDir` is POSIX-relative to the root. */
|
|
@@ -351,15 +370,17 @@ async function* walkDir(absDir, relDir, ctx) {
|
|
|
351
370
|
continue;
|
|
352
371
|
if (!manifest && isGeneratedPath(rel))
|
|
353
372
|
continue;
|
|
373
|
+
let size;
|
|
354
374
|
try {
|
|
355
375
|
const s = await stat(abs);
|
|
356
376
|
if (!passesSizeLimit(rel, s.size, ctx.maxFileSize))
|
|
357
377
|
continue;
|
|
378
|
+
size = s.size;
|
|
358
379
|
}
|
|
359
380
|
catch {
|
|
360
381
|
continue;
|
|
361
382
|
}
|
|
362
|
-
yield rel;
|
|
383
|
+
yield { rel, size };
|
|
363
384
|
}
|
|
364
385
|
}
|
|
365
386
|
//# sourceMappingURL=walk.js.map
|