@de-otio/repo-aegis-core 0.2.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 (191) hide show
  1. package/dist/age.d.ts +32 -0
  2. package/dist/age.d.ts.map +1 -0
  3. package/dist/age.js +98 -0
  4. package/dist/age.js.map +1 -0
  5. package/dist/audit-log.d.ts +50 -0
  6. package/dist/audit-log.d.ts.map +1 -0
  7. package/dist/audit-log.js +183 -0
  8. package/dist/audit-log.js.map +1 -0
  9. package/dist/audit-log.test.d.ts +2 -0
  10. package/dist/audit-log.test.d.ts.map +1 -0
  11. package/dist/audit-log.test.js +181 -0
  12. package/dist/audit-log.test.js.map +1 -0
  13. package/dist/deny-set.d.ts +43 -0
  14. package/dist/deny-set.d.ts.map +1 -0
  15. package/dist/deny-set.js +165 -0
  16. package/dist/deny-set.js.map +1 -0
  17. package/dist/deny-set.test.d.ts +2 -0
  18. package/dist/deny-set.test.d.ts.map +1 -0
  19. package/dist/deny-set.test.js +155 -0
  20. package/dist/deny-set.test.js.map +1 -0
  21. package/dist/exceptions.d.ts +96 -0
  22. package/dist/exceptions.d.ts.map +1 -0
  23. package/dist/exceptions.js +143 -0
  24. package/dist/exceptions.js.map +1 -0
  25. package/dist/exit-codes.d.ts +4 -0
  26. package/dist/exit-codes.d.ts.map +1 -0
  27. package/dist/exit-codes.js +6 -0
  28. package/dist/exit-codes.js.map +1 -0
  29. package/dist/first-touch.d.ts +57 -0
  30. package/dist/first-touch.d.ts.map +1 -0
  31. package/dist/first-touch.js +112 -0
  32. package/dist/first-touch.js.map +1 -0
  33. package/dist/import-graph.test.d.ts +2 -0
  34. package/dist/import-graph.test.d.ts.map +1 -0
  35. package/dist/import-graph.test.js +210 -0
  36. package/dist/import-graph.test.js.map +1 -0
  37. package/dist/index.d.ts +37 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +68 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/lock.d.ts +22 -0
  42. package/dist/lock.d.ts.map +1 -0
  43. package/dist/lock.js +86 -0
  44. package/dist/lock.js.map +1 -0
  45. package/dist/lock.test.d.ts +2 -0
  46. package/dist/lock.test.d.ts.map +1 -0
  47. package/dist/lock.test.js +125 -0
  48. package/dist/lock.test.js.map +1 -0
  49. package/dist/paths.d.ts +22 -0
  50. package/dist/paths.d.ts.map +1 -0
  51. package/dist/paths.js +46 -0
  52. package/dist/paths.js.map +1 -0
  53. package/dist/paths.test.d.ts +2 -0
  54. package/dist/paths.test.d.ts.map +1 -0
  55. package/dist/paths.test.js +78 -0
  56. package/dist/paths.test.js.map +1 -0
  57. package/dist/redaction.d.ts +29 -0
  58. package/dist/redaction.d.ts.map +1 -0
  59. package/dist/redaction.js +48 -0
  60. package/dist/redaction.js.map +1 -0
  61. package/dist/redaction.test.d.ts +2 -0
  62. package/dist/redaction.test.d.ts.map +1 -0
  63. package/dist/redaction.test.js +67 -0
  64. package/dist/redaction.test.js.map +1 -0
  65. package/dist/regex-safety.d.ts +87 -0
  66. package/dist/regex-safety.d.ts.map +1 -0
  67. package/dist/regex-safety.js +322 -0
  68. package/dist/regex-safety.js.map +1 -0
  69. package/dist/regex-safety.test.d.ts +2 -0
  70. package/dist/regex-safety.test.d.ts.map +1 -0
  71. package/dist/regex-safety.test.js +149 -0
  72. package/dist/regex-safety.test.js.map +1 -0
  73. package/dist/registry-mutate.d.ts +35 -0
  74. package/dist/registry-mutate.d.ts.map +1 -0
  75. package/dist/registry-mutate.js +149 -0
  76. package/dist/registry-mutate.js.map +1 -0
  77. package/dist/registry-mutate.test.d.ts +2 -0
  78. package/dist/registry-mutate.test.d.ts.map +1 -0
  79. package/dist/registry-mutate.test.js +96 -0
  80. package/dist/registry-mutate.test.js.map +1 -0
  81. package/dist/registry.d.ts +64 -0
  82. package/dist/registry.d.ts.map +1 -0
  83. package/dist/registry.js +120 -0
  84. package/dist/registry.js.map +1 -0
  85. package/dist/registry.test.d.ts +2 -0
  86. package/dist/registry.test.d.ts.map +1 -0
  87. package/dist/registry.test.js +316 -0
  88. package/dist/registry.test.js.map +1 -0
  89. package/dist/remote-url.d.ts +18 -0
  90. package/dist/remote-url.d.ts.map +1 -0
  91. package/dist/remote-url.js +66 -0
  92. package/dist/remote-url.js.map +1 -0
  93. package/dist/remote-url.test.d.ts +2 -0
  94. package/dist/remote-url.test.d.ts.map +1 -0
  95. package/dist/remote-url.test.js +116 -0
  96. package/dist/remote-url.test.js.map +1 -0
  97. package/dist/render.d.ts +54 -0
  98. package/dist/render.d.ts.map +1 -0
  99. package/dist/render.js +182 -0
  100. package/dist/render.js.map +1 -0
  101. package/dist/render.test.d.ts +2 -0
  102. package/dist/render.test.d.ts.map +1 -0
  103. package/dist/render.test.js +152 -0
  104. package/dist/render.test.js.map +1 -0
  105. package/dist/repo.d.ts +40 -0
  106. package/dist/repo.d.ts.map +1 -0
  107. package/dist/repo.js +214 -0
  108. package/dist/repo.js.map +1 -0
  109. package/dist/repo.test.d.ts +2 -0
  110. package/dist/repo.test.d.ts.map +1 -0
  111. package/dist/repo.test.js +234 -0
  112. package/dist/repo.test.js.map +1 -0
  113. package/dist/scan.d.ts +103 -0
  114. package/dist/scan.d.ts.map +1 -0
  115. package/dist/scan.js +436 -0
  116. package/dist/scan.js.map +1 -0
  117. package/dist/scan.test.d.ts +2 -0
  118. package/dist/scan.test.d.ts.map +1 -0
  119. package/dist/scan.test.js +437 -0
  120. package/dist/scan.test.js.map +1 -0
  121. package/dist/schemas.d.ts +50 -0
  122. package/dist/schemas.d.ts.map +1 -0
  123. package/dist/schemas.js +190 -0
  124. package/dist/schemas.js.map +1 -0
  125. package/dist/secret-markers.d.ts +34 -0
  126. package/dist/secret-markers.d.ts.map +1 -0
  127. package/dist/secret-markers.js +118 -0
  128. package/dist/secret-markers.js.map +1 -0
  129. package/dist/secret-markers.test.d.ts +2 -0
  130. package/dist/secret-markers.test.d.ts.map +1 -0
  131. package/dist/secret-markers.test.js +154 -0
  132. package/dist/secret-markers.test.js.map +1 -0
  133. package/dist/trust-boundary.d.ts +33 -0
  134. package/dist/trust-boundary.d.ts.map +1 -0
  135. package/dist/trust-boundary.js +77 -0
  136. package/dist/trust-boundary.js.map +1 -0
  137. package/dist/trust-boundary.test.d.ts +2 -0
  138. package/dist/trust-boundary.test.d.ts.map +1 -0
  139. package/dist/trust-boundary.test.js +170 -0
  140. package/dist/trust-boundary.test.js.map +1 -0
  141. package/dist/types.d.ts +47 -0
  142. package/dist/types.d.ts.map +1 -0
  143. package/dist/types.js +8 -0
  144. package/dist/types.js.map +1 -0
  145. package/dist/working-tree.d.ts +38 -0
  146. package/dist/working-tree.d.ts.map +1 -0
  147. package/dist/working-tree.js +133 -0
  148. package/dist/working-tree.js.map +1 -0
  149. package/dist/working-tree.test.d.ts +2 -0
  150. package/dist/working-tree.test.d.ts.map +1 -0
  151. package/dist/working-tree.test.js +162 -0
  152. package/dist/working-tree.test.js.map +1 -0
  153. package/package.json +40 -0
  154. package/src/age.ts +113 -0
  155. package/src/audit-log.test.ts +222 -0
  156. package/src/audit-log.ts +215 -0
  157. package/src/deny-set.test.ts +208 -0
  158. package/src/deny-set.ts +231 -0
  159. package/src/exceptions.ts +134 -0
  160. package/src/exit-codes.ts +5 -0
  161. package/src/first-touch.ts +172 -0
  162. package/src/import-graph.test.ts +239 -0
  163. package/src/index.ts +191 -0
  164. package/src/lock.test.ts +151 -0
  165. package/src/lock.ts +88 -0
  166. package/src/paths.test.ts +94 -0
  167. package/src/paths.ts +55 -0
  168. package/src/redaction.test.ts +81 -0
  169. package/src/redaction.ts +49 -0
  170. package/src/regex-safety.test.ts +194 -0
  171. package/src/regex-safety.ts +349 -0
  172. package/src/registry-mutate.test.ts +134 -0
  173. package/src/registry-mutate.ts +185 -0
  174. package/src/registry.test.ts +460 -0
  175. package/src/registry.ts +178 -0
  176. package/src/remote-url.test.ts +121 -0
  177. package/src/remote-url.ts +78 -0
  178. package/src/render.test.ts +206 -0
  179. package/src/render.ts +215 -0
  180. package/src/repo.test.ts +275 -0
  181. package/src/repo.ts +245 -0
  182. package/src/scan.test.ts +580 -0
  183. package/src/scan.ts +531 -0
  184. package/src/schemas.ts +207 -0
  185. package/src/secret-markers.test.ts +183 -0
  186. package/src/secret-markers.ts +145 -0
  187. package/src/trust-boundary.test.ts +198 -0
  188. package/src/trust-boundary.ts +98 -0
  189. package/src/types.ts +55 -0
  190. package/src/working-tree.test.ts +193 -0
  191. package/src/working-tree.ts +130 -0
@@ -0,0 +1,437 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Richard Myers and contributors.
3
+ import { describe, it, before, after } from "node:test";
4
+ import assert from "node:assert/strict";
5
+ import { execFileSync } from "node:child_process";
6
+ import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, rmSync } from "node:fs";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+ import { scanText, scanFile, scanStagedDiff, scanRange, scanHistory } from "./scan.js";
10
+ const denySetWithPatterns = (patterns) => ({
11
+ files: [],
12
+ patterns,
13
+ combinedRegex: patterns.join("|"),
14
+ warnings: [],
15
+ });
16
+ let tmp;
17
+ before(() => {
18
+ tmp = mkdtempSync(join(tmpdir(), "repo-aegis-scan-"));
19
+ });
20
+ after(() => {
21
+ rmSync(tmp, { recursive: true, force: true });
22
+ });
23
+ describe("scanText", () => {
24
+ it("returns no hits with empty deny set", () => {
25
+ const ds = { files: [], patterns: [], combinedRegex: "", warnings: [] };
26
+ assert.deepEqual(scanText("anything", ds), []);
27
+ });
28
+ it("returns no hits when text doesn't match", () => {
29
+ const ds = denySetWithPatterns(["acme-corp", "betaco"]);
30
+ assert.deepEqual(scanText("hello world", ds), []);
31
+ });
32
+ it("returns one hit per matching line", () => {
33
+ const ds = denySetWithPatterns(["acme-corp", "betaco"]);
34
+ const hits = scanText("first line\nsecond has acme-corp\nthird line\nfourth has betaco", ds);
35
+ assert.equal(hits.length, 2);
36
+ assert.equal(hits[0].line, 2);
37
+ assert.equal(hits[1].line, 4);
38
+ });
39
+ it("computes accurate column number", () => {
40
+ const ds = denySetWithPatterns(["acme-corp"]);
41
+ const hits = scanText("padding acme-corp here", ds);
42
+ assert.equal(hits.length, 1);
43
+ assert.equal(hits[0].column, 9);
44
+ });
45
+ it("redacts match by default (preview format)", () => {
46
+ const ds = denySetWithPatterns(["acme-corp"]);
47
+ const hits = scanText("see acme-corp", ds);
48
+ assert.equal(hits[0].matchPreview, "acm***9");
49
+ assert.ok(!hits[0].matchPreview.includes("corp"));
50
+ });
51
+ it("reveals literal when revealMatches is true", () => {
52
+ const ds = denySetWithPatterns(["acme-corp"]);
53
+ const hits = scanText("see acme-corp", ds, undefined, { revealMatches: true });
54
+ assert.equal(hits[0].matchPreview, "acme-corp");
55
+ });
56
+ it("redaction never echoes the literal", () => {
57
+ const ds = denySetWithPatterns(["very-specific-customer-name"]);
58
+ const hits = scanText("contains very-specific-customer-name here", ds);
59
+ assert.ok(!hits[0].matchPreview.includes("specific"));
60
+ assert.ok(!hits[0].matchPreview.includes("customer"));
61
+ });
62
+ it("propagates path field when provided", () => {
63
+ const ds = denySetWithPatterns(["acme"]);
64
+ const hits = scanText("acme!", ds, "src/foo.ts");
65
+ assert.equal(hits[0].path, "src/foo.ts");
66
+ });
67
+ it("case-insensitive matching", () => {
68
+ const ds = denySetWithPatterns(["acme"]);
69
+ const hits = scanText("see ACME-Corp", ds);
70
+ assert.equal(hits.length, 1);
71
+ });
72
+ it("respects per-line allow comments by default", () => {
73
+ const ds = denySetWithPatterns(["acme-corp"]);
74
+ const text = [
75
+ "this acme-corp has hit",
76
+ "this acme-corp is fine // repo-aegis: allow synthetic fixture",
77
+ "this acme-corp is also a hit",
78
+ ].join("\n");
79
+ const hits = scanText(text, ds);
80
+ assert.equal(hits.length, 2);
81
+ assert.equal(hits[0].line, 1);
82
+ assert.equal(hits[1].line, 3);
83
+ });
84
+ it("recognises the allow comment in any comment style", () => {
85
+ const ds = denySetWithPatterns(["acme-corp"]);
86
+ const cases = [
87
+ "acme-corp # repo-aegis: allow",
88
+ "acme-corp /* repo-aegis: allow */",
89
+ "acme-corp <!-- repo-aegis: allow -->",
90
+ "acme-corp ;; repo-aegis: allow",
91
+ ];
92
+ for (const text of cases) {
93
+ assert.equal(scanText(text, ds).length, 0, `should suppress: ${text}`);
94
+ }
95
+ });
96
+ it("does NOT suppress when allow token is malformed", () => {
97
+ const ds = denySetWithPatterns(["acme-corp"]);
98
+ const text = "acme-corp # repo-aegis allow"; // missing colon
99
+ assert.equal(scanText(text, ds).length, 1);
100
+ });
101
+ it("respectAllowComments=false bypasses suppression", () => {
102
+ const ds = denySetWithPatterns(["acme-corp"]);
103
+ const text = "acme-corp // repo-aegis: allow";
104
+ const hits = scanText(text, ds, undefined, { respectAllowComments: false });
105
+ assert.equal(hits.length, 1);
106
+ });
107
+ it("attributes the matched pattern to its source engagement", () => {
108
+ // Two patterns from two different "engagements". Hit on the second
109
+ // pattern should report engagement = "customer-b".
110
+ const ds = {
111
+ files: [],
112
+ patterns: ["alpha-marker", "bravo-marker"],
113
+ patternSources: ["customer-a", "customer-b"],
114
+ combinedRegex: "alpha-marker|bravo-marker",
115
+ warnings: [],
116
+ };
117
+ const hits = scanText("see bravo-marker", ds);
118
+ assert.equal(hits.length, 1);
119
+ assert.equal(hits[0].engagement, "customer-b");
120
+ });
121
+ it("omits engagement when patternSources is missing", () => {
122
+ const ds = denySetWithPatterns(["lone-marker"]);
123
+ const hits = scanText("see lone-marker", ds);
124
+ assert.equal(hits.length, 1);
125
+ assert.equal(hits[0].engagement, undefined);
126
+ });
127
+ it("omits engagement when patternSources length mismatches", () => {
128
+ const ds = {
129
+ files: [],
130
+ patterns: ["a-marker", "b-marker"],
131
+ patternSources: ["only-one"], // length mismatch
132
+ combinedRegex: "a-marker|b-marker",
133
+ warnings: [],
134
+ };
135
+ const hits = scanText("see a-marker", ds);
136
+ assert.equal(hits[0].engagement, undefined);
137
+ });
138
+ });
139
+ describe("scanFile", () => {
140
+ it("returns hits from a real file", () => {
141
+ const path = join(tmp, "test.txt");
142
+ writeFileSync(path, "first line\nsecond has acme-corp here");
143
+ const ds = denySetWithPatterns(["acme-corp"]);
144
+ const r = scanFile(path, ds);
145
+ assert.equal(r.hits.length, 1);
146
+ assert.equal(r.skipped.length, 0);
147
+ });
148
+ it("skips binary files (NUL byte heuristic)", () => {
149
+ const path = join(tmp, "binary.bin");
150
+ writeFileSync(path, Buffer.from([0x00, 0x01, 0x02, 0x03, 0x04]));
151
+ const ds = denySetWithPatterns(["a"]);
152
+ const r = scanFile(path, ds);
153
+ assert.equal(r.hits.length, 0);
154
+ assert.equal(r.skipped.length, 1);
155
+ assert.equal(r.skipped[0].reason, "binary");
156
+ });
157
+ it("skips files over the size limit", () => {
158
+ const path = join(tmp, "big.txt");
159
+ writeFileSync(path, "a".repeat(100));
160
+ const ds = denySetWithPatterns(["a"]);
161
+ const r = scanFile(path, ds, { maxFileBytes: 50 });
162
+ assert.equal(r.hits.length, 0);
163
+ assert.equal(r.skipped[0].reason, "too-large");
164
+ });
165
+ it("reports unreadable for missing files", () => {
166
+ const ds = denySetWithPatterns(["a"]);
167
+ const r = scanFile(join(tmp, "doesnotexist.txt"), ds);
168
+ assert.equal(r.skipped[0].reason, "unreadable");
169
+ });
170
+ });
171
+ function makeRepoConfig(cwd) {
172
+ return {
173
+ cwd,
174
+ isGitRepo: true,
175
+ class: "private-strict",
176
+ classExplicit: true,
177
+ engagements: [],
178
+ };
179
+ }
180
+ function gitInit(dir) {
181
+ mkdirSync(dir, { recursive: true });
182
+ execFileSync("git", ["init", "-q", "-b", "main"], { cwd: dir });
183
+ execFileSync("git", ["config", "user.email", "test@example.com"], { cwd: dir });
184
+ execFileSync("git", ["config", "user.name", "test"], { cwd: dir });
185
+ }
186
+ function commit(dir, files, msg) {
187
+ for (const [p, c] of Object.entries(files)) {
188
+ writeFileSync(join(dir, p), c);
189
+ execFileSync("git", ["add", p], { cwd: dir });
190
+ }
191
+ execFileSync("git", ["commit", "-q", "-m", msg], { cwd: dir });
192
+ return execFileSync("git", ["rev-parse", "HEAD"], { cwd: dir, encoding: "utf8" }).trim();
193
+ }
194
+ describe("scanRange", () => {
195
+ it("returns no hits when range has no matching additions", () => {
196
+ const dir = join(tmp, "range-clean");
197
+ gitInit(dir);
198
+ const a = commit(dir, { "f.txt": "hello\n" }, "init");
199
+ const b = commit(dir, { "f.txt": "hello\nworld\n" }, "add world");
200
+ const r = scanRange(makeRepoConfig(dir), denySetWithPatterns(["secret-marker"]), `${a}..${b}`);
201
+ assert.equal(r.hits.length, 0);
202
+ });
203
+ it("flags an added line that contains a marker", () => {
204
+ const dir = join(tmp, "range-hit");
205
+ gitInit(dir);
206
+ const a = commit(dir, { "f.txt": "hello\n" }, "init");
207
+ const b = commit(dir, { "f.txt": "hello\nleaked-marker-here\n" }, "leak");
208
+ const r = scanRange(makeRepoConfig(dir), denySetWithPatterns(["leaked-marker"]), `${a}..${b}`);
209
+ assert.equal(r.hits.length, 1);
210
+ });
211
+ it("does NOT flag a removed line (only + lines)", () => {
212
+ const dir = join(tmp, "range-removed");
213
+ gitInit(dir);
214
+ const a = commit(dir, { "f.txt": "removed-marker\n" }, "init");
215
+ const b = commit(dir, { "f.txt": "" }, "remove");
216
+ const r = scanRange(makeRepoConfig(dir), denySetWithPatterns(["removed-marker"]), `${a}..${b}`);
217
+ assert.equal(r.hits.length, 0);
218
+ });
219
+ it("redacts the literal in matchPreview by default", () => {
220
+ const dir = join(tmp, "range-redact");
221
+ gitInit(dir);
222
+ const a = commit(dir, { "f.txt": "x\n" }, "init");
223
+ const b = commit(dir, { "f.txt": "x\nspecific-leak-string\n" }, "leak");
224
+ const r = scanRange(makeRepoConfig(dir), denySetWithPatterns(["specific-leak-string"]), `${a}..${b}`);
225
+ assert.ok(!r.hits[0].matchPreview.includes("specific-leak"));
226
+ });
227
+ });
228
+ describe("scanRange diff parsing edge cases", () => {
229
+ it("does NOT flag the literal '+++ b/<name>' header even when the path matches a pattern", () => {
230
+ // Construct a scenario where the new filename itself contains the
231
+ // marker. The hand-rolled `+`-line filter would have read
232
+ // `+++ b/leaked-marker.txt` as added content (after slicing the
233
+ // first `+`, the content `++ b/leaked-marker.txt` no longer starts
234
+ // with `+`, but historically `+++` was special-cased only for the
235
+ // header itself — pattern-matching the path is the false positive
236
+ // here). parse-diff treats `+++ b/...` as a header and never emits
237
+ // it as an `add` change.
238
+ const dir = join(tmp, "range-rename-header");
239
+ gitInit(dir);
240
+ const a = commit(dir, { "ordinary.txt": "hello\n" }, "init");
241
+ // Rename ordinary.txt to a name that contains the marker. No
242
+ // content changes, so no `add` content lines should be emitted.
243
+ execFileSync("git", ["mv", "ordinary.txt", "leaked-marker.txt"], { cwd: dir });
244
+ execFileSync("git", ["commit", "-q", "-m", "rename"], { cwd: dir });
245
+ const b = execFileSync("git", ["rev-parse", "HEAD"], {
246
+ cwd: dir,
247
+ encoding: "utf8",
248
+ }).trim();
249
+ const r = scanRange(makeRepoConfig(dir), denySetWithPatterns(["leaked-marker"]), `${a}..${b}`);
250
+ assert.equal(r.hits.length, 0, "filename in '+++ b/...' header must not be scanned as content");
251
+ });
252
+ it("a pure rename (no content changes) yields no additions", () => {
253
+ const dir = join(tmp, "range-rename-only");
254
+ gitInit(dir);
255
+ const a = commit(dir, { "old.txt": "the-secret-marker\n" }, "init");
256
+ execFileSync("git", ["mv", "old.txt", "new.txt"], { cwd: dir });
257
+ execFileSync("git", ["commit", "-q", "-m", "rename"], { cwd: dir });
258
+ const b = execFileSync("git", ["rev-parse", "HEAD"], {
259
+ cwd: dir,
260
+ encoding: "utf8",
261
+ }).trim();
262
+ const r = scanRange(makeRepoConfig(dir), denySetWithPatterns(["the-secret-marker"]), `${a}..${b}`);
263
+ assert.equal(r.hits.length, 0, "pure rename has no `add` changes; pre-existing content must not be re-flagged");
264
+ });
265
+ it("flags an added line whose literal content begins with '+'", () => {
266
+ // A hunk line of `++added-marker` is, in unified-diff terms, an
267
+ // `add` whose content is `+added-marker`. The hand-rolled filter
268
+ // sliced one `+` off the front (correct), giving `+added-marker`,
269
+ // so it would still flag — but the property under test is that
270
+ // parse-diff also flags it (i.e. we didn't regress the
271
+ // "+`-prefixed in-hunk content gets scanned" case).
272
+ const dir = join(tmp, "range-plus-prefixed");
273
+ gitInit(dir);
274
+ const a = commit(dir, { "f.txt": "hello\n" }, "init");
275
+ const b = commit(dir, { "f.txt": "hello\n+added-marker\n" }, "add plus-prefixed line");
276
+ const r = scanRange(makeRepoConfig(dir), denySetWithPatterns(["added-marker"]), `${a}..${b}`);
277
+ assert.equal(r.hits.length, 1, "added line whose content starts with '+' must be flagged");
278
+ });
279
+ it("does NOT flag context (unchanged) lines whose content begins with '+'", () => {
280
+ // With -U0 there are no context lines in scanRange's git invocation,
281
+ // but feed a synthetic diff through extractAdditions via scanStagedDiff
282
+ // would require staging. Instead, exercise the parser directly through
283
+ // a multi-hunk scenario: two unrelated changes far apart in a file
284
+ // already containing a '+'-prefixed line; only the actually-added
285
+ // line should be flagged.
286
+ const dir = join(tmp, "range-context-plus");
287
+ gitInit(dir);
288
+ // Pre-existing line "+context-marker" is committed (so it lives in
289
+ // the file at base), then an unrelated benign change is added.
290
+ const a = commit(dir, { "f.txt": "alpha\n+context-marker\nbeta\n" }, "init with plus-prefixed context");
291
+ const b = commit(dir, { "f.txt": "alpha\n+context-marker\nbeta\nharmless\n" }, "append harmless line");
292
+ const r = scanRange(makeRepoConfig(dir), denySetWithPatterns(["context-marker"]), `${a}..${b}`);
293
+ assert.equal(r.hits.length, 0, "context line containing '+context-marker' must not be flagged when only an unrelated line was added");
294
+ });
295
+ });
296
+ describe("scanStagedDiff", () => {
297
+ it("flags an added line in the staged diff", () => {
298
+ const dir = join(tmp, "staged-hit");
299
+ gitInit(dir);
300
+ commit(dir, { "f.txt": "hello\n" }, "init");
301
+ writeFileSync(join(dir, "f.txt"), "hello\nstaged-leak-marker\n");
302
+ execFileSync("git", ["add", "f.txt"], { cwd: dir });
303
+ const r = scanStagedDiff(makeRepoConfig(dir), denySetWithPatterns(["staged-leak-marker"]));
304
+ assert.equal(r.hits.length, 1);
305
+ });
306
+ it("does NOT flag the new filename in a staged rename whose path matches a pattern", () => {
307
+ const dir = join(tmp, "staged-rename");
308
+ gitInit(dir);
309
+ commit(dir, { "ordinary.txt": "hello\n" }, "init");
310
+ execFileSync("git", ["mv", "ordinary.txt", "leaked-marker.txt"], { cwd: dir });
311
+ // staged but not committed
312
+ const r = scanStagedDiff(makeRepoConfig(dir), denySetWithPatterns(["leaked-marker"]));
313
+ assert.equal(r.hits.length, 0, "filename in '+++ b/...' header must not be scanned as content");
314
+ });
315
+ });
316
+ describe("scanHistory", () => {
317
+ it("finds a commit whose diff contains a marker pattern", () => {
318
+ const dir = join(tmp, "hist-hit");
319
+ gitInit(dir);
320
+ commit(dir, { "f.txt": "x\n" }, "init");
321
+ const sha = commit(dir, { "f.txt": "x\nhistorical-marker-leak\n" }, "leaks-it");
322
+ const hits = scanHistory(makeRepoConfig(dir), denySetWithPatterns(["historical-marker-leak"]));
323
+ assert.ok(hits.length >= 1);
324
+ assert.ok(hits.some(h => sha.startsWith(h.commitSha)));
325
+ });
326
+ it("returns empty when no commits match any pattern", () => {
327
+ const dir = join(tmp, "hist-clean");
328
+ gitInit(dir);
329
+ commit(dir, { "f.txt": "boring\n" }, "init");
330
+ const hits = scanHistory(makeRepoConfig(dir), denySetWithPatterns(["never-existed"]));
331
+ assert.equal(hits.length, 0);
332
+ });
333
+ it("redacts the pattern by default", () => {
334
+ const dir = join(tmp, "hist-redact");
335
+ gitInit(dir);
336
+ commit(dir, { "f.txt": "secret-pattern-x\n" }, "leak");
337
+ const hits = scanHistory(makeRepoConfig(dir), denySetWithPatterns(["secret-pattern-x"]));
338
+ assert.ok(hits.length >= 1);
339
+ assert.ok(!hits[0].pattern.includes("secret-pattern"));
340
+ });
341
+ it("reveals literal pattern with revealMatches=true", () => {
342
+ const dir = join(tmp, "hist-reveal");
343
+ gitInit(dir);
344
+ commit(dir, { "f.txt": "secret-pattern-y\n" }, "leak");
345
+ const hits = scanHistory(makeRepoConfig(dir), denySetWithPatterns(["secret-pattern-y"]), { revealMatches: true });
346
+ assert.equal(hits[0].pattern, "secret-pattern-y");
347
+ });
348
+ it("multi-pattern scan: all patterns attributed in a single git invocation", () => {
349
+ // Two distinct patterns, each leaked in a different commit. The
350
+ // refactor combines patterns into one `git log -G '<a>|<b>'`
351
+ // invocation; we verify that with a counting `git` shim on PATH
352
+ // and assert exactly ONE git invocation drove the whole scan.
353
+ const dir = join(tmp, "hist-multi");
354
+ gitInit(dir);
355
+ commit(dir, { "f.txt": "init\n" }, "init");
356
+ const shaA = commit(dir, { "f.txt": "init\nalpha-leak-marker-here\n" }, "leak alpha");
357
+ const shaB = commit(dir, { "f.txt": "init\nalpha-leak-marker-here\nbravo-leak-marker-here\n" }, "leak bravo");
358
+ // Build a fake `git` on PATH that records each invocation to a
359
+ // log file and then exec()s the real git so behaviour is
360
+ // unchanged. Sufficient for invocation counting.
361
+ const shimDir = mkdtempSync(join(tmp, "shim-"));
362
+ const logPath = join(shimDir, "git-calls.log");
363
+ const realGit = execFileSync("which", ["git"], { encoding: "utf8" }).trim();
364
+ const shim = `#!/usr/bin/env bash\necho "$@" >> "${logPath}"\nexec ${realGit} "$@"\n`;
365
+ writeFileSync(join(shimDir, "git"), shim);
366
+ execFileSync("chmod", ["+x", join(shimDir, "git")]);
367
+ const prevPath = process.env["PATH"];
368
+ process.env["PATH"] = `${shimDir}:${prevPath ?? ""}`;
369
+ let hits;
370
+ try {
371
+ hits = scanHistory(makeRepoConfig(dir), denySetWithPatterns(["alpha-leak-marker", "bravo-leak-marker"]), { revealMatches: true });
372
+ }
373
+ finally {
374
+ if (prevPath !== undefined)
375
+ process.env["PATH"] = prevPath;
376
+ else
377
+ delete process.env["PATH"];
378
+ }
379
+ // Only one git invocation should have been made by scanHistory.
380
+ const calls = readFileSync(logPath, "utf8")
381
+ .split("\n")
382
+ .filter(Boolean);
383
+ // Some calls may include `git log -G` and others come from the
384
+ // shim itself only when scanHistory invoked git. The test gitInit
385
+ // / commit helpers call `execFileSync("git", ...)` *directly* with
386
+ // an absolute path resolved at import time, so they bypass the
387
+ // shim and don't pollute the count. (We installed the shim AFTER
388
+ // those commits.) Therefore exactly one entry is expected.
389
+ assert.equal(calls.length, 1, `expected exactly 1 git invocation, got ${calls.length}: ${calls.join(" | ")}`);
390
+ assert.ok(calls[0].includes("log"), `expected log subcommand, got: ${calls[0]}`);
391
+ // Each pattern must attribute to the commit that *introduced* it.
392
+ // (`git log -G` filters to commits where the diff content
393
+ // matched. Once a line is present, subsequent commits that don't
394
+ // touch it won't appear for that pattern.)
395
+ const alphaHits = hits.filter(h => h.pattern === "alpha-leak-marker");
396
+ const bravoHits = hits.filter(h => h.pattern === "bravo-leak-marker");
397
+ assert.ok(alphaHits.some(h => shaA.startsWith(h.commitSha)), `alpha pattern should attribute to commit ${shaA.slice(0, 7)}`);
398
+ assert.ok(bravoHits.some(h => shaB.startsWith(h.commitSha)), `bravo pattern should attribute to commit ${shaB.slice(0, 7)}`);
399
+ assert.ok(!bravoHits.some(h => shaA.startsWith(h.commitSha)), `bravo pattern must NOT attribute to commit ${shaA.slice(0, 7)} (not introduced there)`);
400
+ });
401
+ });
402
+ describe("scanRange streaming", () => {
403
+ it("handles a multi-MB diff without OOM (streaming, not buffered whole)", () => {
404
+ // Build a synthetic diff several MB in size by committing many
405
+ // benign lines and one marker line. The streaming implementation
406
+ // walks the diff in 64 KiB chunks; the prior buffer-the-whole-
407
+ // diff implementation would still complete here, but the test is
408
+ // worthwhile as a smoke test for the new code path on realistic
409
+ // large inputs.
410
+ const dir = join(tmp, "range-large");
411
+ gitInit(dir);
412
+ commit(dir, { "f.txt": "seed\n" }, "init");
413
+ // ~3 MB of benign added content: 60_000 lines × ~50 bytes each.
414
+ const benignLines = ["seed"];
415
+ for (let i = 0; i < 60_000; i++) {
416
+ benignLines.push(`benign-line-${i}-padding-padding-padding-padding-padding`);
417
+ }
418
+ benignLines.push("hidden-streaming-marker-line");
419
+ for (let i = 0; i < 100; i++) {
420
+ benignLines.push(`tail-${i}`);
421
+ }
422
+ const a = execFileSync("git", ["rev-parse", "HEAD"], {
423
+ cwd: dir,
424
+ encoding: "utf8",
425
+ }).trim();
426
+ writeFileSync(join(dir, "f.txt"), benignLines.join("\n") + "\n");
427
+ execFileSync("git", ["add", "f.txt"], { cwd: dir });
428
+ execFileSync("git", ["commit", "-q", "-m", "huge"], { cwd: dir });
429
+ const b = execFileSync("git", ["rev-parse", "HEAD"], {
430
+ cwd: dir,
431
+ encoding: "utf8",
432
+ }).trim();
433
+ const r = scanRange(makeRepoConfig(dir), denySetWithPatterns(["hidden-streaming-marker"]), `${a}..${b}`);
434
+ assert.equal(r.hits.length, 1, "marker buried in MB of additions must still be found");
435
+ });
436
+ });
437
+ //# sourceMappingURL=scan.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.test.js","sourceRoot":"","sources":["../src/scan.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Format a ZodError into the multi-line "human-readable" string we used
4
+ * to build by hand in the per-callsite validators. The output preserves
5
+ * the substrings that existing tests pin on (e.g. "must be", "missing",
6
+ * "reserved").
7
+ *
8
+ * For deeply nested issues we render `engagements[3].markers: ...`
9
+ * style paths — matches what the previous bespoke loops emitted.
10
+ */
11
+ export declare function formatZodError(err: z.ZodError, kind: string): string;
12
+ /**
13
+ * Allowed shape for a GitHub org name, used in `personalOrgs` and
14
+ * `engagements[*].githubOrgs`. Mirrors GitHub's own org-name constraint:
15
+ * lowercase alphanumerics and hyphens, starting with an alphanumeric.
16
+ *
17
+ * Schema rejects uppercase. Callers writing into the registry (e.g.
18
+ * `engagements add --github-org`) must lowercase input before persisting;
19
+ * the gate-time read path trusts the schema (no runtime case-folding).
20
+ */
21
+ export declare const ORG_NAME_REGEX: RegExp;
22
+ export declare const registryFileSchema: z.ZodObject<{
23
+ schemaVersion: z.ZodOptional<z.ZodNumber>;
24
+ always_block: z.ZodOptional<z.ZodArray<z.ZodString>>;
25
+ personalOrgs: z.ZodOptional<z.ZodArray<z.ZodString>>;
26
+ engagements: z.ZodArray<z.ZodObject<{
27
+ id: z.ZodString;
28
+ name: z.ZodString;
29
+ started: z.ZodOptional<z.ZodNullable<z.ZodString>>;
30
+ ended: z.ZodOptional<z.ZodNullable<z.ZodString>>;
31
+ reposActive: z.ZodOptional<z.ZodArray<z.ZodString>>;
32
+ markers: z.ZodArray<z.ZodString>;
33
+ notes: z.ZodOptional<z.ZodString>;
34
+ githubOrgs: z.ZodOptional<z.ZodArray<z.ZodString>>;
35
+ }, z.core.$loose>>;
36
+ }, z.core.$loose>;
37
+ export type RegistryFile = z.infer<typeof registryFileSchema>;
38
+ export declare const REPO_CLASSES: readonly ["public-eligible", "private-strict", "customer-coupled", "scratch"];
39
+ export type RepoClassLiteral = (typeof REPO_CLASSES)[number];
40
+ export declare const repoOverrideSchema: z.ZodObject<{
41
+ class: z.ZodOptional<z.ZodEnum<{
42
+ "public-eligible": "public-eligible";
43
+ "private-strict": "private-strict";
44
+ "customer-coupled": "customer-coupled";
45
+ scratch: "scratch";
46
+ }>>;
47
+ engagements: z.ZodOptional<z.ZodArray<z.ZodString>>;
48
+ }, z.core.$loose>;
49
+ export type RepoOverrideFile = z.infer<typeof repoOverrideSchema>;
50
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAapE;AAQD;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,QAAyB,CAAC;AAsCrD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;iBA8E3B,CAAC;AAEL,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAM9D,eAAO,MAAM,YAAY,+EAKf,CAAC;AACX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,eAAO,MAAM,kBAAkB;;;;;;;;iBAOf,CAAC;AAEjB,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}