@quantakrypto/core 0.4.4 → 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/README.md +76 -27
- package/dist/cbom-merge.d.ts.map +1 -1
- package/dist/cbom-merge.js +30 -8
- package/dist/cbom-merge.js.map +1 -1
- package/dist/cbom.d.ts +5 -0
- package/dist/cbom.d.ts.map +1 -1
- package/dist/cbom.js +132 -37
- package/dist/cbom.js.map +1 -1
- package/dist/comments.d.ts +2 -23
- package/dist/comments.d.ts.map +1 -1
- package/dist/comments.js +24 -5
- package/dist/comments.js.map +1 -1
- 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/detect-utils.d.ts +55 -21
- package/dist/detect-utils.d.ts.map +1 -1
- package/dist/detect-utils.js +133 -7
- package/dist/detect-utils.js.map +1 -1
- package/dist/detectors/age.d.ts +16 -0
- package/dist/detectors/age.d.ts.map +1 -0
- package/dist/detectors/age.js +40 -0
- package/dist/detectors/age.js.map +1 -0
- package/dist/detectors/ansible.d.ts +13 -0
- package/dist/detectors/ansible.d.ts.map +1 -0
- package/dist/detectors/ansible.js +108 -0
- package/dist/detectors/ansible.js.map +1 -0
- package/dist/detectors/bicep.d.ts +20 -0
- package/dist/detectors/bicep.d.ts.map +1 -0
- package/dist/detectors/bicep.js +74 -0
- package/dist/detectors/bicep.js.map +1 -0
- package/dist/detectors/c.d.ts.map +1 -1
- package/dist/detectors/c.js +30 -3
- package/dist/detectors/c.js.map +1 -1
- package/dist/detectors/cicd.d.ts.map +1 -1
- package/dist/detectors/cicd.js +18 -5
- package/dist/detectors/cicd.js.map +1 -1
- package/dist/detectors/cloud-kms.d.ts +8 -5
- package/dist/detectors/cloud-kms.d.ts.map +1 -1
- package/dist/detectors/cloud-kms.js +62 -20
- package/dist/detectors/cloud-kms.js.map +1 -1
- package/dist/detectors/cloudformation.d.ts +8 -0
- package/dist/detectors/cloudformation.d.ts.map +1 -1
- package/dist/detectors/cloudformation.js +41 -10
- package/dist/detectors/cloudformation.js.map +1 -1
- package/dist/detectors/codesign.d.ts +50 -0
- package/dist/detectors/codesign.d.ts.map +1 -0
- package/dist/detectors/codesign.js +143 -0
- package/dist/detectors/codesign.js.map +1 -0
- package/dist/detectors/csharp.d.ts.map +1 -1
- package/dist/detectors/csharp.js +13 -3
- package/dist/detectors/csharp.js.map +1 -1
- package/dist/detectors/dart.d.ts +35 -0
- package/dist/detectors/dart.d.ts.map +1 -0
- package/dist/detectors/dart.js +177 -0
- package/dist/detectors/dart.js.map +1 -0
- package/dist/detectors/database.d.ts +5 -3
- package/dist/detectors/database.d.ts.map +1 -1
- package/dist/detectors/database.js +45 -8
- package/dist/detectors/database.js.map +1 -1
- package/dist/detectors/dkim.d.ts +54 -0
- package/dist/detectors/dkim.d.ts.map +1 -0
- package/dist/detectors/dkim.js +92 -0
- package/dist/detectors/dkim.js.map +1 -0
- package/dist/detectors/dnssec.d.ts.map +1 -1
- package/dist/detectors/dnssec.js +19 -10
- package/dist/detectors/dnssec.js.map +1 -1
- package/dist/detectors/elixir.d.ts.map +1 -1
- package/dist/detectors/elixir.js +34 -2
- package/dist/detectors/elixir.js.map +1 -1
- package/dist/detectors/java.d.ts.map +1 -1
- package/dist/detectors/java.js +33 -3
- package/dist/detectors/java.js.map +1 -1
- package/dist/detectors/jose.d.ts.map +1 -1
- package/dist/detectors/jose.js +13 -3
- package/dist/detectors/jose.js.map +1 -1
- package/dist/detectors/jwk.d.ts +7 -7
- package/dist/detectors/jwk.d.ts.map +1 -1
- package/dist/detectors/jwk.js +44 -8
- package/dist/detectors/jwk.js.map +1 -1
- package/dist/detectors/k8s.d.ts.map +1 -1
- package/dist/detectors/k8s.js +5 -2
- package/dist/detectors/k8s.js.map +1 -1
- package/dist/detectors/keystore.d.ts +19 -0
- package/dist/detectors/keystore.d.ts.map +1 -0
- package/dist/detectors/keystore.js +76 -0
- package/dist/detectors/keystore.js.map +1 -0
- package/dist/detectors/mesh.d.ts +7 -8
- package/dist/detectors/mesh.d.ts.map +1 -1
- package/dist/detectors/mesh.js +17 -35
- package/dist/detectors/mesh.js.map +1 -1
- package/dist/detectors/messaging.d.ts +2 -2
- package/dist/detectors/messaging.d.ts.map +1 -1
- package/dist/detectors/messaging.js +19 -12
- package/dist/detectors/messaging.js.map +1 -1
- package/dist/detectors/objc.d.ts +41 -0
- package/dist/detectors/objc.d.ts.map +1 -0
- package/dist/detectors/objc.js +146 -0
- package/dist/detectors/objc.js.map +1 -0
- package/dist/detectors/openpgp.d.ts +20 -0
- package/dist/detectors/openpgp.d.ts.map +1 -0
- package/dist/detectors/openpgp.js +151 -0
- package/dist/detectors/openpgp.js.map +1 -0
- package/dist/detectors/pem.d.ts.map +1 -1
- package/dist/detectors/pem.js +32 -0
- package/dist/detectors/pem.js.map +1 -1
- package/dist/detectors/php.d.ts +2 -1
- package/dist/detectors/php.d.ts.map +1 -1
- package/dist/detectors/php.js +7 -3
- package/dist/detectors/php.js.map +1 -1
- package/dist/detectors/pkcs11.d.ts +17 -0
- package/dist/detectors/pkcs11.d.ts.map +1 -0
- package/dist/detectors/pkcs11.js +87 -0
- package/dist/detectors/pkcs11.js.map +1 -0
- package/dist/detectors/proxy.d.ts +52 -0
- package/dist/detectors/proxy.d.ts.map +1 -0
- package/dist/detectors/proxy.js +157 -0
- package/dist/detectors/proxy.js.map +1 -0
- package/dist/detectors/pulumi.d.ts +19 -0
- package/dist/detectors/pulumi.d.ts.map +1 -0
- package/dist/detectors/pulumi.js +80 -0
- package/dist/detectors/pulumi.js.map +1 -0
- package/dist/detectors/rust.d.ts.map +1 -1
- package/dist/detectors/rust.js +5 -0
- package/dist/detectors/rust.js.map +1 -1
- package/dist/detectors/secrets.d.ts +4 -1
- package/dist/detectors/secrets.d.ts.map +1 -1
- package/dist/detectors/secrets.js +5 -21
- package/dist/detectors/secrets.js.map +1 -1
- package/dist/detectors/solidity.d.ts +50 -0
- package/dist/detectors/solidity.d.ts.map +1 -0
- package/dist/detectors/solidity.js +108 -0
- package/dist/detectors/solidity.js.map +1 -0
- package/dist/detectors/source.d.ts.map +1 -1
- package/dist/detectors/source.js +105 -6
- package/dist/detectors/source.js.map +1 -1
- package/dist/detectors/spire.d.ts +49 -0
- package/dist/detectors/spire.d.ts.map +1 -0
- package/dist/detectors/spire.js +77 -0
- package/dist/detectors/spire.js.map +1 -0
- package/dist/detectors/ssh-ca.d.ts +72 -0
- package/dist/detectors/ssh-ca.d.ts.map +1 -0
- package/dist/detectors/ssh-ca.js +119 -0
- package/dist/detectors/ssh-ca.js.map +1 -0
- package/dist/detectors/supply-chain.d.ts +17 -0
- package/dist/detectors/supply-chain.d.ts.map +1 -0
- package/dist/detectors/supply-chain.js +89 -0
- package/dist/detectors/supply-chain.js.map +1 -0
- package/dist/detectors/swift.d.ts +22 -0
- package/dist/detectors/swift.d.ts.map +1 -0
- package/dist/detectors/swift.js +120 -0
- package/dist/detectors/swift.js.map +1 -0
- package/dist/detectors/terraform.d.ts.map +1 -1
- package/dist/detectors/terraform.js +35 -8
- package/dist/detectors/terraform.js.map +1 -1
- package/dist/detectors/vault.d.ts +15 -0
- package/dist/detectors/vault.d.ts.map +1 -0
- package/dist/detectors/vault.js +97 -0
- package/dist/detectors/vault.js.map +1 -0
- package/dist/detectors/vpn.d.ts +8 -8
- package/dist/detectors/vpn.d.ts.map +1 -1
- package/dist/detectors/vpn.js +12 -38
- package/dist/detectors/vpn.js.map +1 -1
- package/dist/detectors/weak-hash.d.ts +71 -0
- package/dist/detectors/weak-hash.d.ts.map +1 -0
- package/dist/detectors/weak-hash.js +116 -0
- package/dist/detectors/weak-hash.js.map +1 -0
- package/dist/detectors/webauthn.d.ts +61 -0
- package/dist/detectors/webauthn.d.ts.map +1 -0
- package/dist/detectors/webauthn.js +109 -0
- package/dist/detectors/webauthn.js.map +1 -0
- package/dist/detectors/xmldsig.d.ts +23 -0
- package/dist/detectors/xmldsig.d.ts.map +1 -0
- package/dist/detectors/xmldsig.js +84 -0
- package/dist/detectors/xmldsig.js.map +1 -0
- package/dist/evidence.d.ts +74 -4
- package/dist/evidence.d.ts.map +1 -1
- package/dist/evidence.js +71 -0
- package/dist/evidence.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 +18 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -11
- package/dist/index.js.map +1 -1
- package/dist/inventory.d.ts +0 -2
- package/dist/inventory.d.ts.map +1 -1
- package/dist/inventory.js +15 -6
- package/dist/inventory.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/registry.d.ts +9 -4
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +51 -4
- package/dist/registry.js.map +1 -1
- package/dist/remediate-pipeline.d.ts +0 -3
- package/dist/remediate-pipeline.d.ts.map +1 -1
- package/dist/remediate-pipeline.js +1 -1
- package/dist/remediate-pipeline.js.map +1 -1
- package/dist/remediation.d.ts +10 -0
- package/dist/remediation.d.ts.map +1 -1
- package/dist/remediation.js +32 -0
- package/dist/remediation.js.map +1 -1
- package/dist/report.d.ts +17 -0
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +106 -20
- package/dist/report.js.map +1 -1
- package/dist/scan-worker.js +5 -3
- package/dist/scan-worker.js.map +1 -1
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +35 -6
- package/dist/scan.js.map +1 -1
- package/dist/standards-profiles.d.ts +58 -0
- package/dist/standards-profiles.d.ts.map +1 -0
- package/dist/standards-profiles.js +100 -0
- package/dist/standards-profiles.js.map +1 -0
- package/dist/types.d.ts +7 -6
- 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/vex.d.ts +39 -0
- package/dist/vex.d.ts.map +1 -0
- package/dist/vex.js +87 -0
- package/dist/vex.js.map +1 -0
- package/dist/walk.d.ts +39 -4
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +62 -10
- package/dist/walk.js.map +1 -1
- package/package.json +1 -1
- package/src/cbom-merge.ts +38 -8
- package/src/cbom.ts +153 -39
- package/src/comments.ts +25 -6
- package/src/crypto-agility.ts +407 -0
- package/src/dependencies.ts +182 -16
- package/src/detect-utils.ts +133 -11
- package/src/detectors/age.ts +60 -0
- package/src/detectors/ansible.ts +140 -0
- package/src/detectors/bicep.ts +107 -0
- package/src/detectors/c.ts +31 -3
- package/src/detectors/cicd.ts +18 -5
- package/src/detectors/cloud-kms.ts +79 -25
- package/src/detectors/cloudformation.ts +45 -10
- package/src/detectors/codesign.ts +214 -0
- package/src/detectors/csharp.ts +13 -3
- package/src/detectors/dart.ts +237 -0
- package/src/detectors/database.ts +64 -11
- package/src/detectors/dkim.ts +172 -0
- package/src/detectors/dnssec.ts +19 -10
- package/src/detectors/elixir.ts +33 -2
- package/src/detectors/java.ts +37 -3
- package/src/detectors/jose.ts +19 -3
- package/src/detectors/jwk.ts +59 -17
- package/src/detectors/k8s.ts +5 -2
- package/src/detectors/keystore.ts +109 -0
- package/src/detectors/mesh.ts +21 -45
- package/src/detectors/messaging.ts +22 -14
- package/src/detectors/objc.ts +209 -0
- package/src/detectors/openpgp.ts +194 -0
- package/src/detectors/pem.ts +30 -0
- package/src/detectors/php.ts +9 -4
- package/src/detectors/pkcs11.ts +113 -0
- package/src/detectors/proxy.ts +236 -0
- package/src/detectors/pulumi.ts +106 -0
- package/src/detectors/rust.ts +5 -0
- package/src/detectors/secrets.ts +15 -26
- package/src/detectors/solidity.ts +176 -0
- package/src/detectors/source.ts +110 -5
- package/src/detectors/spire.ts +143 -0
- package/src/detectors/ssh-ca.ts +215 -0
- package/src/detectors/supply-chain.ts +117 -0
- package/src/detectors/swift.ts +149 -0
- package/src/detectors/terraform.ts +42 -8
- package/src/detectors/vault.ts +120 -0
- package/src/detectors/vpn.ts +20 -48
- package/src/detectors/weak-hash.ts +217 -0
- package/src/detectors/webauthn.ts +205 -0
- package/src/detectors/xmldsig.ts +115 -0
- package/src/evidence.ts +127 -4
- package/src/hndl.ts +1012 -0
- package/src/index.ts +93 -13
- package/src/inventory.ts +15 -7
- package/src/parallel.ts +21 -20
- package/src/registry.ts +51 -4
- package/src/remediate-pipeline.ts +1 -1
- package/src/remediation.ts +39 -0
- package/src/report.ts +120 -20
- package/src/scan-worker.ts +5 -3
- package/src/scan.ts +41 -6
- package/src/standards-profiles.ts +136 -0
- package/src/types.ts +18 -5
- package/src/version.ts +1 -1
- package/src/vex.ts +122 -0
- package/src/walk.ts +80 -12
package/src/index.ts
CHANGED
|
@@ -56,13 +56,14 @@ export type {
|
|
|
56
56
|
// Scan cancellation / work-budget errors.
|
|
57
57
|
export { AbortError, BudgetExceededError } from "./errors.js";
|
|
58
58
|
|
|
59
|
-
// Parallel scanning (worker_threads pool)
|
|
60
|
-
|
|
61
|
-
export
|
|
59
|
+
// Parallel scanning (worker_threads pool). The chunk/merge helpers and their
|
|
60
|
+
// SizedFile/ChunkResult types are internal plumbing (not part of the public API).
|
|
61
|
+
export { scanParallel } from "./parallel.js";
|
|
62
|
+
export type { ScanChunk } from "./parallel.js";
|
|
62
63
|
|
|
63
|
-
// Detector registry (plugin point)
|
|
64
|
-
|
|
65
|
-
export
|
|
64
|
+
// Detector registry (plugin point). `detectorScope` and the rule-catalog type are
|
|
65
|
+
// internal.
|
|
66
|
+
export { DetectorRegistry, defaultRegistry } from "./registry.js";
|
|
66
67
|
|
|
67
68
|
// Canonical baseline (shared by qScan + the Action).
|
|
68
69
|
export {
|
|
@@ -82,8 +83,44 @@ export { changedFiles } from "./changed.js";
|
|
|
82
83
|
export { loadConfig, ConfigError, CONFIG_FILENAME } from "./config.js";
|
|
83
84
|
export type { QuantakryptoFileConfig, LoadConfigResult } from "./config.js";
|
|
84
85
|
|
|
86
|
+
// HNDL (harvest-now-decrypt-later) data-risk quantifier (see docs/HNDL.md).
|
|
87
|
+
export {
|
|
88
|
+
HNDL_MODEL_VERSION,
|
|
89
|
+
HNDL_FILENAME,
|
|
90
|
+
SEVERITY_VULNERABILITY,
|
|
91
|
+
CONFIDENCE_WEIGHT,
|
|
92
|
+
CLASSIFICATION_SENSITIVITY,
|
|
93
|
+
NON_HNDL_DISCOUNT,
|
|
94
|
+
DEFAULT_QUANTUM_THREAT_YEARS,
|
|
95
|
+
DEFAULT_MIGRATION_HORIZON_YEARS,
|
|
96
|
+
DEFAULT_UNBOUND_CLASSIFICATION,
|
|
97
|
+
HndlError,
|
|
98
|
+
computeHndl,
|
|
99
|
+
vulnerabilityFactor,
|
|
100
|
+
moscaFactor,
|
|
101
|
+
globMatch,
|
|
102
|
+
findingFingerprint,
|
|
103
|
+
findingScope,
|
|
104
|
+
parseHndlMap,
|
|
105
|
+
loadHndlMap,
|
|
106
|
+
scaffoldHndlYaml,
|
|
107
|
+
} from "./hndl.js";
|
|
108
|
+
export type {
|
|
109
|
+
DataClassification,
|
|
110
|
+
HndlScope,
|
|
111
|
+
HndlDataAsset,
|
|
112
|
+
HndlHorizon,
|
|
113
|
+
HndlDefaults,
|
|
114
|
+
HndlMap,
|
|
115
|
+
ExposureRationale,
|
|
116
|
+
FindingExposure,
|
|
117
|
+
AssetExposure,
|
|
118
|
+
HndlSummary,
|
|
119
|
+
HndlReport,
|
|
120
|
+
} from "./hndl.js";
|
|
121
|
+
|
|
85
122
|
// Filesystem walker (relative POSIX paths, default ignores, size/binary filters).
|
|
86
|
-
export { walkFiles, isBinaryPath,
|
|
123
|
+
export { walkFiles, isBinaryPath, looksMinified } from "./walk.js";
|
|
87
124
|
|
|
88
125
|
// Analyzable-language coverage (which source languages the scanner inspects).
|
|
89
126
|
export {
|
|
@@ -104,7 +141,13 @@ export { vulnerableDependencies, DEP_VULNERABLE_RULE, isManifestFile } from "./d
|
|
|
104
141
|
export { SEVERITY_ORDER, severityRank, meetsThreshold, sarifLevel } from "./severity.js";
|
|
105
142
|
|
|
106
143
|
// Reporters.
|
|
107
|
-
export {
|
|
144
|
+
export {
|
|
145
|
+
toSarif,
|
|
146
|
+
toJson,
|
|
147
|
+
formatSummary,
|
|
148
|
+
formatTierGuidance,
|
|
149
|
+
formatProfileGuidance,
|
|
150
|
+
} from "./report.js";
|
|
108
151
|
export type { ReportOptions } from "./report.js";
|
|
109
152
|
|
|
110
153
|
// CycloneDX 1.6 cryptographic bill of materials (CBOM) export.
|
|
@@ -112,18 +155,45 @@ export { toCbom } from "./cbom.js";
|
|
|
112
155
|
export type { CycloneDxBom, CbomComponent } from "./cbom.js";
|
|
113
156
|
// Merge multiple CBOMs (code + infra + live endpoints) into one combined BOM.
|
|
114
157
|
export { mergeCboms } from "./cbom-merge.js";
|
|
158
|
+
// OpenVEX 0.2.0 export — quantum-readiness posture as VEX statements.
|
|
159
|
+
export { toOpenVex } from "./vex.js";
|
|
160
|
+
export type { OpenVexDocument, OpenVexStatement, OpenVexOptions } from "./vex.js";
|
|
161
|
+
// Crypto-agility manifest: agent-consumable crypto-posture document.
|
|
162
|
+
export {
|
|
163
|
+
buildCryptoAgilityManifest,
|
|
164
|
+
validateCryptoAgilityManifest,
|
|
165
|
+
CRYPTO_AGILITY_MANIFEST_VERSION,
|
|
166
|
+
CRYPTO_AGILITY_WELL_KNOWN_PATH,
|
|
167
|
+
} from "./crypto-agility.js";
|
|
168
|
+
export type {
|
|
169
|
+
CryptoAgilityManifest,
|
|
170
|
+
CryptoAgilityManifestOptions,
|
|
171
|
+
CryptoAgilityPosture,
|
|
172
|
+
CryptoAgilityCbomSummary,
|
|
173
|
+
CryptoAgilityFamily,
|
|
174
|
+
CryptoAgilityPolicy,
|
|
175
|
+
ManifestValidation,
|
|
176
|
+
} from "./crypto-agility.js";
|
|
115
177
|
// ISO/IEC 27001 A.8.24 evidence-chain readiness report.
|
|
116
|
-
export { buildReadinessReport } from "./evidence.js";
|
|
117
|
-
export type {
|
|
178
|
+
export { buildReadinessReport, signReadinessReport, verifyReadinessReport } from "./evidence.js";
|
|
179
|
+
export type {
|
|
180
|
+
ReadinessReport,
|
|
181
|
+
EvidenceFinding,
|
|
182
|
+
ReadinessReportOptions,
|
|
183
|
+
EvidenceSigner,
|
|
184
|
+
SignEvidenceOptions,
|
|
185
|
+
VerifyReadinessResult,
|
|
186
|
+
} from "./evidence.js";
|
|
118
187
|
|
|
119
188
|
// Cryptography policy → per-finding verdicts (A.8.24 evidence §4).
|
|
120
|
-
export { buildPolicyMapping, parseCryptoPolicy
|
|
189
|
+
export { buildPolicyMapping, parseCryptoPolicy } from "./policy.js";
|
|
121
190
|
export type { CryptoPolicy, PolicyVerdict, PolicyMapping, PolicyFindingVerdict } from "./policy.js";
|
|
122
191
|
|
|
123
|
-
// Remediation lookup (family + tier-aware) and stateful-HBS guidance.
|
|
192
|
+
// Remediation lookup (family + tier-aware + profile-aware) and stateful-HBS guidance.
|
|
124
193
|
export {
|
|
125
194
|
remediationFor,
|
|
126
195
|
remediationForTier,
|
|
196
|
+
remediationForProfile,
|
|
127
197
|
TIER_PARAMS,
|
|
128
198
|
STATEFUL_HBS_NOTE,
|
|
129
199
|
PQC_TRANSITION_NOTE,
|
|
@@ -132,9 +202,19 @@ export {
|
|
|
132
202
|
export type { SecurityTier } from "./remediation.js";
|
|
133
203
|
|
|
134
204
|
// Post-quantum standards source of truth + review cadence.
|
|
135
|
-
export { PQC_STANDARDS
|
|
205
|
+
export { PQC_STANDARDS } from "./standards.js";
|
|
136
206
|
export type { PqcStandards, StandardsCitation, StandardsReviewStatus } from "./standards.js";
|
|
137
207
|
|
|
208
|
+
// Selectable standards regime profiles (NIST / CNSA / BSI / ANSSI / NCSC).
|
|
209
|
+
export {
|
|
210
|
+
STANDARDS_PROFILES,
|
|
211
|
+
DEFAULT_PROFILE_ID,
|
|
212
|
+
standardsProfileIds,
|
|
213
|
+
getStandardsProfile,
|
|
214
|
+
defaultStandardsProfile,
|
|
215
|
+
} from "./standards-profiles.js";
|
|
216
|
+
export type { StandardsProfile, HybridStance } from "./standards-profiles.js";
|
|
217
|
+
|
|
138
218
|
// CWE identifier constants.
|
|
139
219
|
export {
|
|
140
220
|
CWE_BROKEN_CRYPTO,
|
package/src/inventory.ts
CHANGED
|
@@ -48,7 +48,7 @@ const SCORE_SCALE = 100;
|
|
|
48
48
|
const TEST_PATH_WEIGHT = 0.15;
|
|
49
49
|
|
|
50
50
|
/** True when a finding's file path is test / fixture / example / documentation. */
|
|
51
|
-
|
|
51
|
+
function isTestOrFixturePath(file: string): boolean {
|
|
52
52
|
const f = file.toLowerCase().replace(/\\/g, "/");
|
|
53
53
|
if (
|
|
54
54
|
/(?:^|\/)(?:tests?|__tests__|testdata|test-data|fixtures?|examples?|demos?|samples?|specs?|mocks?|docs?|benchmarks?|e2e)\//.test(
|
|
@@ -75,20 +75,28 @@ export function isTestOrFixturePath(file: string): boolean {
|
|
|
75
75
|
export function readinessScore(findings: Finding[]): number {
|
|
76
76
|
if (findings.length === 0) return 100;
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
// Diminishing-returns occurrence counters, kept SEPARATE for full-weight vs
|
|
79
|
+
// test-path findings. Sharing one counter per severity let whichever finding came
|
|
80
|
+
// first in the (path-sorted) list claim the `1/√1` slot, so a directory rename — or
|
|
81
|
+
// a test finding sorting ahead of a real one — changed the score. Bucketing makes
|
|
82
|
+
// the penalty independent of file order and of test/real interleaving.
|
|
83
|
+
const zero = (): Record<Severity, number> => ({
|
|
79
84
|
critical: 0,
|
|
80
85
|
high: 0,
|
|
81
86
|
medium: 0,
|
|
82
87
|
low: 0,
|
|
83
88
|
info: 0,
|
|
84
|
-
};
|
|
89
|
+
});
|
|
90
|
+
const seenReal = zero();
|
|
91
|
+
const seenTest = zero();
|
|
85
92
|
|
|
86
93
|
let penalty = 0;
|
|
87
94
|
for (const f of findings) {
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
const isTest = isTestOrFixturePath(f.location.file);
|
|
96
|
+
const bucket = isTest ? seenTest : seenReal;
|
|
97
|
+
bucket[f.severity] += 1;
|
|
98
|
+
const weight = SEVERITY_WEIGHT[f.severity] * (isTest ? TEST_PATH_WEIGHT : 1);
|
|
99
|
+
penalty += penaltyFor(weight, bucket[f.severity]);
|
|
92
100
|
}
|
|
93
101
|
|
|
94
102
|
return Math.max(0, Math.min(100, Math.round(100 * Math.exp(-penalty / SCORE_SCALE))));
|
package/src/parallel.ts
CHANGED
|
@@ -17,7 +17,7 @@ import { fileURLToPath } from "node:url";
|
|
|
17
17
|
import type { Worker as NodeWorker } from "node:worker_threads";
|
|
18
18
|
|
|
19
19
|
import type { Finding, ParallelScanOptions, ScanResult } from "./types.js";
|
|
20
|
-
import {
|
|
20
|
+
import { walkFilesSized } from "./walk.js";
|
|
21
21
|
import { isAnalyzableSource } from "./detect-utils.js";
|
|
22
22
|
import { buildInventory } from "./inventory.js";
|
|
23
23
|
import { compareFindings, filterExplicitFileList, scan } from "./scan.js";
|
|
@@ -115,30 +115,31 @@ function shouldParallelize(options: ParallelScanOptions, files: SizedFile[]): bo
|
|
|
115
115
|
* explicit `files` list or the walker. Sizes power byte-balanced chunking.
|
|
116
116
|
*/
|
|
117
117
|
async function enumerateFiles(options: ParallelScanOptions, baseDir: string): Promise<SizedFile[]> {
|
|
118
|
-
const
|
|
118
|
+
const sized: SizedFile[] = [];
|
|
119
119
|
if (options.files) {
|
|
120
|
+
// Explicit file list: the walker isn't involved, so stat each once here.
|
|
120
121
|
// Apply the SAME include/exclude/binary filtering the serial path uses via
|
|
121
|
-
// `
|
|
122
|
-
for (const rel of filterExplicitFileList(options.files, options))
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
rels.push(rel);
|
|
122
|
+
// `filterExplicitFileList`, so `--parallel` is byte-for-byte identical to serial.
|
|
123
|
+
for (const rel of filterExplicitFileList(options.files, options)) {
|
|
124
|
+
let size = 0;
|
|
125
|
+
try {
|
|
126
|
+
size = (await stat(path.join(baseDir, ...rel.split("/")))).size;
|
|
127
|
+
} catch {
|
|
128
|
+
// Unreadable now; keep with size 0 (the worker read will skip if it's gone).
|
|
129
|
+
}
|
|
130
|
+
sized.push({ rel, size });
|
|
131
131
|
}
|
|
132
|
+
return sized;
|
|
132
133
|
}
|
|
133
134
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
135
|
+
// Directory walk: reuse the size the walker already stat'd while enforcing the
|
|
136
|
+
// size limit, so files are not stat'd a second time here (double-stat fix).
|
|
137
|
+
for await (const { rel, size } of walkFilesSized(options.root, {
|
|
138
|
+
include: options.include,
|
|
139
|
+
exclude: options.exclude,
|
|
140
|
+
noDefaultIgnores: options.noDefaultIgnores,
|
|
141
|
+
maxFileSize: options.maxFileSize,
|
|
142
|
+
})) {
|
|
142
143
|
sized.push({ rel, size });
|
|
143
144
|
}
|
|
144
145
|
return sized;
|
package/src/registry.ts
CHANGED
|
@@ -21,6 +21,10 @@ import { rubyDetector } from "./detectors/ruby.js";
|
|
|
21
21
|
import { phpDetector } from "./detectors/php.js";
|
|
22
22
|
import { elixirDetector } from "./detectors/elixir.js";
|
|
23
23
|
import { cDetector } from "./detectors/c.js";
|
|
24
|
+
import { swiftDetector } from "./detectors/swift.js";
|
|
25
|
+
import { objcDetector } from "./detectors/objc.js";
|
|
26
|
+
import { dartDetector } from "./detectors/dart.js";
|
|
27
|
+
import { solidityDetector } from "./detectors/solidity.js";
|
|
24
28
|
import { pemDetector } from "./detectors/pem.js";
|
|
25
29
|
import { jwkDetector } from "./detectors/jwk.js";
|
|
26
30
|
import { terraformDetector } from "./detectors/terraform.js";
|
|
@@ -31,10 +35,27 @@ import { joseDetector } from "./detectors/jose.js";
|
|
|
31
35
|
import { k8sDetector } from "./detectors/k8s.js";
|
|
32
36
|
import { messagingDetector } from "./detectors/messaging.js";
|
|
33
37
|
import { databaseDetector } from "./detectors/database.js";
|
|
38
|
+
import { xmldsigDetector } from "./detectors/xmldsig.js";
|
|
39
|
+
import { pkcs11Detector } from "./detectors/pkcs11.js";
|
|
40
|
+
import { dkimDetector } from "./detectors/dkim.js";
|
|
41
|
+
import { sshCaDetector } from "./detectors/ssh-ca.js";
|
|
42
|
+
import { spireDetector } from "./detectors/spire.js";
|
|
43
|
+
import { proxyDetector } from "./detectors/proxy.js";
|
|
44
|
+
import { webauthnDetector } from "./detectors/webauthn.js";
|
|
45
|
+
import { codesignDetector } from "./detectors/codesign.js";
|
|
46
|
+
import { weakHashDetector } from "./detectors/weak-hash.js";
|
|
34
47
|
import { cloudformationDetector } from "./detectors/cloudformation.js";
|
|
48
|
+
import { bicepDetector } from "./detectors/bicep.js";
|
|
49
|
+
import { pulumiDetector } from "./detectors/pulumi.js";
|
|
35
50
|
import { meshDetector } from "./detectors/mesh.js";
|
|
36
51
|
import { dnssecDetector } from "./detectors/dnssec.js";
|
|
37
52
|
import { vpnDetector } from "./detectors/vpn.js";
|
|
53
|
+
import { ansibleDetector } from "./detectors/ansible.js";
|
|
54
|
+
import { ageDetector } from "./detectors/age.js";
|
|
55
|
+
import { supplyChainDetector } from "./detectors/supply-chain.js";
|
|
56
|
+
import { vaultDetector } from "./detectors/vault.js";
|
|
57
|
+
import { keystoreDetector } from "./detectors/keystore.js";
|
|
58
|
+
import { openpgpDetector } from "./detectors/openpgp.js";
|
|
38
59
|
import { statefulHbsDetector } from "./detectors/stateful-hbs.js";
|
|
39
60
|
|
|
40
61
|
/** Normalised scope of a detector (defaults to "source" when undeclared). */
|
|
@@ -125,10 +146,15 @@ export class DetectorRegistry {
|
|
|
125
146
|
}
|
|
126
147
|
|
|
127
148
|
/**
|
|
128
|
-
* The built-in detectors, in run order: the JS/TS source + config
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
149
|
+
* The built-in detectors, in run order: the JS/TS source + language-agnostic config
|
|
150
|
+
* detectors, the per-language source packs (Python, Go, Java/Kotlin/Scala, C#, Rust,
|
|
151
|
+
* Ruby, PHP, Elixir, C/C++, Swift, Objective-C, Dart, Solidity/Move/Cairo), the
|
|
152
|
+
* infrastructure/config detectors (Terraform, Bicep, Pulumi, CloudFormation, cloud-KMS,
|
|
153
|
+
* k8s, mesh, DNSSEC, Vault, database/TDE, messaging, VPN, Ansible, supply-chain, CI/CD,
|
|
154
|
+
* secrets, age, keystore, OpenPGP, JWK, XML-DSig/SAML, PKCS#11/HSM, DKIM, SSH-CA,
|
|
155
|
+
* SPIFFE/SPIRE, reverse-proxy/gRPC TLS, WebAuthn/FIDO2, code-signing, weak-hash-in-
|
|
156
|
+
* signature), and the stateful-HBS (SP 800-208) detector. The manifest (dependency)
|
|
157
|
+
* scanner is handled separately by `scan()`.
|
|
132
158
|
*
|
|
133
159
|
* This is the single source of truth for the default detector set: both
|
|
134
160
|
* {@link defaultRegistry} and the public `detectors` export (re-exported from
|
|
@@ -145,6 +171,10 @@ export const builtinDetectors: Detector[] = [
|
|
|
145
171
|
phpDetector,
|
|
146
172
|
elixirDetector,
|
|
147
173
|
cDetector,
|
|
174
|
+
swiftDetector,
|
|
175
|
+
objcDetector,
|
|
176
|
+
dartDetector,
|
|
177
|
+
solidityDetector,
|
|
148
178
|
pemDetector,
|
|
149
179
|
jwkDetector,
|
|
150
180
|
terraformDetector,
|
|
@@ -155,10 +185,27 @@ export const builtinDetectors: Detector[] = [
|
|
|
155
185
|
k8sDetector,
|
|
156
186
|
messagingDetector,
|
|
157
187
|
databaseDetector,
|
|
188
|
+
xmldsigDetector,
|
|
189
|
+
pkcs11Detector,
|
|
190
|
+
dkimDetector,
|
|
191
|
+
sshCaDetector,
|
|
192
|
+
spireDetector,
|
|
193
|
+
proxyDetector,
|
|
194
|
+
webauthnDetector,
|
|
195
|
+
codesignDetector,
|
|
196
|
+
weakHashDetector,
|
|
158
197
|
cloudformationDetector,
|
|
198
|
+
bicepDetector,
|
|
199
|
+
pulumiDetector,
|
|
159
200
|
meshDetector,
|
|
160
201
|
dnssecDetector,
|
|
161
202
|
vpnDetector,
|
|
203
|
+
ansibleDetector,
|
|
204
|
+
ageDetector,
|
|
205
|
+
supplyChainDetector,
|
|
206
|
+
vaultDetector,
|
|
207
|
+
keystoreDetector,
|
|
208
|
+
openpgpDetector,
|
|
162
209
|
statefulHbsDetector,
|
|
163
210
|
];
|
|
164
211
|
|
|
@@ -69,7 +69,7 @@ const NEW_SINK_LINE_RE = new RegExp(NEW_SINK_RE.source);
|
|
|
69
69
|
|
|
70
70
|
/** Max changed lines allowed in an auto-verified LLM patch — a real crypto fix
|
|
71
71
|
* is localized; a sprawling rewrite is not reviewable as "just the fix". */
|
|
72
|
-
|
|
72
|
+
const LLM_PATCH_MAX_CHANGED_LINES = 60;
|
|
73
73
|
|
|
74
74
|
function countMatches(re: RegExp, s: string): number {
|
|
75
75
|
return (s.match(re) ?? []).length;
|
package/src/remediation.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* standards to track are captured in {@link PQC_TRANSITION_NOTE}.
|
|
7
7
|
*/
|
|
8
8
|
import type { AlgorithmFamily, Remediation } from "./types.js";
|
|
9
|
+
import type { StandardsProfile } from "./standards-profiles.js";
|
|
9
10
|
|
|
10
11
|
/** Canonical remediation table, keyed by algorithm family. */
|
|
11
12
|
const REMEDIATIONS: Record<AlgorithmFamily, Remediation> = {
|
|
@@ -188,6 +189,44 @@ export function remediationForTier(
|
|
|
188
189
|
};
|
|
189
190
|
}
|
|
190
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Regime-aware remediation. Composes the base family guidance with a
|
|
194
|
+
* {@link StandardsProfile}'s parameter sets, HYBRID STANCE, and deprecation
|
|
195
|
+
* deadlines, so an ANSSI/BSI audience is told hybrid is *required* while a CNSA 2.0
|
|
196
|
+
* audience is told it is *optional* (and pointed at the 1024-level hybrid). This is
|
|
197
|
+
* the profile-driven successor to {@link remediationForTier}; `--tier category-5`
|
|
198
|
+
* resolves to the `cnsa-2.0` profile.
|
|
199
|
+
*/
|
|
200
|
+
export function remediationForProfile(
|
|
201
|
+
algorithm: AlgorithmFamily,
|
|
202
|
+
profile: StandardsProfile,
|
|
203
|
+
): Remediation {
|
|
204
|
+
const base = REMEDIATIONS[algorithm];
|
|
205
|
+
const isConf = isConfidentialityFamily(algorithm);
|
|
206
|
+
const primary = isConf ? profile.paramSets.kem : profile.paramSets.signature;
|
|
207
|
+
// The hybrid stance governs KEY ESTABLISHMENT, so it is surfaced for confidentiality
|
|
208
|
+
// families; signature families migrate to a stateless PQC signer directly.
|
|
209
|
+
const stanceWord =
|
|
210
|
+
profile.hybridStance === "required"
|
|
211
|
+
? "hybrid required"
|
|
212
|
+
: profile.hybridStance === "recommended"
|
|
213
|
+
? "hybrid recommended"
|
|
214
|
+
: "hybrids optional";
|
|
215
|
+
const recommendation = isConf
|
|
216
|
+
? `${primary} — ${profile.name}: ${stanceWord}`
|
|
217
|
+
: `${primary} — ${profile.name}`;
|
|
218
|
+
const hybridClause = isConf ? ` ${profile.hybridGuidance}` : "";
|
|
219
|
+
return {
|
|
220
|
+
algorithm,
|
|
221
|
+
recommendation,
|
|
222
|
+
detail:
|
|
223
|
+
`${base.detail} Under ${profile.name} (${profile.citation}), use ${profile.paramSets.kem} for ` +
|
|
224
|
+
`key establishment and ${profile.paramSets.signature} for signatures; classical public-key ` +
|
|
225
|
+
`crypto is deprecated after ${profile.deprecateAfter} and disallowed after ${profile.disallowAfter}.` +
|
|
226
|
+
hybridClause,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
191
230
|
/**
|
|
192
231
|
* Guidance for stateful hash-based signatures (SP 800-208: LMS / XMSS / HSS).
|
|
193
232
|
* These are NIST-approved for firmware / boot signing but are STATEFUL — each
|
package/src/report.ts
CHANGED
|
@@ -7,9 +7,12 @@ import type { AlgorithmFamily, Finding, RuleMeta, ScanResult, Severity } from ".
|
|
|
7
7
|
import { VERSION } from "./version.js";
|
|
8
8
|
import { SEVERITY_ORDER, sarifLevel } from "./severity.js";
|
|
9
9
|
import { ANALYZABLE_LANGUAGES_LABEL } from "./detect-utils.js";
|
|
10
|
-
import { remediationFor, remediationForTier } from "./remediation.js";
|
|
10
|
+
import { remediationFor, remediationForTier, remediationForProfile } from "./remediation.js";
|
|
11
11
|
import type { SecurityTier } from "./remediation.js";
|
|
12
|
+
import type { StandardsProfile } from "./standards-profiles.js";
|
|
12
13
|
import { fingerprintFinding } from "./baseline.js";
|
|
14
|
+
import { findingFingerprint } from "./hndl.js";
|
|
15
|
+
import type { FindingExposure, HndlReport } from "./hndl.js";
|
|
13
16
|
|
|
14
17
|
/** Minimal SARIF 2.1.0 log shape (kept permissive on purpose). */
|
|
15
18
|
export interface SarifLog {
|
|
@@ -35,6 +38,29 @@ export interface ReportOptions {
|
|
|
35
38
|
* {@link toJson}.
|
|
36
39
|
*/
|
|
37
40
|
catalog?: RuleMeta[];
|
|
41
|
+
/**
|
|
42
|
+
* Optional HNDL exposure analysis ({@link computeHndl}). When supplied, each
|
|
43
|
+
* finding gains its `exposure` fields (score, bound data asset, rationale)
|
|
44
|
+
* keyed by fingerprint, and the report carries the repo-level HNDL summary.
|
|
45
|
+
* Purely additive: it never changes finding identity, ordering, or exit codes.
|
|
46
|
+
*/
|
|
47
|
+
hndl?: HndlReport;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The per-finding exposure block emitted in JSON / SARIF, or undefined. */
|
|
51
|
+
function exposureFor(f: Finding, hndl: HndlReport | undefined): FindingExposure | undefined {
|
|
52
|
+
if (!hndl) return undefined;
|
|
53
|
+
return hndl.byFingerprint.get(findingFingerprint(f));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The repo HNDL summary block shared by JSON output and the SARIF run. */
|
|
57
|
+
function hndlSummaryBlock(hndl: HndlReport): Record<string, unknown> {
|
|
58
|
+
return {
|
|
59
|
+
modelVersion: hndl.modelVersion,
|
|
60
|
+
horizon: hndl.horizon,
|
|
61
|
+
summary: hndl.summary,
|
|
62
|
+
assets: hndl.assets,
|
|
63
|
+
};
|
|
38
64
|
}
|
|
39
65
|
|
|
40
66
|
const SARIF_SCHEMA =
|
|
@@ -104,6 +130,16 @@ function sarifRule(spec: {
|
|
|
104
130
|
};
|
|
105
131
|
}
|
|
106
132
|
|
|
133
|
+
/** SARIF result.properties fragment for a finding's HNDL exposure, or empty. */
|
|
134
|
+
function exposureProperties(exposure: FindingExposure | undefined): Record<string, unknown> {
|
|
135
|
+
if (!exposure) return {};
|
|
136
|
+
return {
|
|
137
|
+
exposureScore: exposure.exposureScore,
|
|
138
|
+
dataAsset: exposure.dataAsset,
|
|
139
|
+
exposureRationale: exposure.rationale,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
107
143
|
/** Serialize a scan result as SARIF 2.1.0. */
|
|
108
144
|
export function toSarif(result: ScanResult, opts?: ReportOptions): SarifLog {
|
|
109
145
|
const redactSnippets = opts?.redactSnippets ?? false;
|
|
@@ -170,6 +206,10 @@ export function toSarif(result: ScanResult, opts?: ReportOptions): SarifLog {
|
|
|
170
206
|
// edit above it. `quantakrypto/v1` names our scheme.
|
|
171
207
|
partialFingerprints: { "quantakrypto/v1": fingerprintFinding(f) },
|
|
172
208
|
properties: {
|
|
209
|
+
// Same stable identity mirrored into properties so non-GitHub SARIF
|
|
210
|
+
// consumers (our platform ingest) can read one uniform `fingerprint`
|
|
211
|
+
// field across JSON and SARIF without reaching into partialFingerprints.
|
|
212
|
+
fingerprint: fingerprintFinding(f),
|
|
173
213
|
category: f.category,
|
|
174
214
|
severity: f.severity,
|
|
175
215
|
confidence: f.confidence,
|
|
@@ -177,6 +217,7 @@ export function toSarif(result: ScanResult, opts?: ReportOptions): SarifLog {
|
|
|
177
217
|
...(f.algorithm ? { algorithm: f.algorithm } : {}),
|
|
178
218
|
...(f.remediation ? { remediation: f.remediation } : {}),
|
|
179
219
|
...(f.cwe ? { cwe: f.cwe } : {}),
|
|
220
|
+
...exposureProperties(exposureFor(f, opts?.hndl)),
|
|
180
221
|
},
|
|
181
222
|
...(f.cwe
|
|
182
223
|
? {
|
|
@@ -232,6 +273,7 @@ export function toSarif(result: ScanResult, opts?: ReportOptions): SarifLog {
|
|
|
232
273
|
},
|
|
233
274
|
},
|
|
234
275
|
...(taxonomies.length > 0 ? { taxonomies } : {}),
|
|
276
|
+
...(opts?.hndl ? { properties: { hndl: hndlSummaryBlock(opts.hndl) } } : {}),
|
|
235
277
|
results,
|
|
236
278
|
},
|
|
237
279
|
],
|
|
@@ -257,6 +299,7 @@ function securitySeverity(severity: Severity): string {
|
|
|
257
299
|
/** Serialize a scan result as a plain JSON-friendly object. */
|
|
258
300
|
export function toJson(result: ScanResult, opts?: ReportOptions): Record<string, unknown> {
|
|
259
301
|
const redactSnippets = opts?.redactSnippets ?? false;
|
|
302
|
+
const hndl = opts?.hndl;
|
|
260
303
|
return {
|
|
261
304
|
toolVersion: result.toolVersion,
|
|
262
305
|
root: result.root,
|
|
@@ -272,25 +315,48 @@ export function toJson(result: ScanResult, opts?: ReportOptions): Record<string,
|
|
|
272
315
|
byCategory: result.inventory.byCategory,
|
|
273
316
|
byAlgorithm: result.inventory.byAlgorithm,
|
|
274
317
|
},
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
318
|
+
...(hndl ? { hndl: hndlSummaryBlock(hndl) } : {}),
|
|
319
|
+
findings: result.findings.map((f) => {
|
|
320
|
+
const exposure = exposureFor(f, hndl);
|
|
321
|
+
return {
|
|
322
|
+
// Stable, line-INSENSITIVE identity of the finding: sha256 of
|
|
323
|
+
// ruleId | normalized-POSIX-repo-relative-path | normalized-snippet
|
|
324
|
+
// (the SARIF partialFingerprints trick, line number deliberately
|
|
325
|
+
// excluded). Reused verbatim from the baseline module so JSON identity,
|
|
326
|
+
// SARIF partialFingerprints, and the baseline suppression set are one and
|
|
327
|
+
// the same value. A line move does NOT change it; when no snippet context
|
|
328
|
+
// exists it falls back to ruleId|path. This is the cross-run identity the
|
|
329
|
+
// platform keys posture drift on.
|
|
330
|
+
fingerprint: fingerprintFinding(f),
|
|
331
|
+
ruleId: f.ruleId,
|
|
332
|
+
title: f.title,
|
|
333
|
+
category: f.category,
|
|
334
|
+
severity: f.severity,
|
|
335
|
+
confidence: f.confidence,
|
|
336
|
+
algorithm: f.algorithm,
|
|
337
|
+
hndl: f.hndl,
|
|
338
|
+
message: f.message,
|
|
339
|
+
remediation: f.remediation,
|
|
340
|
+
cwe: f.cwe,
|
|
341
|
+
location: {
|
|
342
|
+
file: f.location.file,
|
|
343
|
+
line: f.location.line,
|
|
344
|
+
column: f.location.column,
|
|
345
|
+
endLine: f.location.endLine,
|
|
346
|
+
snippet: emittedSnippet(f, redactSnippets),
|
|
347
|
+
},
|
|
348
|
+
...(exposure
|
|
349
|
+
? {
|
|
350
|
+
exposure: {
|
|
351
|
+
fingerprint: exposure.fingerprint,
|
|
352
|
+
exposureScore: exposure.exposureScore,
|
|
353
|
+
dataAsset: exposure.dataAsset,
|
|
354
|
+
rationale: exposure.rationale,
|
|
355
|
+
},
|
|
356
|
+
}
|
|
357
|
+
: {}),
|
|
358
|
+
};
|
|
359
|
+
}),
|
|
294
360
|
};
|
|
295
361
|
}
|
|
296
362
|
|
|
@@ -475,3 +541,37 @@ export function formatTierGuidance(
|
|
|
475
541
|
}
|
|
476
542
|
return out;
|
|
477
543
|
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Per-family migration targets tailored to a selected {@link StandardsProfile}
|
|
547
|
+
* (`--profile`). Unlike {@link formatTierGuidance} (CNSA-tier only), this surfaces the
|
|
548
|
+
* regime's parameter sets AND its hybrid stance — required (ANSSI/BSI) vs recommended
|
|
549
|
+
* (NIST/NCSC) vs optional (CNSA 2.0) — so guidance isn't regime-wrong. Returns plain
|
|
550
|
+
* (un-coloured) lines; the caller styles them.
|
|
551
|
+
*/
|
|
552
|
+
export function formatProfileGuidance(
|
|
553
|
+
byAlgorithm: Record<string, number>,
|
|
554
|
+
profile: StandardsProfile,
|
|
555
|
+
): string[] {
|
|
556
|
+
const out: string[] = [`${profile.name} migration targets:`];
|
|
557
|
+
const seen = new Set<string>();
|
|
558
|
+
for (const [k, n] of Object.entries(byAlgorithm)) {
|
|
559
|
+
if (n <= 0) continue;
|
|
560
|
+
const fam = k as AlgorithmFamily;
|
|
561
|
+
if (fam === "unknown" || !remediationFor(fam)) continue; // skip unmapped families
|
|
562
|
+
const rem = remediationForProfile(fam, profile);
|
|
563
|
+
if (seen.has(rem.recommendation)) continue;
|
|
564
|
+
seen.add(rem.recommendation);
|
|
565
|
+
out.push(` ${fam} → ${rem.recommendation}`);
|
|
566
|
+
}
|
|
567
|
+
const stance =
|
|
568
|
+
profile.hybridStance === "required"
|
|
569
|
+
? "requires classical+PQC hybridization"
|
|
570
|
+
: profile.hybridStance === "recommended"
|
|
571
|
+
? "recommends hybridization"
|
|
572
|
+
: "does not require hybridization";
|
|
573
|
+
out.push(
|
|
574
|
+
` ${profile.authority} ${stance}; classical public-key crypto disallowed after ${profile.disallowAfter} (${profile.citation}).`,
|
|
575
|
+
);
|
|
576
|
+
return out;
|
|
577
|
+
}
|
package/src/scan-worker.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { parentPort, workerData } from "node:worker_threads";
|
|
|
15
15
|
import type { Finding } from "./types.js";
|
|
16
16
|
import { defaultRegistry } from "./registry.js";
|
|
17
17
|
import { detectFile } from "./scan.js";
|
|
18
|
-
import { looksMinified } from "./walk.js";
|
|
18
|
+
import { isKeystorePath, looksMinified } from "./walk.js";
|
|
19
19
|
import { isManifestFile } from "./dependencies.js";
|
|
20
20
|
|
|
21
21
|
interface WorkerToggles {
|
|
@@ -48,14 +48,16 @@ if (parentPort) {
|
|
|
48
48
|
|
|
49
49
|
for (const rel of req.files) {
|
|
50
50
|
const abs = path.join(baseDir, ...rel.split("/"));
|
|
51
|
+
// Keystores (.jks/.p12/…) are read byte-preserving (latin1); see scan.ts.
|
|
52
|
+
const keystore = isKeystorePath(rel);
|
|
51
53
|
let content: string;
|
|
52
54
|
try {
|
|
53
|
-
content = readFileSync(abs, "utf8");
|
|
55
|
+
content = readFileSync(abs, keystore ? "latin1" : "utf8");
|
|
54
56
|
} catch {
|
|
55
57
|
unreadable += 1;
|
|
56
58
|
continue;
|
|
57
59
|
}
|
|
58
|
-
if (!toggles.scanMinified && !isManifestFile(rel) && looksMinified(content)) {
|
|
60
|
+
if (!toggles.scanMinified && !isManifestFile(rel) && !keystore && looksMinified(content)) {
|
|
59
61
|
skippedMinified += 1;
|
|
60
62
|
continue;
|
|
61
63
|
}
|