@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
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selectable STANDARDS PROFILES — the regime a scan's remediation, deadlines, and
|
|
3
|
+
* hybrid guidance are tailored to. Different national/regional authorities agree on
|
|
4
|
+
* the PQC primitives (ML-KEM / ML-DSA) but diverge on two things this tool must not
|
|
5
|
+
* hardcode: (a) the required PARAMETER SETS (a commercial ML-KEM-768 vs a
|
|
6
|
+
* national-security ML-KEM-1024), and (b) the HYBRID STANCE — whether classical+PQC
|
|
7
|
+
* hybridization is required, recommended, or optional during the transition. Baking
|
|
8
|
+
* in NIST/CNSA's "hybrids optional" is wrong for an ANSSI or BSI audience, where
|
|
9
|
+
* hybrid is required. `--profile <id>` selects the regime; `--policy` composes an
|
|
10
|
+
* org's own exceptions on top.
|
|
11
|
+
*
|
|
12
|
+
* Like {@link PqcStandards}, every profile carries a citation + `asOf` date and is
|
|
13
|
+
* re-verified on the quarterly standards cadence. These are guidance summaries, not
|
|
14
|
+
* legal advice — consult the cited source of record.
|
|
15
|
+
*/
|
|
16
|
+
/** Whether classical+PQC hybridization is required during the transition, per regime. */
|
|
17
|
+
export type HybridStance = "required" | "recommended" | "optional";
|
|
18
|
+
/** A regime's PQC guidance profile. */
|
|
19
|
+
export interface StandardsProfile {
|
|
20
|
+
/** Stable id used by `--profile` (kebab-case). */
|
|
21
|
+
readonly id: string;
|
|
22
|
+
/** Human-readable name. */
|
|
23
|
+
readonly name: string;
|
|
24
|
+
/** The authority / document of record. */
|
|
25
|
+
readonly authority: string;
|
|
26
|
+
/** The KEM / signature parameter sets this regime calls for. */
|
|
27
|
+
readonly paramSets: {
|
|
28
|
+
readonly kem: string;
|
|
29
|
+
readonly signature: string;
|
|
30
|
+
};
|
|
31
|
+
/** Whether hybridization is required / recommended / optional under this regime. */
|
|
32
|
+
readonly hybridStance: HybridStance;
|
|
33
|
+
/** One-line regime-specific hybrid guidance surfaced in remediation. */
|
|
34
|
+
readonly hybridGuidance: string;
|
|
35
|
+
/** Year after which classical public-key crypto is deprecated under this regime. */
|
|
36
|
+
readonly deprecateAfter: number;
|
|
37
|
+
/** Year after which it is disallowed. */
|
|
38
|
+
readonly disallowAfter: number;
|
|
39
|
+
/** Spec identifier / publication of record. */
|
|
40
|
+
readonly citation: string;
|
|
41
|
+
/** `YYYY-MM` — when this profile was last verified against its source. */
|
|
42
|
+
readonly asOf: string;
|
|
43
|
+
}
|
|
44
|
+
/** The default profile id when `--profile` is not given. */
|
|
45
|
+
export declare const DEFAULT_PROFILE_ID = "nist";
|
|
46
|
+
/**
|
|
47
|
+
* Built-in regime profiles. Facts reflect each authority's published PQC-transition
|
|
48
|
+
* position as of the `asOf` date; verify against the cited source before relying on a
|
|
49
|
+
* deadline or a hybrid mandate for a compliance decision.
|
|
50
|
+
*/
|
|
51
|
+
export declare const STANDARDS_PROFILES: Readonly<Record<string, StandardsProfile>>;
|
|
52
|
+
/** All built-in profile ids, in a stable order (default first). */
|
|
53
|
+
export declare function standardsProfileIds(): string[];
|
|
54
|
+
/** Look up a built-in profile by id, or `undefined` when unknown. */
|
|
55
|
+
export declare function getStandardsProfile(id: string): StandardsProfile | undefined;
|
|
56
|
+
/** The default profile (NIST). Always defined. */
|
|
57
|
+
export declare function defaultStandardsProfile(): StandardsProfile;
|
|
58
|
+
//# sourceMappingURL=standards-profiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standards-profiles.d.ts","sourceRoot":"","sources":["../src/standards-profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,yFAAyF;AACzF,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC;AAEnE,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACzE,oFAAoF;IACpF,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,wEAAwE;IACxE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,oFAAoF;IACpF,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,yCAAyC;IACzC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,4DAA4D;AAC5D,eAAO,MAAM,kBAAkB,SAAS,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAkEzE,CAAC;AAEF,mEAAmE;AACnE,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAK9C;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAE5E;AAED,kDAAkD;AAClD,wBAAgB,uBAAuB,IAAI,gBAAgB,CAE1D"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selectable STANDARDS PROFILES — the regime a scan's remediation, deadlines, and
|
|
3
|
+
* hybrid guidance are tailored to. Different national/regional authorities agree on
|
|
4
|
+
* the PQC primitives (ML-KEM / ML-DSA) but diverge on two things this tool must not
|
|
5
|
+
* hardcode: (a) the required PARAMETER SETS (a commercial ML-KEM-768 vs a
|
|
6
|
+
* national-security ML-KEM-1024), and (b) the HYBRID STANCE — whether classical+PQC
|
|
7
|
+
* hybridization is required, recommended, or optional during the transition. Baking
|
|
8
|
+
* in NIST/CNSA's "hybrids optional" is wrong for an ANSSI or BSI audience, where
|
|
9
|
+
* hybrid is required. `--profile <id>` selects the regime; `--policy` composes an
|
|
10
|
+
* org's own exceptions on top.
|
|
11
|
+
*
|
|
12
|
+
* Like {@link PqcStandards}, every profile carries a citation + `asOf` date and is
|
|
13
|
+
* re-verified on the quarterly standards cadence. These are guidance summaries, not
|
|
14
|
+
* legal advice — consult the cited source of record.
|
|
15
|
+
*/
|
|
16
|
+
/** The default profile id when `--profile` is not given. */
|
|
17
|
+
export const DEFAULT_PROFILE_ID = "nist";
|
|
18
|
+
/**
|
|
19
|
+
* Built-in regime profiles. Facts reflect each authority's published PQC-transition
|
|
20
|
+
* position as of the `asOf` date; verify against the cited source before relying on a
|
|
21
|
+
* deadline or a hybrid mandate for a compliance decision.
|
|
22
|
+
*/
|
|
23
|
+
export const STANDARDS_PROFILES = {
|
|
24
|
+
nist: {
|
|
25
|
+
id: "nist",
|
|
26
|
+
name: "NIST (general / commercial)",
|
|
27
|
+
authority: "NIST",
|
|
28
|
+
paramSets: { kem: "ML-KEM-768 (FIPS 203)", signature: "ML-DSA-65 (FIPS 204)" },
|
|
29
|
+
hybridStance: "recommended",
|
|
30
|
+
hybridGuidance: "Hybrid key establishment (e.g. X25519MLKEM768) is permitted and recommended during the transition; pure ML-KEM is also acceptable (SP 800-227 / IR 8547).",
|
|
31
|
+
deprecateAfter: 2030,
|
|
32
|
+
disallowAfter: 2035,
|
|
33
|
+
citation: "NIST IR 8547 + FIPS 203/204/205",
|
|
34
|
+
asOf: "2026-07",
|
|
35
|
+
},
|
|
36
|
+
"cnsa-2.0": {
|
|
37
|
+
id: "cnsa-2.0",
|
|
38
|
+
name: "NSA CNSA 2.0 (national-security systems)",
|
|
39
|
+
authority: "NSA",
|
|
40
|
+
paramSets: { kem: "ML-KEM-1024 (FIPS 203)", signature: "ML-DSA-87 (FIPS 204)" },
|
|
41
|
+
hybridStance: "optional",
|
|
42
|
+
hybridGuidance: "CNSA 2.0 targets pure PQC and does not require hybrids; if a hybrid TLS group is used, it must be SecP384r1MLKEM1024 — X25519MLKEM768's ML-KEM-768 component is sub-CNSA.",
|
|
43
|
+
deprecateAfter: 2030,
|
|
44
|
+
disallowAfter: 2035,
|
|
45
|
+
citation: "NSA CNSA 2.0 (2030/2033/2035 migration milestones)",
|
|
46
|
+
asOf: "2026-07",
|
|
47
|
+
},
|
|
48
|
+
"bsi-tr-02102": {
|
|
49
|
+
id: "bsi-tr-02102",
|
|
50
|
+
name: "BSI TR-02102 (Germany)",
|
|
51
|
+
authority: "BSI",
|
|
52
|
+
paramSets: { kem: "ML-KEM-768 (FIPS 203)", signature: "ML-DSA-65 (FIPS 204)" },
|
|
53
|
+
hybridStance: "required",
|
|
54
|
+
hybridGuidance: "BSI requires PQC be deployed in HYBRID with an established classical scheme during the transition (defense-in-depth); FrodoKEM is the conservative KEM alternative to ML-KEM, and XMSS/LMS are approved for firmware signing.",
|
|
55
|
+
deprecateAfter: 2030,
|
|
56
|
+
disallowAfter: 2035,
|
|
57
|
+
citation: "BSI TR-02102-1 (Kryptographische Verfahren)",
|
|
58
|
+
asOf: "2026-07",
|
|
59
|
+
},
|
|
60
|
+
anssi: {
|
|
61
|
+
id: "anssi",
|
|
62
|
+
name: "ANSSI (France)",
|
|
63
|
+
authority: "ANSSI",
|
|
64
|
+
paramSets: { kem: "ML-KEM-1024 (FIPS 203)", signature: "ML-DSA-87 (FIPS 204)" },
|
|
65
|
+
hybridStance: "required",
|
|
66
|
+
hybridGuidance: "ANSSI requires HYBRIDIZATION (classical + PQC) throughout the transition phase and does not endorse pure PQC alone yet; use the highest parameter set for long-lived assurance.",
|
|
67
|
+
deprecateAfter: 2030,
|
|
68
|
+
disallowAfter: 2035,
|
|
69
|
+
citation: "ANSSI — PQC transition position papers",
|
|
70
|
+
asOf: "2026-07",
|
|
71
|
+
},
|
|
72
|
+
"uk-ncsc": {
|
|
73
|
+
id: "uk-ncsc",
|
|
74
|
+
name: "UK NCSC",
|
|
75
|
+
authority: "NCSC",
|
|
76
|
+
paramSets: { kem: "ML-KEM-768 (FIPS 203)", signature: "ML-DSA-65 (FIPS 204)" },
|
|
77
|
+
hybridStance: "recommended",
|
|
78
|
+
hybridGuidance: "NCSC recommends ML-KEM / ML-DSA and is broadly agnostic on hybridization (recommended, not mandated); its migration milestones are earlier — discovery/plan by 2028, high-priority migration by 2031, complete by 2035.",
|
|
79
|
+
deprecateAfter: 2031,
|
|
80
|
+
disallowAfter: 2035,
|
|
81
|
+
citation: "NCSC — Preparing for quantum-safe cryptography / PQC migration timeline",
|
|
82
|
+
asOf: "2026-07",
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
/** All built-in profile ids, in a stable order (default first). */
|
|
86
|
+
export function standardsProfileIds() {
|
|
87
|
+
return [
|
|
88
|
+
DEFAULT_PROFILE_ID,
|
|
89
|
+
...Object.keys(STANDARDS_PROFILES).filter((id) => id !== DEFAULT_PROFILE_ID),
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
/** Look up a built-in profile by id, or `undefined` when unknown. */
|
|
93
|
+
export function getStandardsProfile(id) {
|
|
94
|
+
return STANDARDS_PROFILES[id];
|
|
95
|
+
}
|
|
96
|
+
/** The default profile (NIST). Always defined. */
|
|
97
|
+
export function defaultStandardsProfile() {
|
|
98
|
+
return STANDARDS_PROFILES[DEFAULT_PROFILE_ID];
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=standards-profiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standards-profiles.js","sourceRoot":"","sources":["../src/standards-profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA6BH,4DAA4D;AAC5D,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAEzC;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA+C;IAC5E,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,6BAA6B;QACnC,SAAS,EAAE,MAAM;QACjB,SAAS,EAAE,EAAE,GAAG,EAAE,uBAAuB,EAAE,SAAS,EAAE,sBAAsB,EAAE;QAC9E,YAAY,EAAE,aAAa;QAC3B,cAAc,EACZ,2JAA2J;QAC7J,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,iCAAiC;QAC3C,IAAI,EAAE,SAAS;KAChB;IACD,UAAU,EAAE;QACV,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,0CAA0C;QAChD,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,EAAE,GAAG,EAAE,wBAAwB,EAAE,SAAS,EAAE,sBAAsB,EAAE;QAC/E,YAAY,EAAE,UAAU;QACxB,cAAc,EACZ,2KAA2K;QAC7K,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,oDAAoD;QAC9D,IAAI,EAAE,SAAS;KAChB;IACD,cAAc,EAAE;QACd,EAAE,EAAE,cAAc;QAClB,IAAI,EAAE,wBAAwB;QAC9B,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,EAAE,GAAG,EAAE,uBAAuB,EAAE,SAAS,EAAE,sBAAsB,EAAE;QAC9E,YAAY,EAAE,UAAU;QACxB,cAAc,EACZ,+NAA+N;QACjO,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,6CAA6C;QACvD,IAAI,EAAE,SAAS;KAChB;IACD,KAAK,EAAE;QACL,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,gBAAgB;QACtB,SAAS,EAAE,OAAO;QAClB,SAAS,EAAE,EAAE,GAAG,EAAE,wBAAwB,EAAE,SAAS,EAAE,sBAAsB,EAAE;QAC/E,YAAY,EAAE,UAAU;QACxB,cAAc,EACZ,iLAAiL;QACnL,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,wCAAwC;QAClD,IAAI,EAAE,SAAS;KAChB;IACD,SAAS,EAAE;QACT,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,SAAS;QACf,SAAS,EAAE,MAAM;QACjB,SAAS,EAAE,EAAE,GAAG,EAAE,uBAAuB,EAAE,SAAS,EAAE,sBAAsB,EAAE;QAC9E,YAAY,EAAE,aAAa;QAC3B,cAAc,EACZ,yNAAyN;QAC3N,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,yEAAyE;QACnF,IAAI,EAAE,SAAS;KAChB;CACF,CAAC;AAEF,mEAAmE;AACnE,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,kBAAkB;QAClB,GAAG,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,kBAAkB,CAAC;KAC7E,CAAC;AACJ,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,mBAAmB,CAAC,EAAU;IAC5C,OAAO,kBAAkB,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,uBAAuB;IACrC,OAAO,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;AAChD,CAAC","sourcesContent":["/**\n * Selectable STANDARDS PROFILES — the regime a scan's remediation, deadlines, and\n * hybrid guidance are tailored to. Different national/regional authorities agree on\n * the PQC primitives (ML-KEM / ML-DSA) but diverge on two things this tool must not\n * hardcode: (a) the required PARAMETER SETS (a commercial ML-KEM-768 vs a\n * national-security ML-KEM-1024), and (b) the HYBRID STANCE — whether classical+PQC\n * hybridization is required, recommended, or optional during the transition. Baking\n * in NIST/CNSA's \"hybrids optional\" is wrong for an ANSSI or BSI audience, where\n * hybrid is required. `--profile <id>` selects the regime; `--policy` composes an\n * org's own exceptions on top.\n *\n * Like {@link PqcStandards}, every profile carries a citation + `asOf` date and is\n * re-verified on the quarterly standards cadence. These are guidance summaries, not\n * legal advice — consult the cited source of record.\n */\n\n/** Whether classical+PQC hybridization is required during the transition, per regime. */\nexport type HybridStance = \"required\" | \"recommended\" | \"optional\";\n\n/** A regime's PQC guidance profile. */\nexport interface StandardsProfile {\n /** Stable id used by `--profile` (kebab-case). */\n readonly id: string;\n /** Human-readable name. */\n readonly name: string;\n /** The authority / document of record. */\n readonly authority: string;\n /** The KEM / signature parameter sets this regime calls for. */\n readonly paramSets: { readonly kem: string; readonly signature: string };\n /** Whether hybridization is required / recommended / optional under this regime. */\n readonly hybridStance: HybridStance;\n /** One-line regime-specific hybrid guidance surfaced in remediation. */\n readonly hybridGuidance: string;\n /** Year after which classical public-key crypto is deprecated under this regime. */\n readonly deprecateAfter: number;\n /** Year after which it is disallowed. */\n readonly disallowAfter: number;\n /** Spec identifier / publication of record. */\n readonly citation: string;\n /** `YYYY-MM` — when this profile was last verified against its source. */\n readonly asOf: string;\n}\n\n/** The default profile id when `--profile` is not given. */\nexport const DEFAULT_PROFILE_ID = \"nist\";\n\n/**\n * Built-in regime profiles. Facts reflect each authority's published PQC-transition\n * position as of the `asOf` date; verify against the cited source before relying on a\n * deadline or a hybrid mandate for a compliance decision.\n */\nexport const STANDARDS_PROFILES: Readonly<Record<string, StandardsProfile>> = {\n nist: {\n id: \"nist\",\n name: \"NIST (general / commercial)\",\n authority: \"NIST\",\n paramSets: { kem: \"ML-KEM-768 (FIPS 203)\", signature: \"ML-DSA-65 (FIPS 204)\" },\n hybridStance: \"recommended\",\n hybridGuidance:\n \"Hybrid key establishment (e.g. X25519MLKEM768) is permitted and recommended during the transition; pure ML-KEM is also acceptable (SP 800-227 / IR 8547).\",\n deprecateAfter: 2030,\n disallowAfter: 2035,\n citation: \"NIST IR 8547 + FIPS 203/204/205\",\n asOf: \"2026-07\",\n },\n \"cnsa-2.0\": {\n id: \"cnsa-2.0\",\n name: \"NSA CNSA 2.0 (national-security systems)\",\n authority: \"NSA\",\n paramSets: { kem: \"ML-KEM-1024 (FIPS 203)\", signature: \"ML-DSA-87 (FIPS 204)\" },\n hybridStance: \"optional\",\n hybridGuidance:\n \"CNSA 2.0 targets pure PQC and does not require hybrids; if a hybrid TLS group is used, it must be SecP384r1MLKEM1024 — X25519MLKEM768's ML-KEM-768 component is sub-CNSA.\",\n deprecateAfter: 2030,\n disallowAfter: 2035,\n citation: \"NSA CNSA 2.0 (2030/2033/2035 migration milestones)\",\n asOf: \"2026-07\",\n },\n \"bsi-tr-02102\": {\n id: \"bsi-tr-02102\",\n name: \"BSI TR-02102 (Germany)\",\n authority: \"BSI\",\n paramSets: { kem: \"ML-KEM-768 (FIPS 203)\", signature: \"ML-DSA-65 (FIPS 204)\" },\n hybridStance: \"required\",\n hybridGuidance:\n \"BSI requires PQC be deployed in HYBRID with an established classical scheme during the transition (defense-in-depth); FrodoKEM is the conservative KEM alternative to ML-KEM, and XMSS/LMS are approved for firmware signing.\",\n deprecateAfter: 2030,\n disallowAfter: 2035,\n citation: \"BSI TR-02102-1 (Kryptographische Verfahren)\",\n asOf: \"2026-07\",\n },\n anssi: {\n id: \"anssi\",\n name: \"ANSSI (France)\",\n authority: \"ANSSI\",\n paramSets: { kem: \"ML-KEM-1024 (FIPS 203)\", signature: \"ML-DSA-87 (FIPS 204)\" },\n hybridStance: \"required\",\n hybridGuidance:\n \"ANSSI requires HYBRIDIZATION (classical + PQC) throughout the transition phase and does not endorse pure PQC alone yet; use the highest parameter set for long-lived assurance.\",\n deprecateAfter: 2030,\n disallowAfter: 2035,\n citation: \"ANSSI — PQC transition position papers\",\n asOf: \"2026-07\",\n },\n \"uk-ncsc\": {\n id: \"uk-ncsc\",\n name: \"UK NCSC\",\n authority: \"NCSC\",\n paramSets: { kem: \"ML-KEM-768 (FIPS 203)\", signature: \"ML-DSA-65 (FIPS 204)\" },\n hybridStance: \"recommended\",\n hybridGuidance:\n \"NCSC recommends ML-KEM / ML-DSA and is broadly agnostic on hybridization (recommended, not mandated); its migration milestones are earlier — discovery/plan by 2028, high-priority migration by 2031, complete by 2035.\",\n deprecateAfter: 2031,\n disallowAfter: 2035,\n citation: \"NCSC — Preparing for quantum-safe cryptography / PQC migration timeline\",\n asOf: \"2026-07\",\n },\n};\n\n/** All built-in profile ids, in a stable order (default first). */\nexport function standardsProfileIds(): string[] {\n return [\n DEFAULT_PROFILE_ID,\n ...Object.keys(STANDARDS_PROFILES).filter((id) => id !== DEFAULT_PROFILE_ID),\n ];\n}\n\n/** Look up a built-in profile by id, or `undefined` when unknown. */\nexport function getStandardsProfile(id: string): StandardsProfile | undefined {\n return STANDARDS_PROFILES[id];\n}\n\n/** The default profile (NIST). Always defined. */\nexport function defaultStandardsProfile(): StandardsProfile {\n return STANDARDS_PROFILES[DEFAULT_PROFILE_ID];\n}\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -68,7 +68,7 @@ export interface Finding {
|
|
|
68
68
|
location: SourceLocation;
|
|
69
69
|
}
|
|
70
70
|
/** Package ecosystems the dependency scanner understands. */
|
|
71
|
-
export type DependencyEcosystem = "npm" | "pypi" | "cargo" | "go" | "maven" | "rubygems" | "nuget";
|
|
71
|
+
export type DependencyEcosystem = "npm" | "pypi" | "cargo" | "go" | "maven" | "rubygems" | "nuget" | "composer";
|
|
72
72
|
/** A known quantum-vulnerable dependency entry. */
|
|
73
73
|
export interface VulnerableDependency {
|
|
74
74
|
/** Package name (as written in the ecosystem's manifest). */
|
|
@@ -96,7 +96,7 @@ export type DetectorScope = "source" | "config";
|
|
|
96
96
|
* The programming language / surface a detector targets. `"any"` means the
|
|
97
97
|
* detector is language-agnostic (e.g. PEM material, config files).
|
|
98
98
|
*/
|
|
99
|
-
export type DetectorLanguage = "js" | "python" | "go" | "java" | "csharp" | "rust" | "ruby" | "php" | "elixir" | "c" | "any";
|
|
99
|
+
export type DetectorLanguage = "js" | "python" | "go" | "java" | "csharp" | "rust" | "ruby" | "php" | "elixir" | "c" | "swift" | "objc" | "dart" | "solidity" | "any";
|
|
100
100
|
/**
|
|
101
101
|
* Declarative metadata for a single rule a detector can emit. This is the
|
|
102
102
|
* catalog entry: the stable, queryable description of a rule keyed by the
|
|
@@ -295,10 +295,11 @@ export interface ScanResult {
|
|
|
295
295
|
*/
|
|
296
296
|
diagnostics?: ScanDiagnostics;
|
|
297
297
|
/**
|
|
298
|
-
* Of `filesScanned`, how many were in a source language the scanner can
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
298
|
+
* Of `filesScanned`, how many were in a source language the scanner can actually
|
|
299
|
+
* analyze for inline crypto (the 13 packs: JS/TS, Python, Go, Java/Kotlin/Scala,
|
|
300
|
+
* C#, Rust, Ruby, PHP, Elixir, C/C++, Swift, Objective-C, Dart). When this is 0
|
|
301
|
+
* but `filesScanned` > 0, the readiness score reflects NO analyzable code — the
|
|
302
|
+
* crypto likely lives in an unsupported language (Lua, Perl, …) — and
|
|
302
303
|
* reporters surface that so a bare 100/100 can't read as "safe". Optional for
|
|
303
304
|
* backward compatibility with hand-built results.
|
|
304
305
|
*/
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,6DAA6D;AAC7D,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEvE,gFAAgF;AAChF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEnD,+DAA+D;AAC/D,MAAM,MAAM,eAAe,GACvB,KAAK,GACL,cAAc,GACd,WAAW,GACX,KAAK,GACL,aAAa,GACb,YAAY,GACZ,MAAM,GACN,KAAK,CAAC;AAEV,yEAAyE;AACzE,MAAM,MAAM,eAAe,GACvB,KAAK,GACL,MAAM,GACN,OAAO,GACP,OAAO,GACP,IAAI,GACJ,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,SAAS,CAAC;AAEd,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AAEtD;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,cAAc,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,iCAAiC;AACjC,MAAM,WAAW,OAAO;IACtB,uGAAuG;IACvG,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,yDAAyD;IACzD,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,iEAAiE;IACjE,IAAI,EAAE,OAAO,CAAC;IACd,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kFAAkF;IAClF,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,6DAA6D;AAC7D,MAAM,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * @quantakrypto/core — shared types (the locked public contract).\n *\n * These types are the stable interface between every tool in the monorepo\n * (qScan, the MCP server, the GitHub Action). Treat additions as backwards\n * compatible; treat renames/removals as breaking.\n */\n\n/** How serious a finding is, ordered most → least severe. */\nexport type Severity = \"critical\" | \"high\" | \"medium\" | \"low\" | \"info\";\n\n/** How sure the detector is that the finding is a real use of the algorithm. */\nexport type Confidence = \"high\" | \"medium\" | \"low\";\n\n/** What kind of cryptographic concern a finding represents. */\nexport type FindingCategory =\n | \"kem\" // key encapsulation / public-key encryption (e.g. RSA-OAEP)\n | \"key-exchange\" // (EC)DH\n | \"signature\" // RSA/ECDSA/EdDSA signing\n | \"tls\" // transport configuration\n | \"certificate\" // X.509 / PKI material\n | \"dependency\" // a quantum-vulnerable library in the dependency tree\n | \"hash\" // weak / pre-quantum hash usage\n | \"rng\"; // randomness concerns\n\n/** Classical asymmetric algorithm families that are not quantum-safe. */\nexport type AlgorithmFamily =\n | \"RSA\"\n | \"ECDH\"\n | \"ECDSA\"\n | \"EdDSA\"\n | \"DH\"\n | \"DSA\"\n | \"X25519\"\n | \"X448\"\n | \"ECIES\"\n | \"unknown\";\n\n/** A precise location inside a scanned file. */\nexport interface SourceLocation {\n /** Path relative to the scan root, using POSIX separators. */\n file: string;\n /** 1-based line number. */\n line: number;\n /** 1-based column number, if known. */\n column?: number;\n /** 1-based end line, for multi-line matches. */\n endLine?: number;\n /** The matched source text (trimmed, single line). */\n snippet?: string;\n}\n\n/** Relative urgency an LLM triage pass assigns to a finding. */\nexport type TriagePriority = \"now\" | \"soon\" | \"later\";\n\n/**\n * Optional LLM triage annotation attached to a finding by `qscan --triage`.\n * Purely additive: it re-ranks and explains, it never suppresses a finding and\n * never influences the exit code (which is computed from `severity` alone).\n */\nexport interface TriageAnnotation {\n /** 0–100 real-world exposure/exploitability estimate. */\n exposureScore: number;\n priority: TriagePriority;\n rationale: string;\n}\n\n/** A single detected concern. */\nexport interface Finding {\n /** Stable rule identifier, e.g. \"rsa-keygen\", \"ecdh-usage\", \"tls-legacy-version\", \"dep-vulnerable\". */\n ruleId: string;\n title: string;\n category: FindingCategory;\n severity: Severity;\n confidence: Confidence;\n /** The classical algorithm involved, when applicable. */\n algorithm?: AlgorithmFamily;\n /** True when this is exposed to \"harvest now, decrypt later\". */\n hndl: boolean;\n /** One-line human explanation of the concern. */\n message: string;\n /** Suggested post-quantum remediation (e.g. ML-KEM, hybrid X25519MLKEM768). */\n remediation?: string;\n /** Associated CWE identifier, e.g. \"CWE-327\" (broken crypto), \"CWE-326\" (weak strength). */\n cwe?: string;\n /**\n * True when the matched snippet IS the sensitive value (e.g. a PEM private/\n * public key block, an `ssh-rsa AAAA…` public key). Reporters ALWAYS drop the\n * snippet for such findings, regardless of any redaction flag.\n */\n sensitive?: boolean;\n /** Optional LLM triage annotation (`qscan --triage`); never affects exit code. */\n triage?: TriageAnnotation;\n location: SourceLocation;\n}\n\n/** Package ecosystems the dependency scanner understands. */\nexport type DependencyEcosystem = \"npm\" | \"pypi\" | \"cargo\" | \"go\" | \"maven\" | \"rubygems\" | \"nuget\";\n\n/** A known quantum-vulnerable dependency entry. */\nexport interface VulnerableDependency {\n /** Package name (as written in the ecosystem's manifest). */\n name: string;\n ecosystem: DependencyEcosystem;\n /** Why it's flagged (what classical crypto it provides). */\n reason: string;\n /** Algorithm families the package primarily exposes. */\n algorithms: AlgorithmFamily[];\n severity: Severity;\n /**\n * Explicit harvest-now-decrypt-later override. When omitted, HNDL is inferred\n * from whether any listed family is a confidentiality family. Set `false` for\n * signing-only packages (e.g. JWS/JWT libraries) that list RSA/EC as families\n * but never do key transport or key agreement — signatures are not HNDL-exposed.\n */\n hndl?: boolean;\n}\n\n/**\n * Which logical scope a detector belongs to. Drives the source/config scope\n * toggles in {@link ScanOptions} (replacing the old ruleId-prefix inference).\n */\nexport type DetectorScope = \"source\" | \"config\";\n\n/**\n * The programming language / surface a detector targets. `\"any\"` means the\n * detector is language-agnostic (e.g. PEM material, config files).\n */\nexport type DetectorLanguage =\n | \"js\"\n | \"python\"\n | \"go\"\n | \"java\"\n | \"csharp\"\n | \"rust\"\n | \"ruby\"\n | \"php\"\n | \"elixir\"\n | \"c\"\n | \"any\";\n\n/**\n * Declarative metadata for a single rule a detector can emit. This is the\n * catalog entry: the stable, queryable description of a rule keyed by the\n * `ruleId` it stamps onto findings. It is the single source of truth for a\n * rule's title / severity / category / remediation, consumed by the SARIF\n * `rules[]` block, the MCP `explain_finding` resolver, and future per-rule\n * enable/disable + language-pack work.\n *\n * For most rules the metadata is fixed and `detect()` builds findings straight\n * from it (see `findingFromRule`). A few rules are inherently multi-variant\n * (e.g. `node-crypto-keygen` spans RSA/EC/DSA/DH/Ed25519 at different\n * severities); for those the metadata here is a REPRESENTATIVE umbrella and\n * `detect()` refines the per-finding fields at match time. The catalog always\n * enumerates every emittable ruleId regardless.\n */\nexport interface RuleMeta {\n /** Stable rule id — matches {@link Finding.ruleId}. Unique across the catalog. */\n id: string;\n /** Canonical human title. */\n title: string;\n category: FindingCategory;\n severity: Severity;\n /** Default confidence for findings of this rule. */\n confidence: Confidence;\n /** Harvest-now-decrypt-later exposure. */\n hndl: boolean;\n /** Representative classical algorithm family; refined per-finding when it varies. */\n algorithm?: AlgorithmFamily;\n /** Associated CWE identifier (e.g. \"CWE-327\"). */\n cwe?: string;\n /** Suggested post-quantum remediation. When omitted, derived from {@link algorithm}. */\n remediation?: string;\n /** Canonical one-line human explanation; may be refined per-finding. */\n message: string;\n /** True when this rule's matched snippet IS sensitive key material. */\n sensitive?: boolean;\n /** Short description of what the rule detects (for catalog / MCP surfaces). */\n description?: string;\n}\n\n/** A pluggable source detector. Detectors are pure and stateless. */\nexport interface Detector {\n /** Unique id, used as the Finding.ruleId prefix space. */\n id: string;\n /** Human description of what the detector looks for. */\n description: string;\n /**\n * Logical scope of this detector's findings. Used by `scan()` to honour the\n * `config` / `source` toggles. Defaults to `\"source\"` when omitted (for\n * backward compatibility with externally-defined detectors).\n */\n scope?: DetectorScope;\n /**\n * Language this detector targets, for documentation / registry filtering.\n * Defaults to `\"js\"` when omitted.\n */\n language?: DetectorLanguage;\n /**\n * The rules this detector can emit, as declarative metadata. Together across\n * all detectors these form the rule catalog ({@link DetectorRegistry.ruleCatalog}).\n * Optional for backward compatibility with externally-defined detectors, but\n * all built-in detectors declare it.\n */\n rules?: RuleMeta[];\n /** Whether this detector should run against the given file path. */\n appliesTo(filePath: string): boolean;\n /** Inspect a single file's contents and return zero or more findings. */\n detect(input: DetectorInput): Finding[];\n}\n\nexport interface DetectorInput {\n /** Path relative to the scan root (POSIX). */\n file: string;\n /** Full file contents. */\n content: string;\n}\n\n/** Options controlling a scan. */\nexport interface ScanOptions {\n /** Absolute or relative directory (or single file) to scan. */\n root: string;\n /**\n * Restrict the walk to paths matching one of these include patterns\n * (substring or relative-path-prefix match). When omitted, all non-excluded\n * files are scanned. Wired into the walker.\n */\n include?: string[];\n /** Extra exclude patterns (in addition to the built-in defaults). */\n exclude?: string[];\n /** Disable the built-in ignore list (node_modules, .git, dist, …). */\n noDefaultIgnores?: boolean;\n /** Scan source files for inline crypto usage. Default: true. */\n source?: boolean;\n /** Scan dependency manifests/lockfiles for vulnerable libraries. Default: true. */\n dependencies?: boolean;\n /** Scan config files (TLS, certificates). Default: true. */\n config?: boolean;\n /** Max file size to read, in bytes. Default: 2 MiB. */\n maxFileSize?: number;\n /**\n * Scan minified / generated / bundled files (large single-line content)\n * instead of skipping them. Default: false (skip them for speed).\n */\n scanMinified?: boolean;\n /**\n * Explicit relative file list (POSIX, relative to `root`) to scan instead of\n * walking the tree. Used for incremental / changed-files scans. Each path is\n * still subject to the binary / size filters. When set, the directory walk is\n * bypassed entirely.\n */\n files?: string[];\n /**\n * Override / extend the built-in detector set. When omitted, the default\n * registry's detectors are used.\n */\n detectors?: Detector[];\n /**\n * Rule ids to suppress. Any finding whose `ruleId` is listed here is dropped\n * after detection. Serializable (a plain string array), so it is honoured on\n * both the serial and the worker-thread (`scanParallel`) paths. See the rule\n * catalog ({@link DetectorRegistry.ruleCatalog}) for the valid ids.\n */\n disabledRules?: string[];\n /**\n * Path to an on-disk scan cache. When set, unchanged files (same content hash)\n * reuse their previous findings instead of re-running detectors, and the cache\n * is rewritten after the scan. Invalidated wholesale when the tool version,\n * detector set, or `disabledRules` change. Optional; omitted = no caching.\n * The cache forces the in-process (serial) path.\n */\n cacheFile?: string;\n /** Optional progress callback. */\n onFile?: (file: string) => void;\n /**\n * Optional abort signal. When it fires mid-walk the scan stops cooperatively\n * and rejects with an `AbortError` (a `DOMException`-like error with\n * `name === \"AbortError\"`).\n */\n signal?: AbortSignal;\n /**\n * Work budget: maximum number of files to scan. When exceeded mid-walk the\n * scan stops and throws a `BudgetExceededError`. Unlimited when omitted.\n */\n maxFiles?: number;\n /**\n * Work budget: maximum cumulative bytes of scanned file content. When\n * exceeded mid-walk the scan stops and throws a `BudgetExceededError`.\n * Unlimited when omitted.\n */\n maxBytes?: number;\n}\n\n/** Extra options for {@link scanParallel}, layered onto {@link ScanOptions}. */\nexport interface ParallelScanOptions extends ScanOptions {\n /**\n * Number of worker threads. Default: `os.availableParallelism()`. A value of\n * 0 or 1 forces the in-process serial path.\n */\n concurrency?: number;\n /**\n * Combined-size floor (bytes) below which the scan always runs in-process.\n * Default: 2 MiB. Also stays serial below `parallelFileThreshold` files.\n */\n parallelThresholdBytes?: number;\n /** File-count floor below which the scan always runs in-process. Default: 200. */\n parallelFileThreshold?: number;\n /** Target bytes per worker chunk. Default: 4 MiB. */\n chunkBytes?: number;\n}\n\n/** Aggregated counts produced from a scan's findings. */\nexport interface CryptoInventory {\n byAlgorithm: Partial<Record<AlgorithmFamily, number>>;\n byCategory: Partial<Record<FindingCategory, number>>;\n bySeverity: Record<Severity, number>;\n /** Number of findings exposed to harvest-now-decrypt-later. */\n hndlCount: number;\n /** 0–100 readiness score (100 = no classical asymmetric crypto found). */\n readinessScore: number;\n}\n\n/**\n * Non-fatal things that happened during a scan that reduce coverage. Surfaced so\n * a silent under-scan (e.g. half the tree was unreadable) can't masquerade as a\n * clean \"0 findings\" result — reporters warn when any count is non-zero.\n */\nexport interface ScanDiagnostics {\n /** Files that could not be read (permissions, vanished, decode failure) and were skipped. */\n unreadable: number;\n /** Files skipped because they look machine-minified / generated (scan with `scanMinified` to include). */\n skippedMinified: number;\n}\n\n/** The full result of a scan. */\nexport interface ScanResult {\n /** The scan root (as provided). */\n root: string;\n findings: Finding[];\n filesScanned: number;\n /**\n * Coverage diagnostics: counts of files skipped as unreadable or minified.\n * Optional for backward compatibility with hand-built results.\n */\n diagnostics?: ScanDiagnostics;\n /**\n * Of `filesScanned`, how many were in a source language the scanner can\n * actually analyze for inline crypto (JS/TS, Python, Go, Java). When this is 0 but\n * `filesScanned` > 0, the readiness score reflects NO analyzable code — the\n * crypto likely lives in an unsupported language (Go, Java, Rust, …) — and\n * reporters surface that so a bare 100/100 can't read as \"safe\". Optional for\n * backward compatibility with hand-built results.\n */\n analyzedFiles?: number;\n inventory: CryptoInventory;\n /** ISO timestamps. */\n startedAt: string;\n finishedAt: string;\n /** Tool version that produced the result. */\n toolVersion: string;\n}\n\n/** Output formats qScan / reporters can emit. */\nexport type ReportFormat = \"human\" | \"json\" | \"sarif\";\n\n/** A remediation recommendation for a classical algorithm. */\nexport interface Remediation {\n algorithm: AlgorithmFamily;\n /** Short recommended replacement, e.g. \"ML-KEM-768 (hybrid X25519MLKEM768)\". */\n recommendation: string;\n /** Longer rationale. */\n detail: string;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * @quantakrypto/core — shared types (the locked public contract).\n *\n * These types are the stable interface between every tool in the monorepo\n * (qScan, the MCP server, the GitHub Action). Treat additions as backwards\n * compatible; treat renames/removals as breaking.\n */\n\n/** How serious a finding is, ordered most → least severe. */\nexport type Severity = \"critical\" | \"high\" | \"medium\" | \"low\" | \"info\";\n\n/** How sure the detector is that the finding is a real use of the algorithm. */\nexport type Confidence = \"high\" | \"medium\" | \"low\";\n\n/** What kind of cryptographic concern a finding represents. */\nexport type FindingCategory =\n | \"kem\" // key encapsulation / public-key encryption (e.g. RSA-OAEP)\n | \"key-exchange\" // (EC)DH\n | \"signature\" // RSA/ECDSA/EdDSA signing\n | \"tls\" // transport configuration\n | \"certificate\" // X.509 / PKI material\n | \"dependency\" // a quantum-vulnerable library in the dependency tree\n | \"hash\" // weak / pre-quantum hash usage\n | \"rng\"; // randomness concerns\n\n/** Classical asymmetric algorithm families that are not quantum-safe. */\nexport type AlgorithmFamily =\n | \"RSA\"\n | \"ECDH\"\n | \"ECDSA\"\n | \"EdDSA\"\n | \"DH\"\n | \"DSA\"\n | \"X25519\"\n | \"X448\"\n | \"ECIES\"\n | \"unknown\";\n\n/** A precise location inside a scanned file. */\nexport interface SourceLocation {\n /** Path relative to the scan root, using POSIX separators. */\n file: string;\n /** 1-based line number. */\n line: number;\n /** 1-based column number, if known. */\n column?: number;\n /** 1-based end line, for multi-line matches. */\n endLine?: number;\n /** The matched source text (trimmed, single line). */\n snippet?: string;\n}\n\n/** Relative urgency an LLM triage pass assigns to a finding. */\nexport type TriagePriority = \"now\" | \"soon\" | \"later\";\n\n/**\n * Optional LLM triage annotation attached to a finding by `qscan --triage`.\n * Purely additive: it re-ranks and explains, it never suppresses a finding and\n * never influences the exit code (which is computed from `severity` alone).\n */\nexport interface TriageAnnotation {\n /** 0–100 real-world exposure/exploitability estimate. */\n exposureScore: number;\n priority: TriagePriority;\n rationale: string;\n}\n\n/** A single detected concern. */\nexport interface Finding {\n /** Stable rule identifier, e.g. \"rsa-keygen\", \"ecdh-usage\", \"tls-legacy-version\", \"dep-vulnerable\". */\n ruleId: string;\n title: string;\n category: FindingCategory;\n severity: Severity;\n confidence: Confidence;\n /** The classical algorithm involved, when applicable. */\n algorithm?: AlgorithmFamily;\n /** True when this is exposed to \"harvest now, decrypt later\". */\n hndl: boolean;\n /** One-line human explanation of the concern. */\n message: string;\n /** Suggested post-quantum remediation (e.g. ML-KEM, hybrid X25519MLKEM768). */\n remediation?: string;\n /** Associated CWE identifier, e.g. \"CWE-327\" (broken crypto), \"CWE-326\" (weak strength). */\n cwe?: string;\n /**\n * True when the matched snippet IS the sensitive value (e.g. a PEM private/\n * public key block, an `ssh-rsa AAAA…` public key). Reporters ALWAYS drop the\n * snippet for such findings, regardless of any redaction flag.\n */\n sensitive?: boolean;\n /** Optional LLM triage annotation (`qscan --triage`); never affects exit code. */\n triage?: TriageAnnotation;\n location: SourceLocation;\n}\n\n/** Package ecosystems the dependency scanner understands. */\nexport type DependencyEcosystem =\n | \"npm\"\n | \"pypi\"\n | \"cargo\"\n | \"go\"\n | \"maven\"\n | \"rubygems\"\n | \"nuget\"\n | \"composer\";\n\n/** A known quantum-vulnerable dependency entry. */\nexport interface VulnerableDependency {\n /** Package name (as written in the ecosystem's manifest). */\n name: string;\n ecosystem: DependencyEcosystem;\n /** Why it's flagged (what classical crypto it provides). */\n reason: string;\n /** Algorithm families the package primarily exposes. */\n algorithms: AlgorithmFamily[];\n severity: Severity;\n /**\n * Explicit harvest-now-decrypt-later override. When omitted, HNDL is inferred\n * from whether any listed family is a confidentiality family. Set `false` for\n * signing-only packages (e.g. JWS/JWT libraries) that list RSA/EC as families\n * but never do key transport or key agreement — signatures are not HNDL-exposed.\n */\n hndl?: boolean;\n}\n\n/**\n * Which logical scope a detector belongs to. Drives the source/config scope\n * toggles in {@link ScanOptions} (replacing the old ruleId-prefix inference).\n */\nexport type DetectorScope = \"source\" | \"config\";\n\n/**\n * The programming language / surface a detector targets. `\"any\"` means the\n * detector is language-agnostic (e.g. PEM material, config files).\n */\nexport type DetectorLanguage =\n | \"js\"\n | \"python\"\n | \"go\"\n | \"java\"\n | \"csharp\"\n | \"rust\"\n | \"ruby\"\n | \"php\"\n | \"elixir\"\n | \"c\"\n | \"swift\"\n | \"objc\"\n | \"dart\"\n | \"solidity\"\n | \"any\";\n\n/**\n * Declarative metadata for a single rule a detector can emit. This is the\n * catalog entry: the stable, queryable description of a rule keyed by the\n * `ruleId` it stamps onto findings. It is the single source of truth for a\n * rule's title / severity / category / remediation, consumed by the SARIF\n * `rules[]` block, the MCP `explain_finding` resolver, and future per-rule\n * enable/disable + language-pack work.\n *\n * For most rules the metadata is fixed and `detect()` builds findings straight\n * from it (see `findingFromRule`). A few rules are inherently multi-variant\n * (e.g. `node-crypto-keygen` spans RSA/EC/DSA/DH/Ed25519 at different\n * severities); for those the metadata here is a REPRESENTATIVE umbrella and\n * `detect()` refines the per-finding fields at match time. The catalog always\n * enumerates every emittable ruleId regardless.\n */\nexport interface RuleMeta {\n /** Stable rule id — matches {@link Finding.ruleId}. Unique across the catalog. */\n id: string;\n /** Canonical human title. */\n title: string;\n category: FindingCategory;\n severity: Severity;\n /** Default confidence for findings of this rule. */\n confidence: Confidence;\n /** Harvest-now-decrypt-later exposure. */\n hndl: boolean;\n /** Representative classical algorithm family; refined per-finding when it varies. */\n algorithm?: AlgorithmFamily;\n /** Associated CWE identifier (e.g. \"CWE-327\"). */\n cwe?: string;\n /** Suggested post-quantum remediation. When omitted, derived from {@link algorithm}. */\n remediation?: string;\n /** Canonical one-line human explanation; may be refined per-finding. */\n message: string;\n /** True when this rule's matched snippet IS sensitive key material. */\n sensitive?: boolean;\n /** Short description of what the rule detects (for catalog / MCP surfaces). */\n description?: string;\n}\n\n/** A pluggable source detector. Detectors are pure and stateless. */\nexport interface Detector {\n /** Unique id, used as the Finding.ruleId prefix space. */\n id: string;\n /** Human description of what the detector looks for. */\n description: string;\n /**\n * Logical scope of this detector's findings. Used by `scan()` to honour the\n * `config` / `source` toggles. Defaults to `\"source\"` when omitted (for\n * backward compatibility with externally-defined detectors).\n */\n scope?: DetectorScope;\n /**\n * Language this detector targets, for documentation / registry filtering.\n * Defaults to `\"js\"` when omitted.\n */\n language?: DetectorLanguage;\n /**\n * The rules this detector can emit, as declarative metadata. Together across\n * all detectors these form the rule catalog ({@link DetectorRegistry.ruleCatalog}).\n * Optional for backward compatibility with externally-defined detectors, but\n * all built-in detectors declare it.\n */\n rules?: RuleMeta[];\n /** Whether this detector should run against the given file path. */\n appliesTo(filePath: string): boolean;\n /** Inspect a single file's contents and return zero or more findings. */\n detect(input: DetectorInput): Finding[];\n}\n\nexport interface DetectorInput {\n /** Path relative to the scan root (POSIX). */\n file: string;\n /** Full file contents. */\n content: string;\n}\n\n/** Options controlling a scan. */\nexport interface ScanOptions {\n /** Absolute or relative directory (or single file) to scan. */\n root: string;\n /**\n * Restrict the walk to paths matching one of these include patterns\n * (substring or relative-path-prefix match). When omitted, all non-excluded\n * files are scanned. Wired into the walker.\n */\n include?: string[];\n /** Extra exclude patterns (in addition to the built-in defaults). */\n exclude?: string[];\n /** Disable the built-in ignore list (node_modules, .git, dist, …). */\n noDefaultIgnores?: boolean;\n /** Scan source files for inline crypto usage. Default: true. */\n source?: boolean;\n /** Scan dependency manifests/lockfiles for vulnerable libraries. Default: true. */\n dependencies?: boolean;\n /** Scan config files (TLS, certificates). Default: true. */\n config?: boolean;\n /** Max file size to read, in bytes. Default: 2 MiB. */\n maxFileSize?: number;\n /**\n * Scan minified / generated / bundled files (large single-line content)\n * instead of skipping them. Default: false (skip them for speed).\n */\n scanMinified?: boolean;\n /**\n * Explicit relative file list (POSIX, relative to `root`) to scan instead of\n * walking the tree. Used for incremental / changed-files scans. Each path is\n * still subject to the binary / size filters. When set, the directory walk is\n * bypassed entirely.\n */\n files?: string[];\n /**\n * Override / extend the built-in detector set. When omitted, the default\n * registry's detectors are used.\n */\n detectors?: Detector[];\n /**\n * Rule ids to suppress. Any finding whose `ruleId` is listed here is dropped\n * after detection. Serializable (a plain string array), so it is honoured on\n * both the serial and the worker-thread (`scanParallel`) paths. See the rule\n * catalog ({@link DetectorRegistry.ruleCatalog}) for the valid ids.\n */\n disabledRules?: string[];\n /**\n * Path to an on-disk scan cache. When set, unchanged files (same content hash)\n * reuse their previous findings instead of re-running detectors, and the cache\n * is rewritten after the scan. Invalidated wholesale when the tool version,\n * detector set, or `disabledRules` change. Optional; omitted = no caching.\n * The cache forces the in-process (serial) path.\n */\n cacheFile?: string;\n /** Optional progress callback. */\n onFile?: (file: string) => void;\n /**\n * Optional abort signal. When it fires mid-walk the scan stops cooperatively\n * and rejects with an `AbortError` (a `DOMException`-like error with\n * `name === \"AbortError\"`).\n */\n signal?: AbortSignal;\n /**\n * Work budget: maximum number of files to scan. When exceeded mid-walk the\n * scan stops and throws a `BudgetExceededError`. Unlimited when omitted.\n */\n maxFiles?: number;\n /**\n * Work budget: maximum cumulative bytes of scanned file content. When\n * exceeded mid-walk the scan stops and throws a `BudgetExceededError`.\n * Unlimited when omitted.\n */\n maxBytes?: number;\n}\n\n/** Extra options for {@link scanParallel}, layered onto {@link ScanOptions}. */\nexport interface ParallelScanOptions extends ScanOptions {\n /**\n * Number of worker threads. Default: `os.availableParallelism()`. A value of\n * 0 or 1 forces the in-process serial path.\n */\n concurrency?: number;\n /**\n * Combined-size floor (bytes) below which the scan always runs in-process.\n * Default: 2 MiB. Also stays serial below `parallelFileThreshold` files.\n */\n parallelThresholdBytes?: number;\n /** File-count floor below which the scan always runs in-process. Default: 200. */\n parallelFileThreshold?: number;\n /** Target bytes per worker chunk. Default: 4 MiB. */\n chunkBytes?: number;\n}\n\n/** Aggregated counts produced from a scan's findings. */\nexport interface CryptoInventory {\n byAlgorithm: Partial<Record<AlgorithmFamily, number>>;\n byCategory: Partial<Record<FindingCategory, number>>;\n bySeverity: Record<Severity, number>;\n /** Number of findings exposed to harvest-now-decrypt-later. */\n hndlCount: number;\n /** 0–100 readiness score (100 = no classical asymmetric crypto found). */\n readinessScore: number;\n}\n\n/**\n * Non-fatal things that happened during a scan that reduce coverage. Surfaced so\n * a silent under-scan (e.g. half the tree was unreadable) can't masquerade as a\n * clean \"0 findings\" result — reporters warn when any count is non-zero.\n */\nexport interface ScanDiagnostics {\n /** Files that could not be read (permissions, vanished, decode failure) and were skipped. */\n unreadable: number;\n /** Files skipped because they look machine-minified / generated (scan with `scanMinified` to include). */\n skippedMinified: number;\n}\n\n/** The full result of a scan. */\nexport interface ScanResult {\n /** The scan root (as provided). */\n root: string;\n findings: Finding[];\n filesScanned: number;\n /**\n * Coverage diagnostics: counts of files skipped as unreadable or minified.\n * Optional for backward compatibility with hand-built results.\n */\n diagnostics?: ScanDiagnostics;\n /**\n * Of `filesScanned`, how many were in a source language the scanner can actually\n * analyze for inline crypto (the 13 packs: JS/TS, Python, Go, Java/Kotlin/Scala,\n * C#, Rust, Ruby, PHP, Elixir, C/C++, Swift, Objective-C, Dart). When this is 0\n * but `filesScanned` > 0, the readiness score reflects NO analyzable code — the\n * crypto likely lives in an unsupported language (Lua, Perl, …) — and\n * reporters surface that so a bare 100/100 can't read as \"safe\". Optional for\n * backward compatibility with hand-built results.\n */\n analyzedFiles?: number;\n inventory: CryptoInventory;\n /** ISO timestamps. */\n startedAt: string;\n finishedAt: string;\n /** Tool version that produced the result. */\n toolVersion: string;\n}\n\n/** Output formats qScan / reporters can emit. */\nexport type ReportFormat = \"human\" | \"json\" | \"sarif\";\n\n/** A remediation recommendation for a classical algorithm. */\nexport interface Remediation {\n algorithm: AlgorithmFamily;\n /** Short recommended replacement, e.g. \"ML-KEM-768 (hybrid X25519MLKEM768)\". */\n recommendation: string;\n /** Longer rationale. */\n detail: string;\n}\n"]}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC","sourcesContent":["/**\n * The tool version surfaced in reports. Kept in its own module so reporters and\n * the scan orchestrator can import it without creating a cycle through index.ts.\n * Keep in sync with packages/core/package.json.\n */\nexport const VERSION = \"0.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC","sourcesContent":["/**\n * The tool version surfaced in reports. Kept in its own module so reporters and\n * the scan orchestrator can import it without creating a cycle through index.ts.\n * Keep in sync with packages/core/package.json.\n */\nexport const VERSION = \"0.6.0\";\n"]}
|
package/dist/vex.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ScanResult } from "./types.js";
|
|
2
|
+
/** A single OpenVEX statement: one synthetic vulnerability over its affected products. */
|
|
3
|
+
export interface OpenVexStatement {
|
|
4
|
+
vulnerability: {
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
};
|
|
8
|
+
products: {
|
|
9
|
+
"@id": string;
|
|
10
|
+
}[];
|
|
11
|
+
status: "not_affected" | "affected" | "fixed" | "under_investigation";
|
|
12
|
+
/** Recommended action for an `affected` product (the rule's remediation). */
|
|
13
|
+
action_statement?: string;
|
|
14
|
+
/** Free-form status detail — carries the `--triage` exposure verdict when present. */
|
|
15
|
+
status_notes?: string;
|
|
16
|
+
}
|
|
17
|
+
/** An OpenVEX 0.2.0 document. */
|
|
18
|
+
export interface OpenVexDocument {
|
|
19
|
+
"@context": "https://openvex.dev/ns/v0.2.0";
|
|
20
|
+
"@id": string;
|
|
21
|
+
author: string;
|
|
22
|
+
timestamp: string;
|
|
23
|
+
version: number;
|
|
24
|
+
statements: OpenVexStatement[];
|
|
25
|
+
}
|
|
26
|
+
/** Options for {@link toOpenVex}. */
|
|
27
|
+
export interface OpenVexOptions {
|
|
28
|
+
/** Document author (VEX issuer). Default: `"qScan"`. */
|
|
29
|
+
author?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build an OpenVEX 0.2.0 document from a scan result. One statement per distinct
|
|
33
|
+
* rule id, listing every affected `file:line` product. Output is deterministic
|
|
34
|
+
* (statements sorted by vulnerability name, products sorted and de-duplicated;
|
|
35
|
+
* the `@id` and `timestamp` derive from the result), so re-exporting the same
|
|
36
|
+
* scan yields byte-identical VEX.
|
|
37
|
+
*/
|
|
38
|
+
export declare function toOpenVex(result: ScanResult, opts?: OpenVexOptions): OpenVexDocument;
|
|
39
|
+
//# sourceMappingURL=vex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vex.d.ts","sourceRoot":"","sources":["../src/vex.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtD,0FAA0F;AAC1F,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9B,MAAM,EAAE,cAAc,GAAG,UAAU,GAAG,OAAO,GAAG,qBAAqB,CAAC;IACtE,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sFAAsF;IACtF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,+BAA+B,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED,qCAAqC;AACrC,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAWD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,GAAE,cAAmB,GAAG,eAAe,CA0DxF"}
|
package/dist/vex.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenVEX export — turn a {@link ScanResult} into an OpenVEX 0.2.0 document so
|
|
3
|
+
* the quantum-readiness posture flows into the SAME supply-chain pipeline that
|
|
4
|
+
* already ingests CVE-based VEX (Vulnerability Exploitability eXchange).
|
|
5
|
+
*
|
|
6
|
+
* Reference: OpenVEX spec (https://openvex.dev/, `@context` v0.2.0).
|
|
7
|
+
*
|
|
8
|
+
* Modeling choice (documented, honest): PQC findings have no CVE, so each qScan
|
|
9
|
+
* rule becomes a synthetic vulnerability `QK-<ruleId>`. Every finding is reported
|
|
10
|
+
* `status: "affected"` — the classical, Shor-breakable primitive IS present in
|
|
11
|
+
* the product by construction — with the rule's remediation as the VEX
|
|
12
|
+
* `action_statement`. A `--triage` exposure verdict, when present, is surfaced in
|
|
13
|
+
* `status_notes` (score / priority / rationale). qScan never downgrades a finding
|
|
14
|
+
* to `not_affected`: only the operator can attest a mitigation, so that judgment
|
|
15
|
+
* is deliberately left to them (they can post-process this document).
|
|
16
|
+
*/
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
|
+
/**
|
|
19
|
+
* A stable product identifier for a finding as an IRI (OpenVEX requires product
|
|
20
|
+
* `@id` to be an IRI): a `file:` URI with the line in the fragment, e.g.
|
|
21
|
+
* `file:src/a.ts#L3`.
|
|
22
|
+
*/
|
|
23
|
+
function productId(f) {
|
|
24
|
+
return `file:${f.location.file}#L${f.location.line}`;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build an OpenVEX 0.2.0 document from a scan result. One statement per distinct
|
|
28
|
+
* rule id, listing every affected `file:line` product. Output is deterministic
|
|
29
|
+
* (statements sorted by vulnerability name, products sorted and de-duplicated;
|
|
30
|
+
* the `@id` and `timestamp` derive from the result), so re-exporting the same
|
|
31
|
+
* scan yields byte-identical VEX.
|
|
32
|
+
*/
|
|
33
|
+
export function toOpenVex(result, opts = {}) {
|
|
34
|
+
// Group findings by rule id → one VEX statement per rule.
|
|
35
|
+
const byRule = new Map();
|
|
36
|
+
for (const f of result.findings) {
|
|
37
|
+
const list = byRule.get(f.ruleId);
|
|
38
|
+
if (list)
|
|
39
|
+
list.push(f);
|
|
40
|
+
else
|
|
41
|
+
byRule.set(f.ruleId, [f]);
|
|
42
|
+
}
|
|
43
|
+
const statements = [...byRule.entries()]
|
|
44
|
+
.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))
|
|
45
|
+
.map(([ruleId, findings]) => {
|
|
46
|
+
const first = findings[0];
|
|
47
|
+
// De-duplicate + sort the affected products (a rule can fire many times).
|
|
48
|
+
const products = [...new Set(findings.map(productId))].sort().map((id) => ({ "@id": id }));
|
|
49
|
+
// Surface a triage verdict (if any finding for this rule carries one). Findings
|
|
50
|
+
// of the same rule share a rule; the most-exposed verdict is the informative one.
|
|
51
|
+
const triaged = findings
|
|
52
|
+
.filter((f) => f.triage)
|
|
53
|
+
.sort((a, b) => (b.triage?.exposureScore ?? 0) - (a.triage?.exposureScore ?? 0))[0]?.triage;
|
|
54
|
+
const statement = {
|
|
55
|
+
vulnerability: {
|
|
56
|
+
name: `QK-${ruleId}`,
|
|
57
|
+
description: first.message,
|
|
58
|
+
},
|
|
59
|
+
products,
|
|
60
|
+
status: "affected",
|
|
61
|
+
action_statement: first.remediation ?? "Migrate to a NIST PQC standard (FIPS 203/204/205).",
|
|
62
|
+
};
|
|
63
|
+
if (triaged) {
|
|
64
|
+
statement.status_notes =
|
|
65
|
+
`qScan triage — exposure ${triaged.exposureScore}/100, priority ${triaged.priority}: ` +
|
|
66
|
+
triaged.rationale;
|
|
67
|
+
}
|
|
68
|
+
return statement;
|
|
69
|
+
});
|
|
70
|
+
// Deterministic doc id + timestamp so the same scan yields identical VEX. The
|
|
71
|
+
// triage `status_notes` are part of the identity: a triaged and an untriaged
|
|
72
|
+
// export of the same scan are DIFFERENT documents and must not share an @id.
|
|
73
|
+
const digest = createHash("sha256").update(`${result.root}|${result.toolVersion}`, "utf8");
|
|
74
|
+
for (const s of statements) {
|
|
75
|
+
digest.update(`\n${s.vulnerability.name}|${s.products.map((p) => p["@id"]).join(",")}|${s.status_notes ?? ""}`);
|
|
76
|
+
}
|
|
77
|
+
const id = `https://quantakrypto.com/vex/${digest.digest("hex").slice(0, 16)}`;
|
|
78
|
+
return {
|
|
79
|
+
"@context": "https://openvex.dev/ns/v0.2.0",
|
|
80
|
+
"@id": id,
|
|
81
|
+
author: opts.author ?? "qScan",
|
|
82
|
+
timestamp: result.finishedAt,
|
|
83
|
+
version: 1,
|
|
84
|
+
statements,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=vex.js.map
|
package/dist/vex.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vex.js","sourceRoot":"","sources":["../src/vex.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * OpenVEX export — turn a {@link ScanResult} into an OpenVEX 0.2.0 document so\n * the quantum-readiness posture flows into the SAME supply-chain pipeline that\n * already ingests CVE-based VEX (Vulnerability Exploitability eXchange).\n *\n * Reference: OpenVEX spec (https://openvex.dev/, `@context` v0.2.0).\n *\n * Modeling choice (documented, honest): PQC findings have no CVE, so each qScan\n * rule becomes a synthetic vulnerability `QK-<ruleId>`. Every finding is reported\n * `status: \"affected\"` — the classical, Shor-breakable primitive IS present in\n * the product by construction — with the rule's remediation as the VEX\n * `action_statement`. A `--triage` exposure verdict, when present, is surfaced in\n * `status_notes` (score / priority / rationale). qScan never downgrades a finding\n * to `not_affected`: only the operator can attest a mitigation, so that judgment\n * is deliberately left to them (they can post-process this document).\n */\nimport { createHash } from \"node:crypto\";\n\nimport type { Finding, ScanResult } from \"./types.js\";\n\n/** A single OpenVEX statement: one synthetic vulnerability over its affected products. */\nexport interface OpenVexStatement {\n vulnerability: { name: string; description?: string };\n products: { \"@id\": string }[];\n status: \"not_affected\" | \"affected\" | \"fixed\" | \"under_investigation\";\n /** Recommended action for an `affected` product (the rule's remediation). */\n action_statement?: string;\n /** Free-form status detail — carries the `--triage` exposure verdict when present. */\n status_notes?: string;\n}\n\n/** An OpenVEX 0.2.0 document. */\nexport interface OpenVexDocument {\n \"@context\": \"https://openvex.dev/ns/v0.2.0\";\n \"@id\": string;\n author: string;\n timestamp: string;\n version: number;\n statements: OpenVexStatement[];\n}\n\n/** Options for {@link toOpenVex}. */\nexport interface OpenVexOptions {\n /** Document author (VEX issuer). Default: `\"qScan\"`. */\n author?: string;\n}\n\n/**\n * A stable product identifier for a finding as an IRI (OpenVEX requires product\n * `@id` to be an IRI): a `file:` URI with the line in the fragment, e.g.\n * `file:src/a.ts#L3`.\n */\nfunction productId(f: Finding): string {\n return `file:${f.location.file}#L${f.location.line}`;\n}\n\n/**\n * Build an OpenVEX 0.2.0 document from a scan result. One statement per distinct\n * rule id, listing every affected `file:line` product. Output is deterministic\n * (statements sorted by vulnerability name, products sorted and de-duplicated;\n * the `@id` and `timestamp` derive from the result), so re-exporting the same\n * scan yields byte-identical VEX.\n */\nexport function toOpenVex(result: ScanResult, opts: OpenVexOptions = {}): OpenVexDocument {\n // Group findings by rule id → one VEX statement per rule.\n const byRule = new Map<string, Finding[]>();\n for (const f of result.findings) {\n const list = byRule.get(f.ruleId);\n if (list) list.push(f);\n else byRule.set(f.ruleId, [f]);\n }\n\n const statements: OpenVexStatement[] = [...byRule.entries()]\n .sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))\n .map(([ruleId, findings]) => {\n const first = findings[0] as Finding;\n // De-duplicate + sort the affected products (a rule can fire many times).\n const products = [...new Set(findings.map(productId))].sort().map((id) => ({ \"@id\": id }));\n\n // Surface a triage verdict (if any finding for this rule carries one). Findings\n // of the same rule share a rule; the most-exposed verdict is the informative one.\n const triaged = findings\n .filter((f) => f.triage)\n .sort((a, b) => (b.triage?.exposureScore ?? 0) - (a.triage?.exposureScore ?? 0))[0]?.triage;\n\n const statement: OpenVexStatement = {\n vulnerability: {\n name: `QK-${ruleId}`,\n description: first.message,\n },\n products,\n status: \"affected\",\n action_statement: first.remediation ?? \"Migrate to a NIST PQC standard (FIPS 203/204/205).\",\n };\n if (triaged) {\n statement.status_notes =\n `qScan triage — exposure ${triaged.exposureScore}/100, priority ${triaged.priority}: ` +\n triaged.rationale;\n }\n return statement;\n });\n\n // Deterministic doc id + timestamp so the same scan yields identical VEX. The\n // triage `status_notes` are part of the identity: a triaged and an untriaged\n // export of the same scan are DIFFERENT documents and must not share an @id.\n const digest = createHash(\"sha256\").update(`${result.root}|${result.toolVersion}`, \"utf8\");\n for (const s of statements) {\n digest.update(\n `\\n${s.vulnerability.name}|${s.products.map((p) => p[\"@id\"]).join(\",\")}|${s.status_notes ?? \"\"}`,\n );\n }\n const id = `https://quantakrypto.com/vex/${digest.digest(\"hex\").slice(0, 16)}`;\n\n return {\n \"@context\": \"https://openvex.dev/ns/v0.2.0\",\n \"@id\": id,\n author: opts.author ?? \"qScan\",\n timestamp: result.finishedAt,\n version: 1,\n statements,\n };\n}\n"]}
|
package/dist/walk.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
/** Directories ignored by default (can be disabled with noDefaultIgnores). */
|
|
2
|
-
export declare const DEFAULT_IGNORES: readonly string[];
|
|
3
1
|
/** Default maximum file size to read: 2 MiB. */
|
|
4
2
|
export declare const DEFAULT_MAX_FILE_SIZE: number;
|
|
5
3
|
/** Options accepted by {@link walkFiles}. */
|
|
6
|
-
|
|
4
|
+
interface WalkOptions {
|
|
7
5
|
/**
|
|
8
6
|
* Restrict to paths matching one of these include patterns (substring or
|
|
9
7
|
* relative-path-prefix match). When omitted/empty, all files pass.
|
|
@@ -27,6 +25,12 @@ export declare function toPosix(p: string): string;
|
|
|
27
25
|
export declare function matchesAny(rel: string, patterns: readonly string[]): boolean;
|
|
28
26
|
/** True if the file's extension marks it as binary / non-text. */
|
|
29
27
|
export declare function isBinaryPath(rel: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* True if the path is a binary cryptographic key container we scan byte-preserving.
|
|
30
|
+
* Uses a suffix match (not `extname`) so it agrees with the detectors' `hasExtension`
|
|
31
|
+
* even for a bare dotfile literally named e.g. `.gpg` (where `extname` returns "").
|
|
32
|
+
*/
|
|
33
|
+
export declare function isKeystorePath(rel: string): boolean;
|
|
30
34
|
/** True if the path looks like generated / bundled output (by name). */
|
|
31
35
|
export declare function isGeneratedPath(rel: string): boolean;
|
|
32
36
|
/**
|
|
@@ -35,10 +39,41 @@ export declare function isGeneratedPath(rel: string): boolean;
|
|
|
35
39
|
* ~50 KB, in the first ~64 KB sampled. Used at read time, not in the walker.
|
|
36
40
|
*/
|
|
37
41
|
export declare function looksMinified(content: string): boolean;
|
|
42
|
+
/** A scannable file plus the byte size the walker already stat'd for it. */
|
|
43
|
+
export interface WalkedFile {
|
|
44
|
+
/** Relative POSIX path from the walk root. */
|
|
45
|
+
rel: string;
|
|
46
|
+
/** File size in bytes (from the walker's own stat; never re-stat downstream). */
|
|
47
|
+
size: number;
|
|
48
|
+
}
|
|
38
49
|
/**
|
|
39
50
|
* Recursively yield scannable file paths (relative to `root`, POSIX) under a
|
|
40
51
|
* directory. If `root` points at a single file, yields just that file's
|
|
41
|
-
* basename (subject to the size / binary filters).
|
|
52
|
+
* basename (subject to the size / binary filters). Thin wrapper over
|
|
53
|
+
* {@link walkFilesSized} that drops the size (the historical string-yielding API).
|
|
42
54
|
*/
|
|
43
55
|
export declare function walkFiles(root: string, options?: WalkOptions): AsyncGenerator<string>;
|
|
56
|
+
/**
|
|
57
|
+
* Like {@link walkFiles} but yields each file WITH the byte size the walker
|
|
58
|
+
* already obtained while applying the size limit. Callers that need sizes (the
|
|
59
|
+
* parallel scanner's byte-balanced chunking) consume this directly so they do
|
|
60
|
+
* not stat every file a second time (P2 double-stat elimination).
|
|
61
|
+
*/
|
|
62
|
+
export declare function walkFilesSized(root: string, options?: WalkOptions): AsyncGenerator<WalkedFile>;
|
|
63
|
+
/**
|
|
64
|
+
* Manifests bypass the normal file-size cap (they carry the whole dependency
|
|
65
|
+
* tree and must not be dropped), but still get a generous hard ceiling so a
|
|
66
|
+
* pathological or hostile lockfile can't be read unbounded and OOM the scan.
|
|
67
|
+
* 16 MiB comfortably covers real monorepo lockfiles (npm's own is well under 5).
|
|
68
|
+
*/
|
|
69
|
+
export declare const MANIFEST_MAX_BYTES: number;
|
|
70
|
+
/**
|
|
71
|
+
* True if a file passes the size limit. Dependency manifests (package.json /
|
|
72
|
+
* package-lock.json / yarn.lock / …) get the larger {@link MANIFEST_MAX_BYTES}
|
|
73
|
+
* ceiling instead of the ordinary cap, so large lockfiles still get scanned for
|
|
74
|
+
* vulnerable dependencies without letting an enormous one exhaust memory.
|
|
75
|
+
* Exported for unit testing.
|
|
76
|
+
*/
|
|
77
|
+
export declare function passesSizeLimit(rel: string, size: number, maxFileSize: number): boolean;
|
|
78
|
+
export {};
|
|
44
79
|
//# sourceMappingURL=walk.d.ts.map
|
package/dist/walk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"AA0BA,gDAAgD;AAChD,eAAO,MAAM,qBAAqB,QAAkB,CAAC;AAyErD,6CAA6C;AAC7C,UAAU,WAAW;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,0DAA0D;AAC1D,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AA6DD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAc5E;AAgBD,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMjD;AAsBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAInD;AASD,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAmBtD;AAED,4EAA4E;AAC5E,MAAM,WAAW,UAAU;IACzB,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAuB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,cAAc,CAAC,MAAM,CAAC,CAEhG;AAED;;;;;GAKG;AACH,wBAAuB,cAAc,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,cAAc,CAAC,UAAU,CAAC,CAsB5B;AASD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAmB,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAIvF"}
|