@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 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=lock.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.test.d.ts","sourceRoot":"","sources":["../src/lock.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,125 @@
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 { mkdtempSync, writeFileSync, existsSync, rmSync } from "node:fs";
6
+ import { tmpdir } from "node:os";
7
+ import { join } from "node:path";
8
+ import lockfile from "proper-lockfile";
9
+ import { withLock, withLockSync } from "./lock.js";
10
+ import { LockTimeoutError } from "./exceptions.js";
11
+ let tmp;
12
+ before(() => {
13
+ tmp = mkdtempSync(join(tmpdir(), "repo-aegis-lock-test-"));
14
+ });
15
+ after(() => {
16
+ rmSync(tmp, { recursive: true, force: true });
17
+ });
18
+ function lockPathFor(name) {
19
+ const p = join(tmp, name);
20
+ writeFileSync(p, "");
21
+ return p;
22
+ }
23
+ describe("withLockSync", () => {
24
+ it("runs fn while holding the lock and returns its result", () => {
25
+ const lp = lockPathFor("happy.lock");
26
+ const result = withLockSync(() => 42, { lockPath: lp });
27
+ assert.equal(result, 42);
28
+ });
29
+ it("releases the lock even when fn throws", () => {
30
+ const lp = lockPathFor("throw.lock");
31
+ assert.throws(() => withLockSync(() => { throw new Error("boom"); }, { lockPath: lp }), /boom/);
32
+ // Should be able to acquire it again immediately.
33
+ const r = withLockSync(() => "ok", { lockPath: lp });
34
+ assert.equal(r, "ok");
35
+ });
36
+ it("creates the lock file if missing", () => {
37
+ const lp = join(tmp, "auto-create.lock");
38
+ assert.equal(existsSync(lp), false);
39
+ withLockSync(() => 1, { lockPath: lp });
40
+ assert.ok(existsSync(lp));
41
+ });
42
+ it("throws LockTimeoutError when another process holds the lock", () => {
43
+ const lp = lockPathFor("contended.lock");
44
+ const release = lockfile.lockSync(lp, { stale: 30_000 });
45
+ try {
46
+ assert.throws(() => withLockSync(() => 1, { lockPath: lp }), LockTimeoutError);
47
+ }
48
+ finally {
49
+ release();
50
+ }
51
+ });
52
+ });
53
+ describe("withLock (async)", () => {
54
+ it("runs fn and returns its result", async () => {
55
+ const lp = lockPathFor("async-happy.lock");
56
+ const result = await withLock(() => 99, { lockPath: lp });
57
+ assert.equal(result, 99);
58
+ });
59
+ it("supports async fn", async () => {
60
+ const lp = lockPathFor("async-fn.lock");
61
+ const result = await withLock(async () => {
62
+ await new Promise(r => setTimeout(r, 5));
63
+ return "done";
64
+ }, { lockPath: lp });
65
+ assert.equal(result, "done");
66
+ });
67
+ it("releases the lock when fn rejects", async () => {
68
+ const lp = lockPathFor("async-reject.lock");
69
+ await assert.rejects(withLock(async () => { throw new Error("x"); }, { lockPath: lp }), /x/);
70
+ const r = await withLock(() => "ok", { lockPath: lp });
71
+ assert.equal(r, "ok");
72
+ });
73
+ it("serializes two parallel withLock calls against the same lockPath", async () => {
74
+ // Two concurrent withLock calls on the same path must NOT overlap.
75
+ // We record entry/exit timestamps for each and assert one's interval
76
+ // fully precedes the other.
77
+ const lp = lockPathFor("async-serialize.lock");
78
+ const HOLD_MS = 60;
79
+ const spans = [];
80
+ async function critical(label) {
81
+ return withLock(async () => {
82
+ const start = Date.now();
83
+ await new Promise(r => setTimeout(r, HOLD_MS));
84
+ const end = Date.now();
85
+ const span = { start, end, label };
86
+ spans.push(span);
87
+ return span;
88
+ }, { lockPath: lp, timeoutMs: 5000 });
89
+ }
90
+ const [a, b] = await Promise.all([critical("a"), critical("b")]);
91
+ // Sort by start time and assert non-overlap.
92
+ const sorted = [a, b].sort((x, y) => x.start - y.start);
93
+ assert.ok(sorted[0].end <= sorted[1].start, `expected serialized intervals; got a=[${a.start},${a.end}] b=[${b.start},${b.end}]`);
94
+ assert.equal(spans.length, 2);
95
+ });
96
+ it("throws LockTimeoutError when the path is held by lockfile.lockSync", async () => {
97
+ const lp = lockPathFor("async-contended.lock");
98
+ const release = lockfile.lockSync(lp, { stale: 30_000 });
99
+ try {
100
+ await assert.rejects(withLock(() => 1, { lockPath: lp, timeoutMs: 100 }), LockTimeoutError);
101
+ }
102
+ finally {
103
+ release();
104
+ }
105
+ });
106
+ it("honours timeoutMs (rejects within the timeout window)", async () => {
107
+ const lp = lockPathFor("async-timeout.lock");
108
+ const release = lockfile.lockSync(lp, { stale: 30_000 });
109
+ try {
110
+ const t0 = Date.now();
111
+ await assert.rejects(withLock(() => 1, { lockPath: lp, timeoutMs: 100 }), LockTimeoutError);
112
+ const elapsed = Date.now() - t0;
113
+ // proper-lockfile retry math + jitter: a 100ms timeout typically
114
+ // settles in well under 500ms. Generous upper bound to avoid CI
115
+ // flake on busy runners; the lower bound asserts we waited at all
116
+ // (i.e. that timeoutMs wasn't ignored entirely and rejected
117
+ // immediately at the very first retry).
118
+ assert.ok(elapsed < 1500, `withLock should reject promptly under timeoutMs=100; elapsed=${elapsed}ms`);
119
+ }
120
+ finally {
121
+ release();
122
+ }
123
+ });
124
+ });
125
+ //# sourceMappingURL=lock.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.test.js","sourceRoot":"","sources":["../src/lock.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export declare function repoAegisHome(): string;
2
+ export declare function registryPath(home?: string): string;
3
+ export declare function markersDir(home?: string): string;
4
+ export declare function flatMarkersPath(home?: string): string;
5
+ export declare function statePath(home?: string): string;
6
+ export declare function leakContextFlagPath(home?: string): string;
7
+ export declare function lockFilePath(home?: string): string;
8
+ export declare function denySetCachePath(home?: string): string;
9
+ /**
10
+ * Path of the operator audit log. JSON Lines, append-only, chmod 600.
11
+ * Off by default; opted into via `~/.config/repo-aegis/state/audit-log.json`
12
+ * (`{ "enabled": true }`). See `audit-log.ts` for the writer and
13
+ * `cli/commands/audit-log.ts` for the on/off/show/path subcommands.
14
+ */
15
+ export declare function auditLogPath(home?: string): string;
16
+ /**
17
+ * True if `REPO_AEGIS_HOME` is set in the environment, indicating the user
18
+ * (or a parent process) has overridden the default home. CLI uses this to
19
+ * print a stderr warning that the override is in effect.
20
+ */
21
+ export declare function isHomeOverridden(): boolean;
22
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAKA,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,YAAY,CAAC,IAAI,GAAE,MAAwB,GAAG,MAAM,CAEnE;AAED,wBAAgB,UAAU,CAAC,IAAI,GAAE,MAAwB,GAAG,MAAM,CAEjE;AAED,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAwB,GAAG,MAAM,CAEtE;AAED,wBAAgB,SAAS,CAAC,IAAI,GAAE,MAAwB,GAAG,MAAM,CAEhE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,MAAwB,GAAG,MAAM,CAE1E;AAED,wBAAgB,YAAY,CAAC,IAAI,GAAE,MAAwB,GAAG,MAAM,CAEnE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,MAAwB,GAAG,MAAM,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,GAAE,MAAwB,GAAG,MAAM,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}
package/dist/paths.js ADDED
@@ -0,0 +1,46 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Richard Myers and contributors.
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ export function repoAegisHome() {
6
+ return process.env["REPO_AEGIS_HOME"] ?? join(homedir(), ".config", "repo-aegis");
7
+ }
8
+ export function registryPath(home = repoAegisHome()) {
9
+ return process.env["REPO_AEGIS_REGISTRY"] ?? join(home, "engagements.yaml");
10
+ }
11
+ export function markersDir(home = repoAegisHome()) {
12
+ return process.env["REPO_AEGIS_MARKERS_DIR"] ?? join(home, "markers");
13
+ }
14
+ export function flatMarkersPath(home = repoAegisHome()) {
15
+ return join(home, "markers.txt");
16
+ }
17
+ export function statePath(home = repoAegisHome()) {
18
+ return join(home, "state");
19
+ }
20
+ export function leakContextFlagPath(home = repoAegisHome()) {
21
+ return join(statePath(home), "leak-context-mode");
22
+ }
23
+ export function lockFilePath(home = repoAegisHome()) {
24
+ return join(statePath(home), ".lock");
25
+ }
26
+ export function denySetCachePath(home = repoAegisHome()) {
27
+ return join(statePath(home), "deny-set.cache.json");
28
+ }
29
+ /**
30
+ * Path of the operator audit log. JSON Lines, append-only, chmod 600.
31
+ * Off by default; opted into via `~/.config/repo-aegis/state/audit-log.json`
32
+ * (`{ "enabled": true }`). See `audit-log.ts` for the writer and
33
+ * `cli/commands/audit-log.ts` for the on/off/show/path subcommands.
34
+ */
35
+ export function auditLogPath(home = repoAegisHome()) {
36
+ return join(statePath(home), "audit.log");
37
+ }
38
+ /**
39
+ * True if `REPO_AEGIS_HOME` is set in the environment, indicating the user
40
+ * (or a parent process) has overridden the default home. CLI uses this to
41
+ * print a stderr warning that the override is in effect.
42
+ */
43
+ export function isHomeOverridden() {
44
+ return process.env["REPO_AEGIS_HOME"] !== undefined;
45
+ }
46
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,qDAAqD;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,UAAU,aAAa;IAC3B,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe,aAAa,EAAE;IACzD,OAAO,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe,aAAa,EAAE;IACvD,OAAO,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe,aAAa,EAAE;IAC5D,OAAO,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAe,aAAa,EAAE;IACtD,OAAO,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAe,aAAa,EAAE;IAChE,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,mBAAmB,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe,aAAa,EAAE;IACzD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAe,aAAa,EAAE;IAC7D,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,qBAAqB,CAAC,CAAC;AACtD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,aAAa,EAAE;IACzD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC;AAC5C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,SAAS,CAAC;AACtD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=paths.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.test.d.ts","sourceRoot":"","sources":["../src/paths.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,78 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Richard Myers and contributors.
3
+ import { describe, it, beforeEach, afterEach } from "node:test";
4
+ import assert from "node:assert/strict";
5
+ import { repoAegisHome, registryPath, markersDir, flatMarkersPath, statePath, leakContextFlagPath, lockFilePath, isHomeOverridden, } from "./paths.js";
6
+ let originalHome;
7
+ let originalRegistry;
8
+ let originalMarkersDir;
9
+ beforeEach(() => {
10
+ originalHome = process.env["REPO_AEGIS_HOME"];
11
+ originalRegistry = process.env["REPO_AEGIS_REGISTRY"];
12
+ originalMarkersDir = process.env["REPO_AEGIS_MARKERS_DIR"];
13
+ delete process.env["REPO_AEGIS_HOME"];
14
+ delete process.env["REPO_AEGIS_REGISTRY"];
15
+ delete process.env["REPO_AEGIS_MARKERS_DIR"];
16
+ });
17
+ afterEach(() => {
18
+ if (originalHome !== undefined)
19
+ process.env["REPO_AEGIS_HOME"] = originalHome;
20
+ else
21
+ delete process.env["REPO_AEGIS_HOME"];
22
+ if (originalRegistry !== undefined)
23
+ process.env["REPO_AEGIS_REGISTRY"] = originalRegistry;
24
+ else
25
+ delete process.env["REPO_AEGIS_REGISTRY"];
26
+ if (originalMarkersDir !== undefined)
27
+ process.env["REPO_AEGIS_MARKERS_DIR"] = originalMarkersDir;
28
+ else
29
+ delete process.env["REPO_AEGIS_MARKERS_DIR"];
30
+ });
31
+ describe("paths", () => {
32
+ it("default home is ~/.config/repo-aegis", () => {
33
+ const h = repoAegisHome();
34
+ assert.match(h, /\.config\/repo-aegis$/);
35
+ });
36
+ it("REPO_AEGIS_HOME env overrides home", () => {
37
+ process.env["REPO_AEGIS_HOME"] = "/tmp/custom";
38
+ assert.equal(repoAegisHome(), "/tmp/custom");
39
+ });
40
+ it("REPO_AEGIS_REGISTRY overrides registry path", () => {
41
+ process.env["REPO_AEGIS_REGISTRY"] = "/tmp/custom-registry.yaml";
42
+ assert.equal(registryPath(), "/tmp/custom-registry.yaml");
43
+ });
44
+ it("registryPath defaults to home/engagements.yaml", () => {
45
+ process.env["REPO_AEGIS_HOME"] = "/tmp/x";
46
+ assert.equal(registryPath(), "/tmp/x/engagements.yaml");
47
+ });
48
+ it("REPO_AEGIS_MARKERS_DIR overrides markers path", () => {
49
+ process.env["REPO_AEGIS_MARKERS_DIR"] = "/tmp/custom-markers";
50
+ assert.equal(markersDir(), "/tmp/custom-markers");
51
+ });
52
+ it("markersDir defaults to home/markers", () => {
53
+ process.env["REPO_AEGIS_HOME"] = "/tmp/x";
54
+ assert.equal(markersDir(), "/tmp/x/markers");
55
+ });
56
+ it("flatMarkersPath is home/markers.txt", () => {
57
+ process.env["REPO_AEGIS_HOME"] = "/tmp/x";
58
+ assert.equal(flatMarkersPath(), "/tmp/x/markers.txt");
59
+ });
60
+ it("statePath is home/state", () => {
61
+ process.env["REPO_AEGIS_HOME"] = "/tmp/x";
62
+ assert.equal(statePath(), "/tmp/x/state");
63
+ });
64
+ it("leakContextFlagPath is home/state/leak-context-mode", () => {
65
+ process.env["REPO_AEGIS_HOME"] = "/tmp/x";
66
+ assert.equal(leakContextFlagPath(), "/tmp/x/state/leak-context-mode");
67
+ });
68
+ it("lockFilePath is home/state/.lock", () => {
69
+ process.env["REPO_AEGIS_HOME"] = "/tmp/x";
70
+ assert.equal(lockFilePath(), "/tmp/x/state/.lock");
71
+ });
72
+ it("isHomeOverridden reflects env var presence", () => {
73
+ assert.equal(isHomeOverridden(), false);
74
+ process.env["REPO_AEGIS_HOME"] = "/tmp/x";
75
+ assert.equal(isHomeOverridden(), true);
76
+ });
77
+ });
78
+ //# sourceMappingURL=paths.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.test.js","sourceRoot":"","sources":["../src/paths.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export type RedactionMode = "preview" | "hash" | "position-only";
2
+ /**
3
+ * Redact a matched marker string for safe display.
4
+ *
5
+ * Default mode `preview` returns `<first-3-chars>***<length-N>` for matches
6
+ * of length >= 4, else `[redacted]`. The literal match value never appears
7
+ * in output that flows to AI agent context (PostToolUse hook output, error
8
+ * messages, JSON payloads), because the literal match in recent context is
9
+ * exactly the recency-pressure failure mode the tool exists to prevent.
10
+ *
11
+ * `hash` mode returns the first 8 hex chars of SHA-256 + length, useful
12
+ * when distinct hits should be distinguishable from each other but the
13
+ * value itself remains opaque.
14
+ *
15
+ * `position-only` returns the constant `[redacted]`.
16
+ */
17
+ export declare function redactMatch(match: string, mode?: RedactionMode): string;
18
+ /**
19
+ * Pass-through; explicit "this is the literal".
20
+ *
21
+ * Should ONLY be called when the user has explicitly opted in via the
22
+ * `--verbose` CLI flag. Hooks must never pass through this function.
23
+ *
24
+ * The previous `REPO_AEGIS_REVEAL_MATCHES` env-var was removed: env
25
+ * vars propagate to subprocess hooks unintentionally and could cause
26
+ * literal markers to flow into AI tool-result context.
27
+ */
28
+ export declare function revealMatch(match: string): string;
29
+ //# sourceMappingURL=redaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../src/redaction.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,eAAe,CAAC;AAEjE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,aAAyB,GAAG,MAAM,CAalF;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD"}
@@ -0,0 +1,48 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Richard Myers and contributors.
3
+ import { createHash } from "node:crypto";
4
+ /**
5
+ * Redact a matched marker string for safe display.
6
+ *
7
+ * Default mode `preview` returns `<first-3-chars>***<length-N>` for matches
8
+ * of length >= 4, else `[redacted]`. The literal match value never appears
9
+ * in output that flows to AI agent context (PostToolUse hook output, error
10
+ * messages, JSON payloads), because the literal match in recent context is
11
+ * exactly the recency-pressure failure mode the tool exists to prevent.
12
+ *
13
+ * `hash` mode returns the first 8 hex chars of SHA-256 + length, useful
14
+ * when distinct hits should be distinguishable from each other but the
15
+ * value itself remains opaque.
16
+ *
17
+ * `position-only` returns the constant `[redacted]`.
18
+ */
19
+ export function redactMatch(match, mode = "preview") {
20
+ // Use code-point iteration to avoid splitting surrogate pairs in the
21
+ // first 3 characters of multi-byte unicode markers.
22
+ const codePoints = Array.from(match);
23
+ if (mode === "position-only")
24
+ return "[redacted]";
25
+ if (mode === "hash") {
26
+ const h = createHash("sha256").update(match).digest("hex").slice(0, 8);
27
+ return `[hash:${h}:${codePoints.length}]`;
28
+ }
29
+ // preview
30
+ if (codePoints.length < 4)
31
+ return "[redacted]";
32
+ const head = codePoints.slice(0, 3).join("");
33
+ return `${head}***${codePoints.length}`;
34
+ }
35
+ /**
36
+ * Pass-through; explicit "this is the literal".
37
+ *
38
+ * Should ONLY be called when the user has explicitly opted in via the
39
+ * `--verbose` CLI flag. Hooks must never pass through this function.
40
+ *
41
+ * The previous `REPO_AEGIS_REVEAL_MATCHES` env-var was removed: env
42
+ * vars propagate to subprocess hooks unintentionally and could cause
43
+ * literal markers to flow into AI tool-result context.
44
+ */
45
+ export function revealMatch(match) {
46
+ return match;
47
+ }
48
+ //# sourceMappingURL=redaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.js","sourceRoot":"","sources":["../src/redaction.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,qDAAqD;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,OAAsB,SAAS;IACxE,qEAAqE;IACrE,oDAAoD;IACpD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,IAAI,KAAK,eAAe;QAAE,OAAO,YAAY,CAAC;IAClD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACvE,OAAO,SAAS,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;IAC5C,CAAC;IACD,UAAU;IACV,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,YAAY,CAAC;IAC/C,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7C,OAAO,GAAG,IAAI,MAAM,UAAU,CAAC,MAAM,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=redaction.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.test.d.ts","sourceRoot":"","sources":["../src/redaction.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,67 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Richard Myers and contributors.
3
+ import { describe, it } from "node:test";
4
+ import assert from "node:assert/strict";
5
+ import { redactMatch, revealMatch } from "./redaction.js";
6
+ describe("redactMatch", () => {
7
+ it("preview mode: shows first 3 chars + length for long strings", () => {
8
+ assert.equal(redactMatch("acme-corp", "preview"), "acm***9");
9
+ assert.equal(redactMatch("betaco", "preview"), "bet***6");
10
+ });
11
+ it("preview mode: redacts short strings entirely", () => {
12
+ assert.equal(redactMatch("abc", "preview"), "[redacted]");
13
+ assert.equal(redactMatch("ab", "preview"), "[redacted]");
14
+ assert.equal(redactMatch("", "preview"), "[redacted]");
15
+ });
16
+ it("preview mode is the default", () => {
17
+ assert.equal(redactMatch("acme-corp"), "acm***9");
18
+ });
19
+ it("hash mode: returns hex hash + length, deterministic", () => {
20
+ const a = redactMatch("acme-corp", "hash");
21
+ const b = redactMatch("acme-corp", "hash");
22
+ assert.equal(a, b);
23
+ assert.match(a, /^\[hash:[a-f0-9]{8}:9\]$/);
24
+ });
25
+ it("hash mode: distinct inputs produce distinct outputs", () => {
26
+ assert.notEqual(redactMatch("acme-corp", "hash"), redactMatch("betaco", "hash"));
27
+ });
28
+ it("position-only mode: always [redacted]", () => {
29
+ assert.equal(redactMatch("acme-corp", "position-only"), "[redacted]");
30
+ assert.equal(redactMatch("anything", "position-only"), "[redacted]");
31
+ });
32
+ it("never includes the literal in any redaction mode", () => {
33
+ const literal = "veryspecificcustomername";
34
+ const modes = ["preview", "hash", "position-only"];
35
+ for (const m of modes) {
36
+ const out = redactMatch(literal, m);
37
+ assert.ok(!out.includes(literal), `mode ${m} leaked literal`);
38
+ }
39
+ });
40
+ it("handles unicode without crashing", () => {
41
+ assert.ok(redactMatch("éâô-corp", "preview").length > 0);
42
+ assert.ok(redactMatch("中文corp", "hash").length > 0);
43
+ });
44
+ it("preview mode does not split surrogate pairs", () => {
45
+ // 🔒 is U+1F512, a surrogate pair in UTF-16. .slice(0,3) on the raw
46
+ // string would split the surrogate; code-point iteration must not.
47
+ const s = "🔒🔑🔓abcd";
48
+ const out = redactMatch(s, "preview");
49
+ // Length is 7 code points; preview returns the first 3 code points + ***N
50
+ assert.match(out, /^🔒🔑🔓\*\*\*7$/);
51
+ });
52
+ it("preview mode counts length in code points, not UTF-16 units", () => {
53
+ const s = "🔒🔑🔓"; // 3 code points, 6 UTF-16 units
54
+ assert.equal(redactMatch(s, "preview"), "[redacted]"); // length 3 < 4
55
+ });
56
+ });
57
+ describe("revealMatch", () => {
58
+ it("returns the literal", () => {
59
+ assert.equal(revealMatch("acme-corp"), "acme-corp");
60
+ });
61
+ it("is the only function that returns the literal", () => {
62
+ // Documentary test: enforces by convention that revealMatch is the
63
+ // single point of literal exposure in the redaction module.
64
+ assert.equal(typeof revealMatch, "function");
65
+ });
66
+ });
67
+ //# sourceMappingURL=redaction.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.test.js","sourceRoot":"","sources":["../src/redaction.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ export interface PatternValidationResult {
2
+ ok: boolean;
3
+ reason?: string;
4
+ }
5
+ export type RegexBackend = "re2" | "in-process" | "subprocess";
6
+ /**
7
+ * Test-only override. Forces {@link getRegexBackend} and
8
+ * {@link validatePattern} to use a specific backend regardless of which
9
+ * backends are installed. Pass `null` to clear. Production callers must
10
+ * not use this.
11
+ *
12
+ * @internal
13
+ */
14
+ export declare function setRegexBackendForTesting(backend: RegexBackend | null): void;
15
+ /**
16
+ * Report which regex backend repo-aegis is using for *additional*
17
+ * pattern-safety validation:
18
+ *
19
+ * - `"re2"`: the optional `re2` dependency is installed. Patterns that
20
+ * compile cleanly in re2 are provably safe from catastrophic
21
+ * backtracking (re2's hybrid NFA/DFA evaluator is linear-time by
22
+ * construction). For patterns that re2 can't parse (lookahead /
23
+ * look-behind / backreferences are unsupported in re2), validation
24
+ * falls back to the `"in-process"` time-budget heuristic.
25
+ * - `"in-process"`: re2 is unavailable; the in-process timer fires
26
+ * after the test completes (best-effort, may exceed budget).
27
+ * {@link validatePatterns} `{ strict: true }` upgrades to
28
+ * `"subprocess"` for the duration of that call.
29
+ * - `"subprocess"`: only returned by {@link getRegexBackend} when set
30
+ * via {@link setRegexBackendForTesting}; otherwise an internal
31
+ * detail of {@link validatePatterns}.
32
+ *
33
+ * Note: re2 affects *validation*, not the scanner's regex engine. The
34
+ * scanner still uses Node's native RegExp because the marker patterns
35
+ * may legitimately use lookahead constructs that re2 doesn't support.
36
+ */
37
+ export declare function getRegexBackend(): RegexBackend;
38
+ /**
39
+ * Validate a single regex pattern for use as a marker.
40
+ *
41
+ * Checks:
42
+ * 1. Compiles as a JavaScript RegExp without throwing.
43
+ * 2. Length <= 2048 chars.
44
+ * 3. Backtracking-bound test against `'a'.repeat(1000)` completes within 100ms.
45
+ * Catastrophic-backtracking patterns (e.g., `(a+)+$`) hang here and are
46
+ * rejected as ReDoS-suspected.
47
+ *
48
+ * Run at `render` time; bad patterns must not reach the hot path of `check`.
49
+ *
50
+ * @internal Prefer {@link validatePatterns} (which can run strict,
51
+ * subprocess-backed validation that is preemptable on catastrophic
52
+ * backtracking). This single-pattern, in-process helper is exposed for
53
+ * intra-repo callers that already pre-validate adversary-trust boundaries
54
+ * but is not part of the supported public API.
55
+ */
56
+ export declare function validatePattern(pattern: string): PatternValidationResult;
57
+ export interface ValidatePatternsOptions {
58
+ /**
59
+ * If true, run the backtracking-bound test in a subprocess that can be
60
+ * preemptively killed on timeout. Catches catastrophic-backtracking
61
+ * patterns that the in-process timer can only detect after-the-fact.
62
+ * Adds ~50-200ms of process-spawn overhead for the whole batch.
63
+ * Default: false (use the in-process timer).
64
+ */
65
+ strict?: boolean;
66
+ }
67
+ /**
68
+ * Validate a list of patterns. Returns split valid/invalid.
69
+ *
70
+ * With `strict: true`, runs the backtracking-bound check in a subprocess
71
+ * that can be preemptively killed if any pattern hangs the regex engine.
72
+ * Recommended for `render` and other one-time-cost paths; not for the
73
+ * per-scan hot path.
74
+ */
75
+ export declare function validatePatterns(patterns: string[], opts?: ValidatePatternsOptions): {
76
+ valid: string[];
77
+ invalid: {
78
+ pattern: string;
79
+ reason: string;
80
+ }[];
81
+ };
82
+ /**
83
+ * Validate that a combined alternation regex is within the size cap.
84
+ * Used by render and the deny-set computation as a safety net.
85
+ */
86
+ export declare function validateCombinedSize(combined: string): PatternValidationResult;
87
+ //# sourceMappingURL=regex-safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex-safety.d.ts","sourceRoot":"","sources":["../src/regex-safety.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,YAAY,GAAG,YAAY,CAAC;AA+B/D;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI,CAE5E;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAG9C;AAQD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,uBAAuB,CA2CxE;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,GAAE,uBAA4B,GACjC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAYrE;AA+GD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,uBAAuB,CAQ9E"}