@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.
Files changed (166) hide show
  1. package/dist/agent-types.d.ts +48 -0
  2. package/dist/agent-types.d.ts.map +1 -0
  3. package/dist/agent-types.js +2 -0
  4. package/dist/agent-types.js.map +1 -0
  5. package/dist/cache.d.ts +27 -0
  6. package/dist/cache.d.ts.map +1 -0
  7. package/dist/cache.js +93 -0
  8. package/dist/cache.js.map +1 -0
  9. package/dist/cbom.d.ts.map +1 -1
  10. package/dist/cbom.js +26 -1
  11. package/dist/cbom.js.map +1 -1
  12. package/dist/changed.d.ts.map +1 -1
  13. package/dist/changed.js +14 -2
  14. package/dist/changed.js.map +1 -1
  15. package/dist/codemods/config-toggle.d.ts +3 -0
  16. package/dist/codemods/config-toggle.d.ts.map +1 -0
  17. package/dist/codemods/config-toggle.js +26 -0
  18. package/dist/codemods/config-toggle.js.map +1 -0
  19. package/dist/codemods/registry.d.ts +26 -0
  20. package/dist/codemods/registry.d.ts.map +1 -0
  21. package/dist/codemods/registry.js +8 -0
  22. package/dist/codemods/registry.js.map +1 -0
  23. package/dist/comments.d.ts +45 -0
  24. package/dist/comments.d.ts.map +1 -0
  25. package/dist/comments.js +164 -0
  26. package/dist/comments.js.map +1 -0
  27. package/dist/config.d.ts +1 -1
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js +7 -0
  30. package/dist/config.js.map +1 -1
  31. package/dist/dependencies.d.ts +31 -13
  32. package/dist/dependencies.d.ts.map +1 -1
  33. package/dist/dependencies.js +460 -40
  34. package/dist/dependencies.js.map +1 -1
  35. package/dist/detect-utils.d.ts +44 -1
  36. package/dist/detect-utils.d.ts.map +1 -1
  37. package/dist/detect-utils.js +113 -17
  38. package/dist/detect-utils.js.map +1 -1
  39. package/dist/detectors/c.d.ts +20 -0
  40. package/dist/detectors/c.d.ts.map +1 -0
  41. package/dist/detectors/c.js +104 -0
  42. package/dist/detectors/c.js.map +1 -0
  43. package/dist/detectors/csharp.d.ts +15 -0
  44. package/dist/detectors/csharp.d.ts.map +1 -0
  45. package/dist/detectors/csharp.js +76 -0
  46. package/dist/detectors/csharp.js.map +1 -0
  47. package/dist/detectors/go.d.ts +25 -0
  48. package/dist/detectors/go.d.ts.map +1 -0
  49. package/dist/detectors/go.js +132 -0
  50. package/dist/detectors/go.js.map +1 -0
  51. package/dist/detectors/java.d.ts +25 -0
  52. package/dist/detectors/java.d.ts.map +1 -0
  53. package/dist/detectors/java.js +200 -0
  54. package/dist/detectors/java.js.map +1 -0
  55. package/dist/detectors/python.d.ts +26 -0
  56. package/dist/detectors/python.d.ts.map +1 -0
  57. package/dist/detectors/python.js +171 -0
  58. package/dist/detectors/python.js.map +1 -0
  59. package/dist/detectors/ruby.d.ts +15 -0
  60. package/dist/detectors/ruby.d.ts.map +1 -0
  61. package/dist/detectors/ruby.js +75 -0
  62. package/dist/detectors/ruby.js.map +1 -0
  63. package/dist/detectors/rust.d.ts +13 -0
  64. package/dist/detectors/rust.d.ts.map +1 -0
  65. package/dist/detectors/rust.js +94 -0
  66. package/dist/detectors/rust.js.map +1 -0
  67. package/dist/detectors/source.d.ts.map +1 -1
  68. package/dist/detectors/source.js +70 -22
  69. package/dist/detectors/source.js.map +1 -1
  70. package/dist/index.d.ts +18 -1
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +15 -1
  73. package/dist/index.js.map +1 -1
  74. package/dist/parallel.d.ts +4 -0
  75. package/dist/parallel.d.ts.map +1 -1
  76. package/dist/parallel.js +59 -8
  77. package/dist/parallel.js.map +1 -1
  78. package/dist/patch-policy.d.ts +22 -0
  79. package/dist/patch-policy.d.ts.map +1 -0
  80. package/dist/patch-policy.js +21 -0
  81. package/dist/patch-policy.js.map +1 -0
  82. package/dist/redact.d.ts +19 -0
  83. package/dist/redact.d.ts.map +1 -0
  84. package/dist/redact.js +77 -0
  85. package/dist/redact.js.map +1 -0
  86. package/dist/registry.d.ts +13 -3
  87. package/dist/registry.d.ts.map +1 -1
  88. package/dist/registry.js +31 -4
  89. package/dist/registry.js.map +1 -1
  90. package/dist/remediate-pipeline.d.ts +41 -0
  91. package/dist/remediate-pipeline.d.ts.map +1 -0
  92. package/dist/remediate-pipeline.js +38 -0
  93. package/dist/remediate-pipeline.js.map +1 -0
  94. package/dist/remediate-request.d.ts +21 -0
  95. package/dist/remediate-request.d.ts.map +1 -0
  96. package/dist/remediate-request.js +28 -0
  97. package/dist/remediate-request.js.map +1 -0
  98. package/dist/remediation.d.ts +10 -0
  99. package/dist/remediation.d.ts.map +1 -1
  100. package/dist/remediation.js +21 -8
  101. package/dist/remediation.js.map +1 -1
  102. package/dist/report.d.ts.map +1 -1
  103. package/dist/report.js +16 -1
  104. package/dist/report.js.map +1 -1
  105. package/dist/scan-worker.js +6 -2
  106. package/dist/scan-worker.js.map +1 -1
  107. package/dist/scan.d.ts +5 -4
  108. package/dist/scan.d.ts.map +1 -1
  109. package/dist/scan.js +52 -29
  110. package/dist/scan.js.map +1 -1
  111. package/dist/triage.d.ts +27 -0
  112. package/dist/triage.d.ts.map +1 -0
  113. package/dist/triage.js +33 -0
  114. package/dist/triage.js.map +1 -0
  115. package/dist/types.d.ts +53 -3
  116. package/dist/types.d.ts.map +1 -1
  117. package/dist/verify.d.ts +30 -0
  118. package/dist/verify.d.ts.map +1 -0
  119. package/dist/verify.js +65 -0
  120. package/dist/verify.js.map +1 -0
  121. package/dist/version.d.ts +1 -1
  122. package/dist/version.js +1 -1
  123. package/dist/walk.d.ts +7 -0
  124. package/dist/walk.d.ts.map +1 -1
  125. package/dist/walk.js +85 -11
  126. package/dist/walk.js.map +1 -1
  127. package/dist/worktree.d.ts +6 -0
  128. package/dist/worktree.d.ts.map +1 -0
  129. package/dist/worktree.js +43 -0
  130. package/dist/worktree.js.map +1 -0
  131. package/package.json +1 -1
  132. package/src/agent-types.ts +52 -0
  133. package/src/cache.ts +120 -0
  134. package/src/cbom.ts +27 -1
  135. package/src/changed.ts +13 -4
  136. package/src/codemods/config-toggle.ts +35 -0
  137. package/src/codemods/registry.ts +31 -0
  138. package/src/comments.ts +180 -0
  139. package/src/config.ts +8 -0
  140. package/src/dependencies.ts +483 -51
  141. package/src/detect-utils.ts +123 -15
  142. package/src/detectors/c.ts +132 -0
  143. package/src/detectors/csharp.ts +98 -0
  144. package/src/detectors/go.ts +167 -0
  145. package/src/detectors/java.ts +235 -0
  146. package/src/detectors/python.ts +212 -0
  147. package/src/detectors/ruby.ts +97 -0
  148. package/src/detectors/rust.ts +112 -0
  149. package/src/detectors/source.ts +69 -21
  150. package/src/index.ts +45 -1
  151. package/src/parallel.ts +63 -6
  152. package/src/patch-policy.ts +42 -0
  153. package/src/redact.ts +92 -0
  154. package/src/registry.ts +32 -4
  155. package/src/remediate-pipeline.ts +81 -0
  156. package/src/remediate-request.ts +52 -0
  157. package/src/remediation.ts +27 -11
  158. package/src/report.ts +27 -1
  159. package/src/scan-worker.ts +6 -2
  160. package/src/scan.ts +62 -31
  161. package/src/triage.ts +58 -0
  162. package/src/types.ts +66 -3
  163. package/src/verify.ts +82 -0
  164. package/src/version.ts +1 -1
  165. package/src/walk.ts +81 -12
  166. package/src/worktree.ts +45 -0
package/src/walk.ts CHANGED
@@ -8,6 +8,8 @@ import { readdir, stat } from "node:fs/promises";
8
8
  import type { Dirent } from "node:fs";
9
9
  import * as path from "node:path";
10
10
 
11
+ import { isManifestFile } from "./dependencies.js";
12
+
11
13
  /** Directories ignored by default (can be disabled with noDefaultIgnores). */
12
14
  export const DEFAULT_IGNORES: readonly string[] = [
13
15
  "node_modules",
@@ -116,12 +118,80 @@ export function toPosix(p: string): string {
116
118
  return p.split(path.sep).join("/");
117
119
  }
118
120
 
119
- /** True if `rel` (a POSIX relative path) matches any pattern (substring/prefix). */
120
- function matchesAny(rel: string, patterns: readonly string[]): boolean {
121
+ /** A pattern is treated as a glob when it contains one of these metacharacters. */
122
+ function hasGlobMeta(pattern: string): boolean {
123
+ return /[*?[]/.test(pattern);
124
+ }
125
+
126
+ /**
127
+ * Translate a glob into an anchored RegExp: `*` matches within a path segment
128
+ * (not `/`), `**` matches across segments, a leading `**` before a slash is an
129
+ * optional path prefix, `?` matches a single non-`/` char, `[...]` is a
130
+ * character class. Other regex
131
+ * metacharacters are escaped.
132
+ */
133
+ function globToRegExp(glob: string): RegExp {
134
+ let re = "";
135
+ for (let i = 0; i < glob.length; i++) {
136
+ const c = glob[i];
137
+ if (c === "*") {
138
+ if (glob[i + 1] === "*") {
139
+ i++; // consume the second '*'
140
+ if (glob[i + 1] === "/") {
141
+ i++; // consume the trailing '/'
142
+ re += "(?:.*/)?"; // zero or more path segments
143
+ } else {
144
+ re += ".*"; // '**' spanning segments
145
+ }
146
+ } else {
147
+ re += "[^/]*"; // '*' within a segment
148
+ }
149
+ } else if (c === "?") {
150
+ re += "[^/]";
151
+ } else if (c === "[") {
152
+ // Pass a character class through; find its closing ']'.
153
+ const end = glob.indexOf("]", i + 1);
154
+ if (end === -1) {
155
+ re += "\\[";
156
+ } else {
157
+ re += glob.slice(i, end + 1);
158
+ i = end;
159
+ }
160
+ } else if ("\\^$.|+(){}".includes(c)) {
161
+ re += "\\" + c;
162
+ } else {
163
+ re += c;
164
+ }
165
+ }
166
+ return new RegExp(`^${re}$`);
167
+ }
168
+
169
+ /** Memoized glob→RegExp so a pattern is compiled once, not once per file. */
170
+ const GLOB_CACHE = new Map<string, RegExp>();
171
+ function globRegExp(pattern: string): RegExp {
172
+ let re = GLOB_CACHE.get(pattern);
173
+ if (!re) {
174
+ re = globToRegExp(pattern);
175
+ GLOB_CACHE.set(pattern, re);
176
+ }
177
+ return re;
178
+ }
179
+
180
+ /**
181
+ * True if `rel` (a POSIX relative path) matches any pattern. A pattern with a
182
+ * glob metacharacter (`*`, `?`, `[`) is matched as an anchored glob; a plain
183
+ * pattern keeps the historical substring / path-prefix semantics (so `"src"`
184
+ * still matches `src/a.ts` and `"secrets"` matches anywhere).
185
+ */
186
+ export function matchesAny(rel: string, patterns: readonly string[]): boolean {
121
187
  for (const pattern of patterns) {
122
188
  if (!pattern) continue;
123
189
  const p = toPosix(pattern).replace(/\/+$/, "");
124
- // Substring match (handles "src/legacy" or "secrets")...
190
+ if (hasGlobMeta(p)) {
191
+ if (globRegExp(p).test(rel)) return true;
192
+ continue;
193
+ }
194
+ // Plain pattern: substring match (handles "src/legacy" or "secrets")...
125
195
  if (rel.includes(p)) return true;
126
196
  // ...and explicit path-prefix match ("foo" should match "foo/bar.ts").
127
197
  if (rel === p || rel.startsWith(`${p}/`)) return true;
@@ -232,16 +302,12 @@ interface WalkContext {
232
302
  * scanned for vulnerable dependencies instead of being silently dropped.
233
303
  */
234
304
  function passesSizeLimit(rel: string, size: number, maxFileSize: number): boolean {
235
- if (isManifestPath(rel)) return true;
305
+ // Dependency manifests are always read (they can exceed the size cap but carry
306
+ // the whole dependency tree). Uses the single {@link isManifestFile} definition.
307
+ if (isManifestFile(rel)) return true;
236
308
  return size <= maxFileSize;
237
309
  }
238
310
 
239
- /** True if the path's basename is a dependency manifest we always read. */
240
- function isManifestPath(rel: string): boolean {
241
- const base = rel.split("/").pop() ?? rel;
242
- return base === "package.json" || base === "package-lock.json";
243
- }
244
-
245
311
  /** Internal recursive directory walker. `relDir` is POSIX-relative to the root. */
246
312
  async function* walkDir(absDir: string, relDir: string, ctx: WalkContext): AsyncGenerator<string> {
247
313
  let entries: Dirent[];
@@ -274,8 +340,11 @@ async function* walkDir(absDir: string, relDir: string, ctx: WalkContext): Async
274
340
  if (!entry.isFile()) continue;
275
341
  if (isExcluded(rel, ctx.exclude)) continue;
276
342
  if (!isIncluded(rel, ctx.include)) continue;
277
- if (isBinaryPath(rel)) continue;
278
- if (isGeneratedPath(rel)) continue;
343
+ // Dependency manifests (incl. yarn.lock / pnpm-lock.yaml) are always read —
344
+ // they carry the dependency tree and must not be dropped as binary/generated.
345
+ const manifest = isManifestFile(rel);
346
+ if (!manifest && isBinaryPath(rel)) continue;
347
+ if (!manifest && isGeneratedPath(rel)) continue;
279
348
 
280
349
  try {
281
350
  const s = await stat(abs);
@@ -0,0 +1,45 @@
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
+
13
+ const exec = promisify(execFile);
14
+
15
+ async function git(args: string[], cwd?: string): Promise<void> {
16
+ await exec("git", args, { cwd });
17
+ }
18
+
19
+ /**
20
+ * Create a detached worktree of `repoRoot` at HEAD, run `fn` with its path, and
21
+ * always tear it down. Throws if `repoRoot` is not a git repository.
22
+ */
23
+ export async function withWorktree<T>(
24
+ repoRoot: string,
25
+ fn: (dir: string) => Promise<T>,
26
+ ): Promise<T> {
27
+ try {
28
+ await git(["rev-parse", "--is-inside-work-tree"], repoRoot);
29
+ } catch {
30
+ throw new Error(`withWorktree: "${repoRoot}" is not a git repository`);
31
+ }
32
+ const base = await mkdtemp(join(tmpdir(), "quantakrypto-wt-"));
33
+ const dir = join(base, "wt");
34
+ await git(["worktree", "add", "--detach", dir], repoRoot);
35
+ try {
36
+ return await fn(dir);
37
+ } finally {
38
+ try {
39
+ await git(["worktree", "remove", "--force", dir], repoRoot);
40
+ } catch {
41
+ // best effort — the temp dir removal below still reclaims the disk.
42
+ }
43
+ await rm(base, { recursive: true, force: true });
44
+ }
45
+ }