@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
package/dist/render.js ADDED
@@ -0,0 +1,182 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Richard Myers and contributors.
3
+ import { mkdirSync, writeFileSync, readdirSync, unlinkSync, chmodSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { markersDir as defaultMarkersDir, flatMarkersPath as defaultFlatMarkersPath, repoAegisHome, } from "./paths.js";
6
+ import { isActive } from "./registry.js";
7
+ import { ALWAYS_FILE_STEM } from "./deny-set.js";
8
+ import { validatePatterns } from "./regex-safety.js";
9
+ import { PatternValidationError } from "./exceptions.js";
10
+ /**
11
+ * Format version of marker files written by {@link renderMarkers}. Emitted
12
+ * as the second header line (`; repo-aegis-marker-format: <N>`) of every
13
+ * generated marker file. The deny-set parser ignores `;`-comment lines, so
14
+ * older readers tolerate the field; future readers can branch on it. Per
15
+ * design B14: writers must never lower this version.
16
+ */
17
+ export const MARKER_FORMAT_VERSION = 1;
18
+ /**
19
+ * Generate per-engagement marker files from the registry.
20
+ *
21
+ * Behaviour:
22
+ * 1. Validate every pattern across all engagements + alwaysBlock. If any
23
+ * fail validation, throw `PatternValidationError` and write nothing.
24
+ * 2. Write `markers/_always.txt` from `reg.alwaysBlock`.
25
+ * 3. For each engagement where `isActive(e, retentionMonths)` is true,
26
+ * write `markers/<id>.txt`.
27
+ * 4. Compare existing marker files against the new set; delete files
28
+ * whose stem is not in the new set.
29
+ * 5. Write the flat union `markers.txt` for back-compat.
30
+ *
31
+ * All files are written with mode 0600. The markers directory is created
32
+ * with mode 0700.
33
+ */
34
+ export function renderMarkers(reg, opts = {}) {
35
+ const dir = opts.markersDir ?? defaultMarkersDir();
36
+ const flatPath = opts.flatPath ?? defaultFlatMarkersPath();
37
+ const retentionMonths = opts.retentionMonths ?? 12;
38
+ const dryRun = opts.dryRun ?? false;
39
+ const doValidate = opts.validatePatterns ?? true;
40
+ const invalidPatterns = [];
41
+ if (doValidate) {
42
+ // Strict mode: subprocess-backed validation that can be preemptively
43
+ // killed on catastrophic-backtracking patterns. Render is a manual,
44
+ // infrequent operation; the ~50-200ms spawn overhead is acceptable.
45
+ for (const e of reg.engagements) {
46
+ const r = validatePatterns(e.markers, { strict: true });
47
+ for (const inv of r.invalid) {
48
+ invalidPatterns.push({ engagementId: e.id, pattern: inv.pattern, reason: inv.reason });
49
+ }
50
+ }
51
+ const alwaysR = validatePatterns(reg.alwaysBlock, { strict: true });
52
+ for (const inv of alwaysR.invalid) {
53
+ invalidPatterns.push({
54
+ engagementId: ALWAYS_FILE_STEM,
55
+ pattern: inv.pattern,
56
+ reason: inv.reason,
57
+ });
58
+ }
59
+ if (invalidPatterns.length > 0) {
60
+ throw new PatternValidationError(invalidPatterns.map(p => ({
61
+ pattern: p.pattern,
62
+ reason: p.reason,
63
+ engagementId: p.engagementId,
64
+ })));
65
+ }
66
+ }
67
+ const written = [];
68
+ const targetStems = new Set([ALWAYS_FILE_STEM]);
69
+ // Always-block file (even if alwaysBlock is empty: ensures the file exists,
70
+ // simplifying downstream "compute deny set" logic).
71
+ if (!dryRun) {
72
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
73
+ try {
74
+ chmodSync(dir, 0o700);
75
+ }
76
+ catch {
77
+ /* permission may be platform-restricted */
78
+ }
79
+ }
80
+ const alwaysPath = join(dir, `${ALWAYS_FILE_STEM}.txt`);
81
+ if (!dryRun)
82
+ writeMarkerFile(alwaysPath, ALWAYS_FILE_STEM, reg.alwaysBlock);
83
+ written.push({
84
+ path: alwaysPath,
85
+ engagementId: ALWAYS_FILE_STEM,
86
+ patternCount: reg.alwaysBlock.length,
87
+ });
88
+ for (const e of reg.engagements) {
89
+ if (!isActive(e, retentionMonths))
90
+ continue;
91
+ targetStems.add(e.id);
92
+ const path = join(dir, `${e.id}.txt`);
93
+ if (!dryRun)
94
+ writeMarkerFile(path, e.id, e.markers, e.name);
95
+ written.push({ path, engagementId: e.id, patternCount: e.markers.length });
96
+ }
97
+ // Remove stale marker files whose stem is no longer in the target set.
98
+ let existing = [];
99
+ try {
100
+ existing = readdirSync(dir).filter(f => f.endsWith(".txt"));
101
+ }
102
+ catch {
103
+ /* dir may not exist yet in dry-run */
104
+ }
105
+ const removed = [];
106
+ for (const fname of existing) {
107
+ const stem = fname.replace(/\.txt$/, "");
108
+ if (!targetStems.has(stem)) {
109
+ const p = join(dir, fname);
110
+ if (!dryRun) {
111
+ try {
112
+ unlinkSync(p);
113
+ }
114
+ catch {
115
+ /* ignore */
116
+ }
117
+ }
118
+ removed.push(p);
119
+ }
120
+ }
121
+ // Flat union for back-compat.
122
+ let flatWritten = null;
123
+ if (!dryRun) {
124
+ const flatBody = buildFlatUnion(reg, retentionMonths);
125
+ writeFileSync(flatPath, flatBody, { mode: 0o600 });
126
+ try {
127
+ chmodSync(flatPath, 0o600);
128
+ }
129
+ catch {
130
+ /* ignore */
131
+ }
132
+ flatWritten = flatPath;
133
+ }
134
+ else {
135
+ flatWritten = flatPath;
136
+ }
137
+ // Best-effort: ensure home dir is mode 700 too.
138
+ if (!dryRun) {
139
+ try {
140
+ chmodSync(repoAegisHome(), 0o700);
141
+ }
142
+ catch {
143
+ /* ignore */
144
+ }
145
+ }
146
+ return { written, removed, flat: flatWritten, invalidPatterns };
147
+ }
148
+ function writeMarkerFile(path, engagementId, patterns, name) {
149
+ const header = `; generated by repo-aegis render — do not edit by hand\n` +
150
+ `; repo-aegis-marker-format: ${MARKER_FORMAT_VERSION}\n` +
151
+ `; engagement: ${engagementId}${name ? ` (${name})` : ""}\n`;
152
+ writeFileSync(path, header + patterns.join("\n") + (patterns.length > 0 ? "\n" : ""), {
153
+ mode: 0o600,
154
+ });
155
+ try {
156
+ chmodSync(path, 0o600);
157
+ }
158
+ catch {
159
+ /* ignore */
160
+ }
161
+ }
162
+ function buildFlatUnion(reg, retentionMonths) {
163
+ const parts = [
164
+ "; generated by repo-aegis render — back-compat union of all active engagements",
165
+ `; repo-aegis-marker-format: ${MARKER_FORMAT_VERSION}`,
166
+ "",
167
+ ];
168
+ if (reg.alwaysBlock.length > 0) {
169
+ parts.push(`; ${ALWAYS_FILE_STEM}`);
170
+ parts.push(...reg.alwaysBlock);
171
+ parts.push("");
172
+ }
173
+ for (const e of reg.engagements) {
174
+ if (!isActive(e, retentionMonths))
175
+ continue;
176
+ parts.push(`; ${e.id}${e.name ? ` (${e.name})` : ""}`);
177
+ parts.push(...e.markers);
178
+ parts.push("");
179
+ }
180
+ return parts.join("\n");
181
+ }
182
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=render.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.test.d.ts","sourceRoot":"","sources":["../src/render.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,152 @@
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, rmSync, readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
6
+ import { tmpdir } from "node:os";
7
+ import { join } from "node:path";
8
+ import { renderMarkers, MARKER_FORMAT_VERSION } from "./render.js";
9
+ import { computeDenySet } from "./deny-set.js";
10
+ import { PatternValidationError } from "./exceptions.js";
11
+ let tmp;
12
+ before(() => {
13
+ tmp = mkdtempSync(join(tmpdir(), "repo-aegis-render-"));
14
+ });
15
+ after(() => {
16
+ rmSync(tmp, { recursive: true, force: true });
17
+ });
18
+ describe("renderMarkers", () => {
19
+ it("writes _always.txt and per-engagement files", () => {
20
+ const dir = join(tmp, "case-1");
21
+ mkdirSync(dir, { recursive: true });
22
+ const r = renderMarkers({
23
+ engagements: [
24
+ { id: "customer-a", name: "A", markers: ["acme-corp"] },
25
+ { id: "customer-b", name: "B", markers: ["betaco"] },
26
+ ],
27
+ alwaysBlock: ["PROJECT-CODENAME-ALPHA"],
28
+ schemaVersion: 1,
29
+ }, { markersDir: dir, flatPath: join(dir, "..", "case-1.flat") });
30
+ assert.equal(r.invalidPatterns.length, 0);
31
+ assert.equal(r.written.length, 3); // _always + 2 engagements
32
+ assert.ok(existsSync(join(dir, "_always.txt")));
33
+ assert.ok(existsSync(join(dir, "customer-a.txt")));
34
+ assert.ok(existsSync(join(dir, "customer-b.txt")));
35
+ const aBody = readFileSync(join(dir, "customer-a.txt"), "utf8");
36
+ assert.match(aBody, /acme-corp/);
37
+ assert.match(aBody, /; engagement: customer-a/);
38
+ });
39
+ it("dry-run writes nothing", () => {
40
+ const dir = join(tmp, "case-dry");
41
+ const r = renderMarkers({
42
+ engagements: [{ id: "customer-a", name: "A", markers: ["acme"] }],
43
+ alwaysBlock: [],
44
+ schemaVersion: 1,
45
+ }, { markersDir: dir, dryRun: true, flatPath: join(dir, ".flat") });
46
+ assert.ok(!existsSync(dir));
47
+ assert.equal(r.written.length, 2); // _always + 1 engagement listed but not written
48
+ });
49
+ it("rejects bad patterns by throwing PatternValidationError", () => {
50
+ const dir = join(tmp, "case-bad");
51
+ mkdirSync(dir, { recursive: true });
52
+ assert.throws(() => renderMarkers({
53
+ engagements: [{ id: "customer-a", name: "A", markers: ["(unclosed"] }],
54
+ alwaysBlock: [],
55
+ schemaVersion: 1,
56
+ }, { markersDir: dir, flatPath: join(dir, ".flat") }), PatternValidationError);
57
+ // verify no files were written
58
+ assert.ok(!existsSync(join(dir, "customer-a.txt")));
59
+ });
60
+ it("removes stale per-engagement files no longer in registry", () => {
61
+ const dir = join(tmp, "case-stale");
62
+ mkdirSync(dir, { recursive: true });
63
+ // Pre-existing stale file
64
+ writeFileSync(join(dir, "old-engagement.txt"), "old-marker");
65
+ const r = renderMarkers({
66
+ engagements: [{ id: "customer-a", name: "A", markers: ["acme"] }],
67
+ alwaysBlock: [],
68
+ schemaVersion: 1,
69
+ }, { markersDir: dir, flatPath: join(dir, ".flat") });
70
+ assert.ok(r.removed.some(p => p.endsWith("old-engagement.txt")));
71
+ assert.ok(!existsSync(join(dir, "old-engagement.txt")));
72
+ });
73
+ it("excludes engagements past the retention window", () => {
74
+ const dir = join(tmp, "case-retention");
75
+ mkdirSync(dir, { recursive: true });
76
+ const r = renderMarkers({
77
+ engagements: [
78
+ { id: "active", name: "Active", markers: ["foo"] },
79
+ { id: "past-retention", name: "Past", ended: "2020-01-01", markers: ["bar"] },
80
+ ],
81
+ alwaysBlock: [],
82
+ schemaVersion: 1,
83
+ }, { markersDir: dir, retentionMonths: 12, flatPath: join(dir, ".flat") });
84
+ assert.ok(r.written.some(w => w.engagementId === "active"));
85
+ assert.ok(!r.written.some(w => w.engagementId === "past-retention"));
86
+ });
87
+ it("writes the flat union file", () => {
88
+ const dir = join(tmp, "case-flat");
89
+ mkdirSync(dir, { recursive: true });
90
+ const flat = join(tmp, "flat.txt");
91
+ renderMarkers({
92
+ engagements: [{ id: "a", name: "A", markers: ["acme"] }],
93
+ alwaysBlock: ["PROJECT-X"],
94
+ schemaVersion: 1,
95
+ }, { markersDir: dir, flatPath: flat });
96
+ assert.ok(existsSync(flat));
97
+ const body = readFileSync(flat, "utf8");
98
+ assert.match(body, /acme/);
99
+ assert.match(body, /PROJECT-X/);
100
+ });
101
+ it("writes the repo-aegis-marker-format header line as a comment", () => {
102
+ const dir = join(tmp, "case-format-header");
103
+ mkdirSync(dir, { recursive: true });
104
+ renderMarkers({
105
+ engagements: [{ id: "customer-a", name: "A", markers: ["foo-marker"] }],
106
+ alwaysBlock: ["GLOBAL-MARKER"],
107
+ schemaVersion: 1,
108
+ }, { markersDir: dir, flatPath: join(tmp, "case-format-header.flat") });
109
+ const expected = `; repo-aegis-marker-format: ${MARKER_FORMAT_VERSION}`;
110
+ // Per-engagement file: header line is present and is a `;`-comment.
111
+ const engBody = readFileSync(join(dir, "customer-a.txt"), "utf8");
112
+ assert.ok(engBody.includes(expected), `expected per-engagement file to contain "${expected}"; got:\n${engBody}`);
113
+ // _always file too.
114
+ const alwaysBody = readFileSync(join(dir, "_always.txt"), "utf8");
115
+ assert.ok(alwaysBody.includes(expected), `expected _always file to contain "${expected}"; got:\n${alwaysBody}`);
116
+ // Flat union too.
117
+ const flatBody = readFileSync(join(tmp, "case-format-header.flat"), "utf8");
118
+ assert.ok(flatBody.includes(expected), `expected flat union to contain "${expected}"; got:\n${flatBody}`);
119
+ // The header must be the SECOND line of the per-engagement file (after
120
+ // the "generated by" comment) so it's discoverable at the top.
121
+ const lines = engBody.split("\n");
122
+ assert.equal(lines[1], expected);
123
+ });
124
+ it("marker-format header is ignored by the deny-set parser (round-trip)", () => {
125
+ // Sanity check: the new header must not pollute the pattern set,
126
+ // because deny-set treats any line starting with `;` as a comment.
127
+ const dir = join(tmp, "case-format-roundtrip");
128
+ mkdirSync(dir, { recursive: true });
129
+ renderMarkers({
130
+ engagements: [{ id: "customer-a", name: "A", markers: ["foo-marker"] }],
131
+ alwaysBlock: [],
132
+ schemaVersion: 1,
133
+ }, { markersDir: dir, flatPath: join(tmp, "case-format-roundtrip.flat") });
134
+ const ds = computeDenySet({
135
+ cwd: dir,
136
+ isGitRepo: false,
137
+ class: "public-eligible",
138
+ classExplicit: true,
139
+ engagements: [],
140
+ }, { markersDir: dir });
141
+ assert.deepEqual(ds.patterns, ["foo-marker"]);
142
+ // No pattern in the deny set should be a comment line.
143
+ for (const p of ds.patterns) {
144
+ assert.ok(!p.startsWith(";"), `pattern leaked from header: ${p}`);
145
+ assert.ok(!p.includes("repo-aegis-marker-format"), `format header leaked into patterns: ${p}`);
146
+ }
147
+ });
148
+ it("exports MARKER_FORMAT_VERSION = 1", () => {
149
+ assert.equal(MARKER_FORMAT_VERSION, 1);
150
+ });
151
+ });
152
+ //# sourceMappingURL=render.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.test.js","sourceRoot":"","sources":["../src/render.test.ts"],"names":[],"mappings":"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"}
package/dist/repo.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ import { type RepoClassLiteral } from "./schemas.js";
2
+ export type RepoClass = RepoClassLiteral;
3
+ export declare const REPO_CLASSES: readonly RepoClass[];
4
+ export interface RepoConfig {
5
+ cwd: string;
6
+ isGitRepo: boolean;
7
+ class: RepoClass;
8
+ classExplicit: boolean;
9
+ engagements: string[];
10
+ /** True when class came from a checked-in `.repo-aegis.yml`. */
11
+ classFromOverride?: boolean;
12
+ /** True when engagements came from a checked-in `.repo-aegis.yml`. */
13
+ engagementsFromOverride?: boolean;
14
+ }
15
+ export interface RepoOverride {
16
+ class?: RepoClass;
17
+ engagements?: string[];
18
+ }
19
+ export declare const OVERRIDE_FILENAME = ".repo-aegis.yml";
20
+ export declare class RepoOverrideError extends Error {
21
+ readonly path: string;
22
+ readonly code = "REPO_OVERRIDE_PARSE_ERROR";
23
+ constructor(path: string, message: string);
24
+ }
25
+ export declare function readRepoConfig(cwd?: string): RepoConfig;
26
+ /**
27
+ * Idempotent add. Returns true if added, false if already present.
28
+ */
29
+ export declare function addEngagement(id: string, cwd?: string): boolean;
30
+ /**
31
+ * Idempotent multi-add. Returns the list of ids that were newly added.
32
+ */
33
+ export declare function addEngagements(ids: string[], cwd?: string): string[];
34
+ /**
35
+ * Returns true if removed, false if not present.
36
+ */
37
+ export declare function removeEngagement(id: string, cwd?: string): boolean;
38
+ export declare function setClass(cls: RepoClass, cwd?: string): void;
39
+ export declare function unsetClass(cwd?: string): void;
40
+ //# sourceMappingURL=repo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../src/repo.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,SAAS,GAAG,gBAAgB,CAAC;AAEzC,eAAO,MAAM,YAAY,EAAE,SAAS,SAAS,EAAwB,CAAC;AAEtE,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,SAAS,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,sEAAsE;IACtE,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,eAAO,MAAM,iBAAiB,oBAAoB,CAAC;AAEnD,qBAAa,iBAAkB,SAAQ,KAAK;aAEd,IAAI,EAAE,MAAM;IADxC,QAAQ,CAAC,IAAI,+BAA+B;gBAChB,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAG1D;AAsED,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,UAAU,CAgEtE;AAMD;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,OAAO,CAM9E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,GAAG,GAAE,MAAsB,GAAG,MAAM,EAAE,CAYnF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,OAAO,CAUjF;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,GAAE,MAAsB,GAAG,IAAI,CAI1E;AAED,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,IAAI,CAY5D"}
package/dist/repo.js ADDED
@@ -0,0 +1,214 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Richard Myers and contributors.
3
+ import { execFileSync } from "node:child_process";
4
+ import { existsSync, readFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { parse } from "yaml";
7
+ import { z } from "zod";
8
+ import { NotAGitRepoError } from "./exceptions.js";
9
+ import { repoOverrideSchema, REPO_CLASSES as REPO_CLASSES_SCHEMA, formatZodError, } from "./schemas.js";
10
+ export const REPO_CLASSES = REPO_CLASSES_SCHEMA;
11
+ export const OVERRIDE_FILENAME = ".repo-aegis.yml";
12
+ export class RepoOverrideError extends Error {
13
+ path;
14
+ code = "REPO_OVERRIDE_PARSE_ERROR";
15
+ constructor(path, message) {
16
+ super(`${path}: ${message}`);
17
+ this.path = path;
18
+ }
19
+ }
20
+ function loadOverride(cwd) {
21
+ // Look for `.repo-aegis.yml` at git toplevel; fall back to cwd if not in a
22
+ // git repo (so the override still works in scratch dirs).
23
+ let root = cwd;
24
+ try {
25
+ const top = execFileSync("git", ["rev-parse", "--show-toplevel"], {
26
+ cwd,
27
+ encoding: "utf8",
28
+ stdio: ["ignore", "pipe", "ignore"],
29
+ }).trim();
30
+ if (top)
31
+ root = top;
32
+ }
33
+ catch {
34
+ /* not a git repo; use cwd as root */
35
+ }
36
+ const path = join(root, OVERRIDE_FILENAME);
37
+ if (!existsSync(path))
38
+ return null;
39
+ let parsed;
40
+ try {
41
+ parsed = parse(readFileSync(path, "utf8"));
42
+ }
43
+ catch (err) {
44
+ throw new RepoOverrideError(path, `failed to parse YAML: ${err.message}`);
45
+ }
46
+ if (parsed === null || parsed === undefined) {
47
+ return { override: {}, path };
48
+ }
49
+ if (typeof parsed !== "object" || Array.isArray(parsed)) {
50
+ throw new RepoOverrideError(path, "must be a YAML mapping");
51
+ }
52
+ let validated;
53
+ try {
54
+ validated = repoOverrideSchema.parse(parsed);
55
+ }
56
+ catch (err) {
57
+ if (err instanceof z.ZodError) {
58
+ throw new RepoOverrideError(path, formatZodError(err, "override"));
59
+ }
60
+ throw err;
61
+ }
62
+ const out = {};
63
+ if (validated.class !== undefined)
64
+ out.class = validated.class;
65
+ if (validated.engagements !== undefined)
66
+ out.engagements = validated.engagements;
67
+ return { override: out, path };
68
+ }
69
+ function git(cwd, args) {
70
+ try {
71
+ const stdout = execFileSync("git", args, {
72
+ cwd,
73
+ encoding: "utf8",
74
+ stdio: ["ignore", "pipe", "ignore"],
75
+ }).trim();
76
+ return { ok: true, stdout };
77
+ }
78
+ catch {
79
+ return { ok: false, stdout: "" };
80
+ }
81
+ }
82
+ function isValidClass(s) {
83
+ return REPO_CLASSES.includes(s);
84
+ }
85
+ export function readRepoConfig(cwd = process.cwd()) {
86
+ const inside = git(cwd, ["rev-parse", "--is-inside-work-tree"]);
87
+ const isGitRepo = inside.ok && inside.stdout === "true";
88
+ // .repo-aegis.yml may exist even outside a git repo (scratch dir);
89
+ // load it either way. Throws RepoOverrideError on malformed YAML.
90
+ const overrideResult = loadOverride(cwd);
91
+ const override = overrideResult?.override ?? {};
92
+ if (!isGitRepo) {
93
+ return {
94
+ cwd,
95
+ isGitRepo: false,
96
+ class: override.class ?? "private-strict",
97
+ classExplicit: override.class !== undefined,
98
+ engagements: override.engagements ?? [],
99
+ ...(override.class !== undefined && { classFromOverride: true }),
100
+ ...(override.engagements !== undefined && { engagementsFromOverride: true }),
101
+ };
102
+ }
103
+ // Precedence: git config wins where set, .repo-aegis.yml provides
104
+ // the project-default fallback. This matches the .editorconfig
105
+ // model: the file in the repo declares intent; per-clone git
106
+ // config can override locally without changing the file.
107
+ const cls = git(cwd, ["config", "--get", "repo-aegis.class"]);
108
+ const eng = git(cwd, ["config", "--get-all", "repo-aegis.engagement"]);
109
+ const cfgClassSet = cls.ok && cls.stdout !== "";
110
+ const cfgEngagements = eng.ok && eng.stdout ? eng.stdout.split("\n").filter(Boolean) : [];
111
+ let classValue;
112
+ let classExplicit = false;
113
+ let classFromOverride = false;
114
+ if (cfgClassSet && isValidClass(cls.stdout)) {
115
+ classValue = cls.stdout;
116
+ classExplicit = true;
117
+ }
118
+ else if (override.class !== undefined) {
119
+ classValue = override.class;
120
+ classExplicit = true;
121
+ classFromOverride = true;
122
+ }
123
+ else {
124
+ classValue = "private-strict";
125
+ }
126
+ let engagements;
127
+ let engagementsFromOverride = false;
128
+ if (cfgEngagements.length > 0) {
129
+ engagements = cfgEngagements;
130
+ }
131
+ else if (override.engagements !== undefined) {
132
+ engagements = override.engagements;
133
+ engagementsFromOverride = true;
134
+ }
135
+ else {
136
+ engagements = [];
137
+ }
138
+ return {
139
+ cwd,
140
+ isGitRepo: true,
141
+ class: classValue,
142
+ classExplicit,
143
+ engagements,
144
+ ...(classFromOverride && { classFromOverride: true }),
145
+ ...(engagementsFromOverride && { engagementsFromOverride: true }),
146
+ };
147
+ }
148
+ function escapeRegex(s) {
149
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
150
+ }
151
+ /**
152
+ * Idempotent add. Returns true if added, false if already present.
153
+ */
154
+ export function addEngagement(id, cwd = process.cwd()) {
155
+ const cfg = readRepoConfig(cwd);
156
+ if (!cfg.isGitRepo)
157
+ throw new NotAGitRepoError();
158
+ if (cfg.engagements.includes(id))
159
+ return false;
160
+ execFileSync("git", ["config", "--add", "repo-aegis.engagement", id], { cwd });
161
+ return true;
162
+ }
163
+ /**
164
+ * Idempotent multi-add. Returns the list of ids that were newly added.
165
+ */
166
+ export function addEngagements(ids, cwd = process.cwd()) {
167
+ const cfg = readRepoConfig(cwd);
168
+ if (!cfg.isGitRepo)
169
+ throw new NotAGitRepoError();
170
+ const existing = new Set(cfg.engagements);
171
+ const added = [];
172
+ for (const id of ids) {
173
+ if (existing.has(id))
174
+ continue;
175
+ execFileSync("git", ["config", "--add", "repo-aegis.engagement", id], { cwd });
176
+ existing.add(id);
177
+ added.push(id);
178
+ }
179
+ return added;
180
+ }
181
+ /**
182
+ * Returns true if removed, false if not present.
183
+ */
184
+ export function removeEngagement(id, cwd = process.cwd()) {
185
+ const cfg = readRepoConfig(cwd);
186
+ if (!cfg.isGitRepo)
187
+ throw new NotAGitRepoError();
188
+ if (!cfg.engagements.includes(id))
189
+ return false;
190
+ execFileSync("git", ["config", "--unset-all", "repo-aegis.engagement", `^${escapeRegex(id)}$`], { cwd });
191
+ return true;
192
+ }
193
+ export function setClass(cls, cwd = process.cwd()) {
194
+ const cfg = readRepoConfig(cwd);
195
+ if (!cfg.isGitRepo)
196
+ throw new NotAGitRepoError();
197
+ execFileSync("git", ["config", "repo-aegis.class", cls], { cwd });
198
+ }
199
+ export function unsetClass(cwd = process.cwd()) {
200
+ const cfg = readRepoConfig(cwd);
201
+ if (!cfg.isGitRepo)
202
+ throw new NotAGitRepoError();
203
+ // --unset is idempotent enough; ignore "no value found" errors.
204
+ try {
205
+ execFileSync("git", ["config", "--unset", "repo-aegis.class"], {
206
+ cwd,
207
+ stdio: ["ignore", "ignore", "ignore"],
208
+ });
209
+ }
210
+ catch {
211
+ /* not set; nothing to do */
212
+ }
213
+ }
214
+ //# sourceMappingURL=repo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.js","sourceRoot":"","sources":["../src/repo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=repo.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.test.d.ts","sourceRoot":"","sources":["../src/repo.test.ts"],"names":[],"mappings":""}