@quantakrypto/core 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-types.d.ts +48 -0
- package/dist/agent-types.d.ts.map +1 -0
- package/dist/agent-types.js +2 -0
- package/dist/agent-types.js.map +1 -0
- package/dist/cache.d.ts +27 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +93 -0
- package/dist/cache.js.map +1 -0
- package/dist/cbom.d.ts.map +1 -1
- package/dist/cbom.js +26 -1
- package/dist/cbom.js.map +1 -1
- package/dist/changed.d.ts.map +1 -1
- package/dist/changed.js +14 -2
- package/dist/changed.js.map +1 -1
- package/dist/codemods/config-toggle.d.ts +3 -0
- package/dist/codemods/config-toggle.d.ts.map +1 -0
- package/dist/codemods/config-toggle.js +26 -0
- package/dist/codemods/config-toggle.js.map +1 -0
- package/dist/codemods/registry.d.ts +26 -0
- package/dist/codemods/registry.d.ts.map +1 -0
- package/dist/codemods/registry.js +8 -0
- package/dist/codemods/registry.js.map +1 -0
- package/dist/comments.d.ts +45 -0
- package/dist/comments.d.ts.map +1 -0
- package/dist/comments.js +164 -0
- package/dist/comments.js.map +1 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/dependencies.d.ts +31 -13
- package/dist/dependencies.d.ts.map +1 -1
- package/dist/dependencies.js +460 -40
- package/dist/dependencies.js.map +1 -1
- package/dist/detect-utils.d.ts +44 -1
- package/dist/detect-utils.d.ts.map +1 -1
- package/dist/detect-utils.js +113 -17
- package/dist/detect-utils.js.map +1 -1
- package/dist/detectors/c.d.ts +20 -0
- package/dist/detectors/c.d.ts.map +1 -0
- package/dist/detectors/c.js +104 -0
- package/dist/detectors/c.js.map +1 -0
- package/dist/detectors/csharp.d.ts +15 -0
- package/dist/detectors/csharp.d.ts.map +1 -0
- package/dist/detectors/csharp.js +76 -0
- package/dist/detectors/csharp.js.map +1 -0
- package/dist/detectors/go.d.ts +25 -0
- package/dist/detectors/go.d.ts.map +1 -0
- package/dist/detectors/go.js +132 -0
- package/dist/detectors/go.js.map +1 -0
- package/dist/detectors/java.d.ts +25 -0
- package/dist/detectors/java.d.ts.map +1 -0
- package/dist/detectors/java.js +200 -0
- package/dist/detectors/java.js.map +1 -0
- package/dist/detectors/python.d.ts +26 -0
- package/dist/detectors/python.d.ts.map +1 -0
- package/dist/detectors/python.js +171 -0
- package/dist/detectors/python.js.map +1 -0
- package/dist/detectors/ruby.d.ts +15 -0
- package/dist/detectors/ruby.d.ts.map +1 -0
- package/dist/detectors/ruby.js +75 -0
- package/dist/detectors/ruby.js.map +1 -0
- package/dist/detectors/rust.d.ts +13 -0
- package/dist/detectors/rust.d.ts.map +1 -0
- package/dist/detectors/rust.js +94 -0
- package/dist/detectors/rust.js.map +1 -0
- package/dist/detectors/source.d.ts.map +1 -1
- package/dist/detectors/source.js +70 -22
- package/dist/detectors/source.js.map +1 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/parallel.d.ts +4 -0
- package/dist/parallel.d.ts.map +1 -1
- package/dist/parallel.js +59 -8
- package/dist/parallel.js.map +1 -1
- package/dist/patch-policy.d.ts +22 -0
- package/dist/patch-policy.d.ts.map +1 -0
- package/dist/patch-policy.js +21 -0
- package/dist/patch-policy.js.map +1 -0
- package/dist/redact.d.ts +19 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +77 -0
- package/dist/redact.js.map +1 -0
- package/dist/registry.d.ts +13 -3
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +31 -4
- package/dist/registry.js.map +1 -1
- package/dist/remediate-pipeline.d.ts +41 -0
- package/dist/remediate-pipeline.d.ts.map +1 -0
- package/dist/remediate-pipeline.js +38 -0
- package/dist/remediate-pipeline.js.map +1 -0
- package/dist/remediate-request.d.ts +21 -0
- package/dist/remediate-request.d.ts.map +1 -0
- package/dist/remediate-request.js +28 -0
- package/dist/remediate-request.js.map +1 -0
- package/dist/remediation.d.ts +10 -0
- package/dist/remediation.d.ts.map +1 -1
- package/dist/remediation.js +21 -8
- package/dist/remediation.js.map +1 -1
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +16 -1
- package/dist/report.js.map +1 -1
- package/dist/scan-worker.js +6 -2
- package/dist/scan-worker.js.map +1 -1
- package/dist/scan.d.ts +5 -4
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +52 -29
- package/dist/scan.js.map +1 -1
- package/dist/triage.d.ts +27 -0
- package/dist/triage.d.ts.map +1 -0
- package/dist/triage.js +33 -0
- package/dist/triage.js.map +1 -0
- package/dist/types.d.ts +53 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/verify.d.ts +30 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +65 -0
- package/dist/verify.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/walk.d.ts +7 -0
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +85 -11
- package/dist/walk.js.map +1 -1
- package/dist/worktree.d.ts +6 -0
- package/dist/worktree.d.ts.map +1 -0
- package/dist/worktree.js +43 -0
- package/dist/worktree.js.map +1 -0
- package/package.json +1 -1
- package/src/agent-types.ts +52 -0
- package/src/cache.ts +120 -0
- package/src/cbom.ts +27 -1
- package/src/changed.ts +13 -4
- package/src/codemods/config-toggle.ts +35 -0
- package/src/codemods/registry.ts +31 -0
- package/src/comments.ts +180 -0
- package/src/config.ts +8 -0
- package/src/dependencies.ts +483 -51
- package/src/detect-utils.ts +123 -15
- package/src/detectors/c.ts +132 -0
- package/src/detectors/csharp.ts +98 -0
- package/src/detectors/go.ts +167 -0
- package/src/detectors/java.ts +235 -0
- package/src/detectors/python.ts +212 -0
- package/src/detectors/ruby.ts +97 -0
- package/src/detectors/rust.ts +112 -0
- package/src/detectors/source.ts +69 -21
- package/src/index.ts +45 -1
- package/src/parallel.ts +63 -6
- package/src/patch-policy.ts +42 -0
- package/src/redact.ts +92 -0
- package/src/registry.ts +32 -4
- package/src/remediate-pipeline.ts +81 -0
- package/src/remediate-request.ts +52 -0
- package/src/remediation.ts +27 -11
- package/src/report.ts +27 -1
- package/src/scan-worker.ts +6 -2
- package/src/scan.ts +62 -31
- package/src/triage.ts +58 -0
- package/src/types.ts +66 -3
- package/src/verify.ts +82 -0
- package/src/version.ts +1 -1
- package/src/walk.ts +81 -12
- package/src/worktree.ts +45 -0
package/dist/verify.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snippet-level fix verification: run the detectors over a piece of code (NOT
|
|
3
|
+
* the filesystem) and report any classical crypto that remains. This is the
|
|
4
|
+
* deterministic gate a fix must pass — the same logic the MCP `verify_fix` tool
|
|
5
|
+
* and the remediation pipeline both use, so they can never disagree on what
|
|
6
|
+
* "the finding is gone" means.
|
|
7
|
+
*/
|
|
8
|
+
import type { Finding } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Map a language name (or a bare extension) to a source extension whose
|
|
11
|
+
* detectors we run. Returns null for languages the scanner does not analyze.
|
|
12
|
+
*/
|
|
13
|
+
export declare function languageToExtension(language: string): string | null;
|
|
14
|
+
/** Result of {@link verifyFix}: the findings that remain, and whether the
|
|
15
|
+
* language is one the scanner actually analyzes (so `findings: []` on an
|
|
16
|
+
* unsupported language is NOT a clean verification). */
|
|
17
|
+
export interface VerifyResult {
|
|
18
|
+
supported: boolean;
|
|
19
|
+
findings: Finding[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Run all detectors over `code`, selecting them by `filename` (extension) or
|
|
23
|
+
* `language`. Pure: no I/O. When neither identifies an analyzable language,
|
|
24
|
+
* `supported` is false and the empty findings list must not be read as "fixed".
|
|
25
|
+
*/
|
|
26
|
+
export declare function verifyFix(code: string, opts: {
|
|
27
|
+
filename?: string;
|
|
28
|
+
language?: string;
|
|
29
|
+
}): VerifyResult;
|
|
30
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCnE;AAED;;wDAEwD;AACxD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C,YAAY,CAed"}
|
package/dist/verify.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { detectFile, detectors } from "./scan.js";
|
|
2
|
+
/**
|
|
3
|
+
* Map a language name (or a bare extension) to a source extension whose
|
|
4
|
+
* detectors we run. Returns null for languages the scanner does not analyze.
|
|
5
|
+
*/
|
|
6
|
+
export function languageToExtension(language) {
|
|
7
|
+
const l = language.trim().toLowerCase().replace(/^\./, "");
|
|
8
|
+
const map = {
|
|
9
|
+
js: ".js",
|
|
10
|
+
javascript: ".js",
|
|
11
|
+
jsx: ".jsx",
|
|
12
|
+
ts: ".ts",
|
|
13
|
+
typescript: ".ts",
|
|
14
|
+
tsx: ".tsx",
|
|
15
|
+
mjs: ".mjs",
|
|
16
|
+
cjs: ".cjs",
|
|
17
|
+
py: ".py",
|
|
18
|
+
python: ".py",
|
|
19
|
+
go: ".go",
|
|
20
|
+
golang: ".go",
|
|
21
|
+
java: ".java",
|
|
22
|
+
kotlin: ".kt",
|
|
23
|
+
kt: ".kt",
|
|
24
|
+
cs: ".cs",
|
|
25
|
+
csharp: ".cs",
|
|
26
|
+
"c#": ".cs",
|
|
27
|
+
dotnet: ".cs",
|
|
28
|
+
rs: ".rs",
|
|
29
|
+
rust: ".rs",
|
|
30
|
+
rb: ".rb",
|
|
31
|
+
ruby: ".rb",
|
|
32
|
+
c: ".c",
|
|
33
|
+
"c++": ".cpp",
|
|
34
|
+
cpp: ".cpp",
|
|
35
|
+
cc: ".cc",
|
|
36
|
+
h: ".h",
|
|
37
|
+
hpp: ".hpp",
|
|
38
|
+
};
|
|
39
|
+
return map[l] ?? null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Run all detectors over `code`, selecting them by `filename` (extension) or
|
|
43
|
+
* `language`. Pure: no I/O. When neither identifies an analyzable language,
|
|
44
|
+
* `supported` is false and the empty findings list must not be read as "fixed".
|
|
45
|
+
*/
|
|
46
|
+
export function verifyFix(code, opts) {
|
|
47
|
+
let name;
|
|
48
|
+
if (opts.filename && opts.filename.trim()) {
|
|
49
|
+
name = opts.filename.trim();
|
|
50
|
+
}
|
|
51
|
+
else if (opts.language && opts.language.trim()) {
|
|
52
|
+
const ext = languageToExtension(opts.language);
|
|
53
|
+
if (!ext)
|
|
54
|
+
return { supported: false, findings: [] };
|
|
55
|
+
name = `snippet${ext}`;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
return { supported: false, findings: [] };
|
|
59
|
+
}
|
|
60
|
+
const dotExt = name.replace(/^.*(\.[^.]+)$/, "$1");
|
|
61
|
+
const supported = languageToExtension(dotExt) !== null;
|
|
62
|
+
const findings = detectFile(name, code, detectors, { source: true, config: true, deps: true });
|
|
63
|
+
return { supported, findings };
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAElD;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3D,MAAM,GAAG,GAA2B;QAClC,EAAE,EAAE,KAAK;QACT,UAAU,EAAE,KAAK;QACjB,GAAG,EAAE,MAAM;QACX,EAAE,EAAE,KAAK;QACT,UAAU,EAAE,KAAK;QACjB,GAAG,EAAE,MAAM;QACX,GAAG,EAAE,MAAM;QACX,GAAG,EAAE,MAAM;QACX,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,KAAK;QACb,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,KAAK;QACb,EAAE,EAAE,KAAK;QACT,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,KAAK;QACX,MAAM,EAAE,KAAK;QACb,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,KAAK;QACX,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,KAAK;QACX,CAAC,EAAE,IAAI;QACP,KAAK,EAAE,MAAM;QACb,GAAG,EAAE,MAAM;QACX,EAAE,EAAE,KAAK;QACT,CAAC,EAAE,IAAI;QACP,GAAG,EAAE,MAAM;KACZ,CAAC;IACF,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACxB,CAAC;AAUD;;;;GAIG;AACH,MAAM,UAAU,SAAS,CACvB,IAAY,EACZ,IAA8C;IAE9C,IAAI,IAAY,CAAC;IACjB,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1C,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC9B,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;QACjD,MAAM,GAAG,GAAG,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACpD,IAAI,GAAG,UAAU,GAAG,EAAE,CAAC;IACzB,CAAC;SAAM,CAAC;QACN,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC5C,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,mBAAmB,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IACvD,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/F,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AACjC,CAAC"}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/walk.d.ts
CHANGED
|
@@ -18,6 +18,13 @@ export interface WalkOptions {
|
|
|
18
18
|
}
|
|
19
19
|
/** Normalise a path to forward-slash POSIX separators. */
|
|
20
20
|
export declare function toPosix(p: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* True if `rel` (a POSIX relative path) matches any pattern. A pattern with a
|
|
23
|
+
* glob metacharacter (`*`, `?`, `[`) is matched as an anchored glob; a plain
|
|
24
|
+
* pattern keeps the historical substring / path-prefix semantics (so `"src"`
|
|
25
|
+
* still matches `src/a.ts` and `"secrets"` matches anywhere).
|
|
26
|
+
*/
|
|
27
|
+
export declare function matchesAny(rel: string, patterns: readonly string[]): boolean;
|
|
21
28
|
/** True if the file's extension marks it as binary / non-text. */
|
|
22
29
|
export declare function isBinaryPath(rel: string): boolean;
|
|
23
30
|
/** True if the path looks like generated / bundled output (by name). */
|
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":"AAYA,8EAA8E;AAC9E,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAW5C,CAAC;AAEF,gDAAgD;AAChD,eAAO,MAAM,qBAAqB,QAAkB,CAAC;AAyErD,6CAA6C;AAC7C,MAAM,WAAW,WAAW;IAC1B;;;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;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;;;;GAIG;AACH,wBAAuB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,cAAc,CAAC,MAAM,CAAC,CAsBhG"}
|
package/dist/walk.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { readdir, stat } from "node:fs/promises";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
+
import { isManifestFile } from "./dependencies.js";
|
|
9
10
|
/** Directories ignored by default (can be disabled with noDefaultIgnores). */
|
|
10
11
|
export const DEFAULT_IGNORES = [
|
|
11
12
|
"node_modules",
|
|
@@ -95,13 +96,86 @@ const BINARY_EXTENSIONS = new Set([
|
|
|
95
96
|
export function toPosix(p) {
|
|
96
97
|
return p.split(path.sep).join("/");
|
|
97
98
|
}
|
|
98
|
-
/**
|
|
99
|
-
function
|
|
99
|
+
/** A pattern is treated as a glob when it contains one of these metacharacters. */
|
|
100
|
+
function hasGlobMeta(pattern) {
|
|
101
|
+
return /[*?[]/.test(pattern);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Translate a glob into an anchored RegExp: `*` matches within a path segment
|
|
105
|
+
* (not `/`), `**` matches across segments, a leading `**` before a slash is an
|
|
106
|
+
* optional path prefix, `?` matches a single non-`/` char, `[...]` is a
|
|
107
|
+
* character class. Other regex
|
|
108
|
+
* metacharacters are escaped.
|
|
109
|
+
*/
|
|
110
|
+
function globToRegExp(glob) {
|
|
111
|
+
let re = "";
|
|
112
|
+
for (let i = 0; i < glob.length; i++) {
|
|
113
|
+
const c = glob[i];
|
|
114
|
+
if (c === "*") {
|
|
115
|
+
if (glob[i + 1] === "*") {
|
|
116
|
+
i++; // consume the second '*'
|
|
117
|
+
if (glob[i + 1] === "/") {
|
|
118
|
+
i++; // consume the trailing '/'
|
|
119
|
+
re += "(?:.*/)?"; // zero or more path segments
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
re += ".*"; // '**' spanning segments
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
re += "[^/]*"; // '*' within a segment
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else if (c === "?") {
|
|
130
|
+
re += "[^/]";
|
|
131
|
+
}
|
|
132
|
+
else if (c === "[") {
|
|
133
|
+
// Pass a character class through; find its closing ']'.
|
|
134
|
+
const end = glob.indexOf("]", i + 1);
|
|
135
|
+
if (end === -1) {
|
|
136
|
+
re += "\\[";
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
re += glob.slice(i, end + 1);
|
|
140
|
+
i = end;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else if ("\\^$.|+(){}".includes(c)) {
|
|
144
|
+
re += "\\" + c;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
re += c;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return new RegExp(`^${re}$`);
|
|
151
|
+
}
|
|
152
|
+
/** Memoized glob→RegExp so a pattern is compiled once, not once per file. */
|
|
153
|
+
const GLOB_CACHE = new Map();
|
|
154
|
+
function globRegExp(pattern) {
|
|
155
|
+
let re = GLOB_CACHE.get(pattern);
|
|
156
|
+
if (!re) {
|
|
157
|
+
re = globToRegExp(pattern);
|
|
158
|
+
GLOB_CACHE.set(pattern, re);
|
|
159
|
+
}
|
|
160
|
+
return re;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* True if `rel` (a POSIX relative path) matches any pattern. A pattern with a
|
|
164
|
+
* glob metacharacter (`*`, `?`, `[`) is matched as an anchored glob; a plain
|
|
165
|
+
* pattern keeps the historical substring / path-prefix semantics (so `"src"`
|
|
166
|
+
* still matches `src/a.ts` and `"secrets"` matches anywhere).
|
|
167
|
+
*/
|
|
168
|
+
export function matchesAny(rel, patterns) {
|
|
100
169
|
for (const pattern of patterns) {
|
|
101
170
|
if (!pattern)
|
|
102
171
|
continue;
|
|
103
172
|
const p = toPosix(pattern).replace(/\/+$/, "");
|
|
104
|
-
|
|
173
|
+
if (hasGlobMeta(p)) {
|
|
174
|
+
if (globRegExp(p).test(rel))
|
|
175
|
+
return true;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
// Plain pattern: substring match (handles "src/legacy" or "secrets")...
|
|
105
179
|
if (rel.includes(p))
|
|
106
180
|
return true;
|
|
107
181
|
// ...and explicit path-prefix match ("foo" should match "foo/bar.ts").
|
|
@@ -200,15 +274,12 @@ export async function* walkFiles(root, options = {}) {
|
|
|
200
274
|
* scanned for vulnerable dependencies instead of being silently dropped.
|
|
201
275
|
*/
|
|
202
276
|
function passesSizeLimit(rel, size, maxFileSize) {
|
|
203
|
-
|
|
277
|
+
// Dependency manifests are always read (they can exceed the size cap but carry
|
|
278
|
+
// the whole dependency tree). Uses the single {@link isManifestFile} definition.
|
|
279
|
+
if (isManifestFile(rel))
|
|
204
280
|
return true;
|
|
205
281
|
return size <= maxFileSize;
|
|
206
282
|
}
|
|
207
|
-
/** True if the path's basename is a dependency manifest we always read. */
|
|
208
|
-
function isManifestPath(rel) {
|
|
209
|
-
const base = rel.split("/").pop() ?? rel;
|
|
210
|
-
return base === "package.json" || base === "package-lock.json";
|
|
211
|
-
}
|
|
212
283
|
/** Internal recursive directory walker. `relDir` is POSIX-relative to the root. */
|
|
213
284
|
async function* walkDir(absDir, relDir, ctx) {
|
|
214
285
|
let entries;
|
|
@@ -242,9 +313,12 @@ async function* walkDir(absDir, relDir, ctx) {
|
|
|
242
313
|
continue;
|
|
243
314
|
if (!isIncluded(rel, ctx.include))
|
|
244
315
|
continue;
|
|
245
|
-
|
|
316
|
+
// Dependency manifests (incl. yarn.lock / pnpm-lock.yaml) are always read —
|
|
317
|
+
// they carry the dependency tree and must not be dropped as binary/generated.
|
|
318
|
+
const manifest = isManifestFile(rel);
|
|
319
|
+
if (!manifest && isBinaryPath(rel))
|
|
246
320
|
continue;
|
|
247
|
-
if (isGeneratedPath(rel))
|
|
321
|
+
if (!manifest && isGeneratedPath(rel))
|
|
248
322
|
continue;
|
|
249
323
|
try {
|
|
250
324
|
const s = await stat(abs);
|
package/dist/walk.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"walk.js","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,8EAA8E;AAC9E,MAAM,CAAC,MAAM,eAAe,GAAsB;IAChD,cAAc;IACd,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,KAAK;IACL,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,QAAQ;CACT,CAAC;AAEF,gDAAgD;AAChD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAErD;;;GAGG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAS;IACxC,SAAS;IACT,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,MAAM;IACN,MAAM;IACN,MAAM;IACN,wBAAwB;IACxB,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,QAAQ;IACR,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,uBAAuB;IACvB,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,KAAK;IACL,QAAQ;IACR,MAAM;IACN,IAAI;IACJ,IAAI;IACJ,QAAQ;IACR,OAAO;IACP,kBAAkB;IAClB,KAAK;IACL,SAAS;IACT,UAAU;IACV,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,SAAS;IACT,OAAO;CACR,CAAC,CAAC;AAiBH,0DAA0D;AAC1D,MAAM,UAAU,OAAO,CAAC,CAAS;IAC/B,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACrC,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"walk.js","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a detached worktree of `repoRoot` at HEAD, run `fn` with its path, and
|
|
3
|
+
* always tear it down. Throws if `repoRoot` is not a git repository.
|
|
4
|
+
*/
|
|
5
|
+
export declare function withWorktree<T>(repoRoot: string, fn: (dir: string) => Promise<T>): Promise<T>;
|
|
6
|
+
//# sourceMappingURL=worktree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../src/worktree.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,CAAC,CAAC,CAmBZ"}
|
package/dist/worktree.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ephemeral git worktree runner. Remediation applies candidate patches inside a
|
|
3
|
+
* throwaway `git worktree` checked out at HEAD, so the user's working tree is
|
|
4
|
+
* never touched while patches are being tried and verified. The worktree is
|
|
5
|
+
* always removed afterwards, even if the callback throws.
|
|
6
|
+
*/
|
|
7
|
+
import { execFile } from "node:child_process";
|
|
8
|
+
import { promisify } from "node:util";
|
|
9
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
10
|
+
import { tmpdir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
const exec = promisify(execFile);
|
|
13
|
+
async function git(args, cwd) {
|
|
14
|
+
await exec("git", args, { cwd });
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a detached worktree of `repoRoot` at HEAD, run `fn` with its path, and
|
|
18
|
+
* always tear it down. Throws if `repoRoot` is not a git repository.
|
|
19
|
+
*/
|
|
20
|
+
export async function withWorktree(repoRoot, fn) {
|
|
21
|
+
try {
|
|
22
|
+
await git(["rev-parse", "--is-inside-work-tree"], repoRoot);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
throw new Error(`withWorktree: "${repoRoot}" is not a git repository`);
|
|
26
|
+
}
|
|
27
|
+
const base = await mkdtemp(join(tmpdir(), "quantakrypto-wt-"));
|
|
28
|
+
const dir = join(base, "wt");
|
|
29
|
+
await git(["worktree", "add", "--detach", dir], repoRoot);
|
|
30
|
+
try {
|
|
31
|
+
return await fn(dir);
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
try {
|
|
35
|
+
await git(["worktree", "remove", "--force", dir], repoRoot);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// best effort — the temp dir removal below still reclaims the disk.
|
|
39
|
+
}
|
|
40
|
+
await rm(base, { recursive: true, force: true });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=worktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../src/worktree.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAEjC,KAAK,UAAU,GAAG,CAAC,IAAc,EAAE,GAAY;IAC7C,MAAM,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAgB,EAChB,EAA+B;IAE/B,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,CAAC,WAAW,EAAE,uBAAuB,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,2BAA2B,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7B,MAAM,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC9D,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;QACtE,CAAC;QACD,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quantakrypto/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Shared post-quantum readiness library: crypto detectors, vulnerable-dependency database, inventory + SARIF reporting. Zero runtime dependencies.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Dandelion Labs <hello@dandelionlabs.io> (https://dandelionlabs.io)",
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the agent (BYOK) plane. These live in `@quantakrypto/core`
|
|
3
|
+
* (offline) so both the deterministic MCP tools and the networked
|
|
4
|
+
* `@quantakrypto/agent` package speak the same shapes without the offline side
|
|
5
|
+
* ever importing the network client.
|
|
6
|
+
*/
|
|
7
|
+
import type { Severity, TriageAnnotation } from "./types.js";
|
|
8
|
+
|
|
9
|
+
/** How much source context a redacted request carries. */
|
|
10
|
+
export type ContextLevel = "metadata" | "snippet" | "function" | "file";
|
|
11
|
+
|
|
12
|
+
/** A finding's context, redacted to a {@link ContextLevel} and secret-stripped. */
|
|
13
|
+
export interface RedactedContext {
|
|
14
|
+
level: ContextLevel;
|
|
15
|
+
meta: {
|
|
16
|
+
ruleId: string;
|
|
17
|
+
algorithm?: string;
|
|
18
|
+
severity: Severity;
|
|
19
|
+
hndl: boolean;
|
|
20
|
+
file: string;
|
|
21
|
+
line: number;
|
|
22
|
+
message: string;
|
|
23
|
+
};
|
|
24
|
+
/** Redacted source, or null at `metadata` level / for a `sensitive` finding. */
|
|
25
|
+
code: string | null;
|
|
26
|
+
/** True when key material was stripped from the context. */
|
|
27
|
+
redactedSecret: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** An LLM triage verdict for a single finding (never suppresses it). The
|
|
31
|
+
* exposure/priority/rationale body is the {@link TriageAnnotation} that gets
|
|
32
|
+
* attached to the finding; `fingerprint` links it back to that finding. */
|
|
33
|
+
export interface TriageVerdict extends TriageAnnotation {
|
|
34
|
+
fingerprint: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** A concrete proposed edit: the full new content for a single file. */
|
|
38
|
+
export interface Patch {
|
|
39
|
+
path: string;
|
|
40
|
+
/** Full replacement content for `path` after the fix. */
|
|
41
|
+
newContent: string;
|
|
42
|
+
ruleId: string;
|
|
43
|
+
source: "codemod" | "llm";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** An LLM-proposed fix before it enters the deterministic pipeline. */
|
|
47
|
+
export interface FixProposal {
|
|
48
|
+
fingerprint: string;
|
|
49
|
+
path: string;
|
|
50
|
+
newContent: string;
|
|
51
|
+
explanation: string;
|
|
52
|
+
}
|
package/src/cache.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional on-disk scan cache. Keyed by file content hash so an unchanged file
|
|
3
|
+
* reuses its previous findings instead of re-running every detector — the big
|
|
4
|
+
* win on large monorepos where most files don't change between runs.
|
|
5
|
+
*
|
|
6
|
+
* Invalidation is conservative and whole-cache: the cache stores a RULESET
|
|
7
|
+
* FINGERPRINT (tool version + the active detector ids + disabled rules). If any
|
|
8
|
+
* of those differ from the current run, the entire cache is discarded and
|
|
9
|
+
* rebuilt, so upgrading the tool or changing the rules never serves stale
|
|
10
|
+
* results. Per file, a content-hash mismatch re-scans just that file.
|
|
11
|
+
*
|
|
12
|
+
* The cache is opt-in (`ScanOptions.cacheFile`); with no cache file, scans are
|
|
13
|
+
* exactly as before. A corrupt / unreadable / wrong-version cache file is
|
|
14
|
+
* ignored (treated as empty), never fatal.
|
|
15
|
+
*/
|
|
16
|
+
import { createHash } from "node:crypto";
|
|
17
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
18
|
+
import * as path from "node:path";
|
|
19
|
+
|
|
20
|
+
import type { Detector, Finding } from "./types.js";
|
|
21
|
+
import { VERSION } from "./version.js";
|
|
22
|
+
|
|
23
|
+
const CACHE_VERSION = 1;
|
|
24
|
+
|
|
25
|
+
/** One cached file: the content hash it was computed for, and its findings. */
|
|
26
|
+
export interface CacheEntry {
|
|
27
|
+
hash: string;
|
|
28
|
+
findings: Finding[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface CacheFileShape {
|
|
32
|
+
version: number;
|
|
33
|
+
ruleset: string;
|
|
34
|
+
entries: Record<string, CacheEntry>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** sha256 of a file's content (hex). */
|
|
38
|
+
export function hashContent(content: string): string {
|
|
39
|
+
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Fingerprint of everything that changes what a scan produces: the tool version,
|
|
44
|
+
* the active detector ids (sorted), and the disabled-rule set (sorted). A change
|
|
45
|
+
* to any of these invalidates the whole cache.
|
|
46
|
+
*/
|
|
47
|
+
export function rulesetFingerprint(
|
|
48
|
+
detectors: readonly Detector[],
|
|
49
|
+
disabledRules: readonly string[] | undefined,
|
|
50
|
+
): string {
|
|
51
|
+
const ids = detectors.map((d) => d.id).sort();
|
|
52
|
+
const disabled = [...(disabledRules ?? [])].sort();
|
|
53
|
+
return `v${VERSION}|d:${ids.join(",")}|x:${disabled.join(",")}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Load the cache file into a `Map<relPath, CacheEntry>`. Returns an empty map
|
|
58
|
+
* when the file is missing, unparseable, the wrong version, or was written for a
|
|
59
|
+
* different ruleset (in which case its entries are stale and must not be reused).
|
|
60
|
+
*/
|
|
61
|
+
export async function loadCache(
|
|
62
|
+
cacheFile: string,
|
|
63
|
+
ruleset: string,
|
|
64
|
+
): Promise<Map<string, CacheEntry>> {
|
|
65
|
+
let raw: string;
|
|
66
|
+
try {
|
|
67
|
+
raw = await readFile(cacheFile, "utf8");
|
|
68
|
+
} catch {
|
|
69
|
+
return new Map();
|
|
70
|
+
}
|
|
71
|
+
let parsed: CacheFileShape;
|
|
72
|
+
try {
|
|
73
|
+
parsed = JSON.parse(raw) as CacheFileShape;
|
|
74
|
+
} catch {
|
|
75
|
+
return new Map();
|
|
76
|
+
}
|
|
77
|
+
if (
|
|
78
|
+
parsed === null ||
|
|
79
|
+
typeof parsed !== "object" ||
|
|
80
|
+
parsed.version !== CACHE_VERSION ||
|
|
81
|
+
parsed.ruleset !== ruleset ||
|
|
82
|
+
typeof parsed.entries !== "object" ||
|
|
83
|
+
parsed.entries === null
|
|
84
|
+
) {
|
|
85
|
+
return new Map();
|
|
86
|
+
}
|
|
87
|
+
const map = new Map<string, CacheEntry>();
|
|
88
|
+
for (const [file, entry] of Object.entries(parsed.entries)) {
|
|
89
|
+
if (entry && typeof entry.hash === "string" && Array.isArray(entry.findings)) {
|
|
90
|
+
map.set(file, entry);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return map;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Write the cache atomically (temp file + rename) so a concurrent reader never
|
|
98
|
+
* sees a half-written file. Errors are swallowed — a cache is an optimization,
|
|
99
|
+
* never a reason to fail a scan.
|
|
100
|
+
*/
|
|
101
|
+
export async function saveCache(
|
|
102
|
+
cacheFile: string,
|
|
103
|
+
ruleset: string,
|
|
104
|
+
entries: Map<string, CacheEntry>,
|
|
105
|
+
): Promise<void> {
|
|
106
|
+
const doc: CacheFileShape = {
|
|
107
|
+
version: CACHE_VERSION,
|
|
108
|
+
ruleset,
|
|
109
|
+
entries: Object.fromEntries(entries),
|
|
110
|
+
};
|
|
111
|
+
try {
|
|
112
|
+
await mkdir(path.dirname(cacheFile), { recursive: true });
|
|
113
|
+
const tmp = `${cacheFile}.tmp-${process.pid}`;
|
|
114
|
+
await writeFile(tmp, JSON.stringify(doc), "utf8");
|
|
115
|
+
const { rename } = await import("node:fs/promises");
|
|
116
|
+
await rename(tmp, cacheFile);
|
|
117
|
+
} catch {
|
|
118
|
+
// best effort
|
|
119
|
+
}
|
|
120
|
+
}
|
package/src/cbom.ts
CHANGED
|
@@ -56,6 +56,32 @@ function isQuantumVulnerable(algorithm: AlgorithmFamily): boolean {
|
|
|
56
56
|
return algorithm !== "unknown";
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Approximate CLASSICAL security strength (bits) of the common parameterisation
|
|
61
|
+
* of a classical family — RSA-2048 / DH-2048 ≈ 112-bit, 256-bit curves ≈ 128-bit,
|
|
62
|
+
* X448 ≈ 224-bit. (The QUANTUM level is 0 for all of these: Shor breaks them.)
|
|
63
|
+
* 0 when the family is unknown. Reported so a CBOM doesn't imply these primitives
|
|
64
|
+
* have zero classical strength today.
|
|
65
|
+
*/
|
|
66
|
+
function classicalSecurityLevelFor(algorithm: AlgorithmFamily): number {
|
|
67
|
+
switch (algorithm) {
|
|
68
|
+
case "RSA":
|
|
69
|
+
case "DH":
|
|
70
|
+
case "DSA":
|
|
71
|
+
return 112;
|
|
72
|
+
case "ECDH":
|
|
73
|
+
case "ECDSA":
|
|
74
|
+
case "EdDSA":
|
|
75
|
+
case "X25519":
|
|
76
|
+
case "ECIES":
|
|
77
|
+
return 128;
|
|
78
|
+
case "X448":
|
|
79
|
+
return 224;
|
|
80
|
+
default:
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
59
85
|
/** Deterministic bom-ref for a (algorithm, primitive) asset key. */
|
|
60
86
|
function bomRef(key: string): string {
|
|
61
87
|
return `crypto:${createHash("sha256").update(key, "utf8").digest("hex").slice(0, 16)}`;
|
|
@@ -107,7 +133,7 @@ export function toCbom(result: ScanResult): CycloneDxBom {
|
|
|
107
133
|
primitive: g.primitive,
|
|
108
134
|
parameterSetIdentifier: g.algorithm,
|
|
109
135
|
executionEnvironment: "software-plain-ram",
|
|
110
|
-
classicalSecurityLevel:
|
|
136
|
+
classicalSecurityLevel: classicalSecurityLevelFor(g.algorithm),
|
|
111
137
|
nistQuantumSecurityLevel: 0,
|
|
112
138
|
cryptoFunctions:
|
|
113
139
|
g.primitive === "signature"
|
package/src/changed.ts
CHANGED
|
@@ -53,11 +53,20 @@ export async function changedFiles(root: string, since?: string): Promise<string
|
|
|
53
53
|
// than repo-root-relative, so `scan()` can join them against a sub-directory
|
|
54
54
|
// root. Without it, a `--changed` scan of a subdirectory resolves nothing.
|
|
55
55
|
if (since) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
// A `git diff` against `since` returns null ONLY when the command failed —
|
|
57
|
+
// almost always an unknown ref/range (a typo like `--since maiin`). Surface
|
|
58
|
+
// it instead of silently scanning just the uncommitted files and passing CI.
|
|
59
|
+
const diff = await git(root, [
|
|
60
|
+
"diff",
|
|
61
|
+
"--name-only",
|
|
62
|
+
"--relative",
|
|
63
|
+
"--diff-filter=ACMR",
|
|
64
|
+
since,
|
|
65
|
+
]);
|
|
66
|
+
if (diff === null) {
|
|
67
|
+
throw new Error(`--since: git could not diff against "${since}" (unknown ref or range).`);
|
|
60
68
|
}
|
|
69
|
+
for (const f of toLines(diff)) out.add(f);
|
|
61
70
|
}
|
|
62
71
|
|
|
63
72
|
// Always include local uncommitted edits (staged + unstaged), filtered to ACMR.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config-toggle codemod: mechanical, unambiguous fixes for insecure TLS config.
|
|
3
|
+
* Both target rules have a single correct replacement, so the fix is
|
|
4
|
+
* deterministic and clears the finding (verified by the pipeline's gate).
|
|
5
|
+
*
|
|
6
|
+
* - `tls-legacy-version` — bump a pinned TLS 1.0/1.1 to TLS 1.3.
|
|
7
|
+
* - `tls-reject-unauthorized` — turn certificate verification back on.
|
|
8
|
+
*/
|
|
9
|
+
import type { Finding } from "../types.js";
|
|
10
|
+
import type { Patch } from "../agent-types.js";
|
|
11
|
+
import type { Codemod } from "./registry.js";
|
|
12
|
+
|
|
13
|
+
export const configToggleCodemod: Codemod = {
|
|
14
|
+
id: "config-toggle",
|
|
15
|
+
applies(finding: Finding): boolean {
|
|
16
|
+
return finding.ruleId === "tls-legacy-version" || finding.ruleId === "tls-reject-unauthorized";
|
|
17
|
+
},
|
|
18
|
+
apply(content: string, finding: Finding): Patch | null {
|
|
19
|
+
let out = content;
|
|
20
|
+
if (finding.ruleId === "tls-legacy-version") {
|
|
21
|
+
out = out
|
|
22
|
+
.replace(/((?:minVersion|maxVersion)\s*:\s*['"`])TLSv1(?:\.1)?(['"`])/g, "$1TLSv1.3$2")
|
|
23
|
+
.replace(/(secureProtocol\s*:\s*['"`])TLSv1(?:_1)?_method(['"`])/g, "$1TLSv1_3_method$2");
|
|
24
|
+
} else if (finding.ruleId === "tls-reject-unauthorized") {
|
|
25
|
+
out = out.replace(/(rejectUnauthorized\s*:\s*)false/g, "$1true");
|
|
26
|
+
}
|
|
27
|
+
if (out === content) return null;
|
|
28
|
+
return {
|
|
29
|
+
path: finding.location.file,
|
|
30
|
+
newContent: out,
|
|
31
|
+
ruleId: finding.ruleId,
|
|
32
|
+
source: "codemod",
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
};
|