@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.
- package/dist/age.d.ts +32 -0
- package/dist/age.d.ts.map +1 -0
- package/dist/age.js +98 -0
- package/dist/age.js.map +1 -0
- package/dist/audit-log.d.ts +50 -0
- package/dist/audit-log.d.ts.map +1 -0
- package/dist/audit-log.js +183 -0
- package/dist/audit-log.js.map +1 -0
- package/dist/audit-log.test.d.ts +2 -0
- package/dist/audit-log.test.d.ts.map +1 -0
- package/dist/audit-log.test.js +181 -0
- package/dist/audit-log.test.js.map +1 -0
- package/dist/deny-set.d.ts +43 -0
- package/dist/deny-set.d.ts.map +1 -0
- package/dist/deny-set.js +165 -0
- package/dist/deny-set.js.map +1 -0
- package/dist/deny-set.test.d.ts +2 -0
- package/dist/deny-set.test.d.ts.map +1 -0
- package/dist/deny-set.test.js +155 -0
- package/dist/deny-set.test.js.map +1 -0
- package/dist/exceptions.d.ts +96 -0
- package/dist/exceptions.d.ts.map +1 -0
- package/dist/exceptions.js +143 -0
- package/dist/exceptions.js.map +1 -0
- package/dist/exit-codes.d.ts +4 -0
- package/dist/exit-codes.d.ts.map +1 -0
- package/dist/exit-codes.js +6 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/first-touch.d.ts +57 -0
- package/dist/first-touch.d.ts.map +1 -0
- package/dist/first-touch.js +112 -0
- package/dist/first-touch.js.map +1 -0
- package/dist/import-graph.test.d.ts +2 -0
- package/dist/import-graph.test.d.ts.map +1 -0
- package/dist/import-graph.test.js +210 -0
- package/dist/import-graph.test.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +68 -0
- package/dist/index.js.map +1 -0
- package/dist/lock.d.ts +22 -0
- package/dist/lock.d.ts.map +1 -0
- package/dist/lock.js +86 -0
- package/dist/lock.js.map +1 -0
- package/dist/lock.test.d.ts +2 -0
- package/dist/lock.test.d.ts.map +1 -0
- package/dist/lock.test.js +125 -0
- package/dist/lock.test.js.map +1 -0
- package/dist/paths.d.ts +22 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +46 -0
- package/dist/paths.js.map +1 -0
- package/dist/paths.test.d.ts +2 -0
- package/dist/paths.test.d.ts.map +1 -0
- package/dist/paths.test.js +78 -0
- package/dist/paths.test.js.map +1 -0
- package/dist/redaction.d.ts +29 -0
- package/dist/redaction.d.ts.map +1 -0
- package/dist/redaction.js +48 -0
- package/dist/redaction.js.map +1 -0
- package/dist/redaction.test.d.ts +2 -0
- package/dist/redaction.test.d.ts.map +1 -0
- package/dist/redaction.test.js +67 -0
- package/dist/redaction.test.js.map +1 -0
- package/dist/regex-safety.d.ts +87 -0
- package/dist/regex-safety.d.ts.map +1 -0
- package/dist/regex-safety.js +322 -0
- package/dist/regex-safety.js.map +1 -0
- package/dist/regex-safety.test.d.ts +2 -0
- package/dist/regex-safety.test.d.ts.map +1 -0
- package/dist/regex-safety.test.js +149 -0
- package/dist/regex-safety.test.js.map +1 -0
- package/dist/registry-mutate.d.ts +35 -0
- package/dist/registry-mutate.d.ts.map +1 -0
- package/dist/registry-mutate.js +149 -0
- package/dist/registry-mutate.js.map +1 -0
- package/dist/registry-mutate.test.d.ts +2 -0
- package/dist/registry-mutate.test.d.ts.map +1 -0
- package/dist/registry-mutate.test.js +96 -0
- package/dist/registry-mutate.test.js.map +1 -0
- package/dist/registry.d.ts +64 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +120 -0
- package/dist/registry.js.map +1 -0
- package/dist/registry.test.d.ts +2 -0
- package/dist/registry.test.d.ts.map +1 -0
- package/dist/registry.test.js +316 -0
- package/dist/registry.test.js.map +1 -0
- package/dist/remote-url.d.ts +18 -0
- package/dist/remote-url.d.ts.map +1 -0
- package/dist/remote-url.js +66 -0
- package/dist/remote-url.js.map +1 -0
- package/dist/remote-url.test.d.ts +2 -0
- package/dist/remote-url.test.d.ts.map +1 -0
- package/dist/remote-url.test.js +116 -0
- package/dist/remote-url.test.js.map +1 -0
- package/dist/render.d.ts +54 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +182 -0
- package/dist/render.js.map +1 -0
- package/dist/render.test.d.ts +2 -0
- package/dist/render.test.d.ts.map +1 -0
- package/dist/render.test.js +152 -0
- package/dist/render.test.js.map +1 -0
- package/dist/repo.d.ts +40 -0
- package/dist/repo.d.ts.map +1 -0
- package/dist/repo.js +214 -0
- package/dist/repo.js.map +1 -0
- package/dist/repo.test.d.ts +2 -0
- package/dist/repo.test.d.ts.map +1 -0
- package/dist/repo.test.js +234 -0
- package/dist/repo.test.js.map +1 -0
- package/dist/scan.d.ts +103 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +436 -0
- package/dist/scan.js.map +1 -0
- package/dist/scan.test.d.ts +2 -0
- package/dist/scan.test.d.ts.map +1 -0
- package/dist/scan.test.js +437 -0
- package/dist/scan.test.js.map +1 -0
- package/dist/schemas.d.ts +50 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +190 -0
- package/dist/schemas.js.map +1 -0
- package/dist/secret-markers.d.ts +34 -0
- package/dist/secret-markers.d.ts.map +1 -0
- package/dist/secret-markers.js +118 -0
- package/dist/secret-markers.js.map +1 -0
- package/dist/secret-markers.test.d.ts +2 -0
- package/dist/secret-markers.test.d.ts.map +1 -0
- package/dist/secret-markers.test.js +154 -0
- package/dist/secret-markers.test.js.map +1 -0
- package/dist/trust-boundary.d.ts +33 -0
- package/dist/trust-boundary.d.ts.map +1 -0
- package/dist/trust-boundary.js +77 -0
- package/dist/trust-boundary.js.map +1 -0
- package/dist/trust-boundary.test.d.ts +2 -0
- package/dist/trust-boundary.test.d.ts.map +1 -0
- package/dist/trust-boundary.test.js +170 -0
- package/dist/trust-boundary.test.js.map +1 -0
- package/dist/types.d.ts +47 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/working-tree.d.ts +38 -0
- package/dist/working-tree.d.ts.map +1 -0
- package/dist/working-tree.js +133 -0
- package/dist/working-tree.js.map +1 -0
- package/dist/working-tree.test.d.ts +2 -0
- package/dist/working-tree.test.d.ts.map +1 -0
- package/dist/working-tree.test.js +162 -0
- package/dist/working-tree.test.js.map +1 -0
- package/package.json +40 -0
- package/src/age.ts +113 -0
- package/src/audit-log.test.ts +222 -0
- package/src/audit-log.ts +215 -0
- package/src/deny-set.test.ts +208 -0
- package/src/deny-set.ts +231 -0
- package/src/exceptions.ts +134 -0
- package/src/exit-codes.ts +5 -0
- package/src/first-touch.ts +172 -0
- package/src/import-graph.test.ts +239 -0
- package/src/index.ts +191 -0
- package/src/lock.test.ts +151 -0
- package/src/lock.ts +88 -0
- package/src/paths.test.ts +94 -0
- package/src/paths.ts +55 -0
- package/src/redaction.test.ts +81 -0
- package/src/redaction.ts +49 -0
- package/src/regex-safety.test.ts +194 -0
- package/src/regex-safety.ts +349 -0
- package/src/registry-mutate.test.ts +134 -0
- package/src/registry-mutate.ts +185 -0
- package/src/registry.test.ts +460 -0
- package/src/registry.ts +178 -0
- package/src/remote-url.test.ts +121 -0
- package/src/remote-url.ts +78 -0
- package/src/render.test.ts +206 -0
- package/src/render.ts +215 -0
- package/src/repo.test.ts +275 -0
- package/src/repo.ts +245 -0
- package/src/scan.test.ts +580 -0
- package/src/scan.ts +531 -0
- package/src/schemas.ts +207 -0
- package/src/secret-markers.test.ts +183 -0
- package/src/secret-markers.ts +145 -0
- package/src/trust-boundary.test.ts +198 -0
- package/src/trust-boundary.ts +98 -0
- package/src/types.ts +55 -0
- package/src/working-tree.test.ts +193 -0
- package/src/working-tree.ts +130 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust-boundary.js","sourceRoot":"","sources":["../src/trust-boundary.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,qDAAqD;AACrD,EAAE;AACF,kEAAkE;AAClE,EAAE;AACF,oEAAoE;AACpE,uDAAuD;AACvD,EAAE;AACF,+DAA+D;AAC/D,mBAAmB;AACnB,mDAAmD;AACnD,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,sEAAsE;AACtE,oEAAoE;AACpE,yEAAyE;AAEzE,OAAO,EAAE,cAAc,EAAkB,MAAM,WAAW,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAiBjD;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,WAAmB,EACnB,QAAkB;IAElB,MAAM,IAAI,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,2BAA2B;IAC3B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC;QAC3D,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;YACvC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,kEAAkE;IAClE,kEAAkE;IAClE,gBAAgB;IAChB,IAAI,IAAI,CAAC,KAAK,KAAK,iBAAiB,EAAE,CAAC;QACrC,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC;YAC9C,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,IAAI,kBAAkB,GAAG,KAAK,CAAC;IAC/B,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,SAAS,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;QAC5C,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACpB,kBAAkB,GAAG,IAAI,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI;QACJ,kBAAkB;QAClB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,aAAa,EAAE,IAAI,CAAC,aAAa;KAClC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,CAAgB,EAAE,CAAgB;IACvE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACzD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI;QAAE,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IACvD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust-boundary.test.d.ts","sourceRoot":"","sources":["../src/trust-boundary.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,170 @@
|
|
|
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, rmSync, realpathSync } from "node:fs";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { computeTrustBoundary, trustBoundariesOverlap, } from "./trust-boundary.js";
|
|
10
|
+
let tmp;
|
|
11
|
+
before(() => {
|
|
12
|
+
tmp = realpathSync(mkdtempSync(join(tmpdir(), "repo-aegis-tb-")));
|
|
13
|
+
});
|
|
14
|
+
after(() => {
|
|
15
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
16
|
+
});
|
|
17
|
+
function makeRepo(name, opts = {}) {
|
|
18
|
+
const dir = join(tmp, name);
|
|
19
|
+
mkdirSync(dir);
|
|
20
|
+
execFileSync("git", ["init", "-q", "--initial-branch=main", dir], { stdio: "ignore" });
|
|
21
|
+
if (opts.remote) {
|
|
22
|
+
execFileSync("git", ["-C", dir, "config", "remote.origin.url", opts.remote], {
|
|
23
|
+
stdio: "ignore",
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (opts.class) {
|
|
27
|
+
execFileSync("git", ["-C", dir, "config", "repo-aegis.class", opts.class], {
|
|
28
|
+
stdio: "ignore",
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
for (const eng of opts.engagements ?? []) {
|
|
32
|
+
execFileSync("git", ["-C", dir, "config", "--add", "repo-aegis.engagement", eng], {
|
|
33
|
+
stdio: "ignore",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return dir;
|
|
37
|
+
}
|
|
38
|
+
function makeRegistry(engagements, personalOrgs = []) {
|
|
39
|
+
return {
|
|
40
|
+
engagements,
|
|
41
|
+
alwaysBlock: [],
|
|
42
|
+
personalOrgs,
|
|
43
|
+
schemaVersion: 2,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const E_ALPHA = {
|
|
47
|
+
id: "alpha",
|
|
48
|
+
name: "Alpha",
|
|
49
|
+
markers: [],
|
|
50
|
+
githubOrgs: ["alpha-org", "alpha-mirror"],
|
|
51
|
+
};
|
|
52
|
+
const E_BETA = {
|
|
53
|
+
id: "beta",
|
|
54
|
+
name: "Beta",
|
|
55
|
+
markers: [],
|
|
56
|
+
githubOrgs: ["beta-org"],
|
|
57
|
+
};
|
|
58
|
+
describe("computeTrustBoundary", () => {
|
|
59
|
+
it("derives orgs from a single allow'd engagement", () => {
|
|
60
|
+
const repo = makeRepo("ct-cust", {
|
|
61
|
+
remote: "git@github.com:alpha-org/foo.git",
|
|
62
|
+
class: "customer-coupled",
|
|
63
|
+
engagements: ["alpha"],
|
|
64
|
+
});
|
|
65
|
+
const reg = makeRegistry([E_ALPHA, E_BETA]);
|
|
66
|
+
const tb = computeTrustBoundary(repo, reg);
|
|
67
|
+
assert.deepEqual([...tb.orgs].sort(), ["alpha-mirror", "alpha-org"]);
|
|
68
|
+
assert.equal(tb.fromRemoteFallback, false);
|
|
69
|
+
assert.equal(tb.class, "customer-coupled");
|
|
70
|
+
});
|
|
71
|
+
it("union'd orgs across multiple allow'd engagements", () => {
|
|
72
|
+
const repo = makeRepo("ct-multi", {
|
|
73
|
+
remote: "git@github.com:alpha-org/x.git",
|
|
74
|
+
class: "customer-coupled",
|
|
75
|
+
engagements: ["alpha", "beta"],
|
|
76
|
+
});
|
|
77
|
+
const reg = makeRegistry([E_ALPHA, E_BETA]);
|
|
78
|
+
const tb = computeTrustBoundary(repo, reg);
|
|
79
|
+
assert.deepEqual([...tb.orgs].sort(), ["alpha-mirror", "alpha-org", "beta-org"]);
|
|
80
|
+
});
|
|
81
|
+
it("public-eligible picks up personalOrgs", () => {
|
|
82
|
+
const repo = makeRepo("ct-pub", {
|
|
83
|
+
remote: "git@github.com:de-otio/foo.git",
|
|
84
|
+
class: "public-eligible",
|
|
85
|
+
});
|
|
86
|
+
const reg = makeRegistry([E_ALPHA], ["de-otio", "personal2"]);
|
|
87
|
+
const tb = computeTrustBoundary(repo, reg);
|
|
88
|
+
assert.deepEqual([...tb.orgs].sort(), ["de-otio", "personal2"]);
|
|
89
|
+
assert.equal(tb.fromRemoteFallback, false);
|
|
90
|
+
});
|
|
91
|
+
it("falls back to the remote when classification is empty", () => {
|
|
92
|
+
const repo = makeRepo("ct-fallback", {
|
|
93
|
+
remote: "git@github.com:de-otio/foo.git",
|
|
94
|
+
// No class, no engagements: defaults to private-strict.
|
|
95
|
+
});
|
|
96
|
+
const reg = makeRegistry([E_ALPHA]);
|
|
97
|
+
const tb = computeTrustBoundary(repo, reg);
|
|
98
|
+
assert.deepEqual([...tb.orgs], ["de-otio"]);
|
|
99
|
+
assert.equal(tb.fromRemoteFallback, true);
|
|
100
|
+
assert.equal(tb.class, "private-strict");
|
|
101
|
+
assert.equal(tb.classExplicit, false);
|
|
102
|
+
});
|
|
103
|
+
it("returns an empty set when there's no remote and no classification", () => {
|
|
104
|
+
const repo = makeRepo("ct-bare");
|
|
105
|
+
const reg = makeRegistry([E_ALPHA]);
|
|
106
|
+
const tb = computeTrustBoundary(repo, reg);
|
|
107
|
+
assert.equal(tb.orgs.size, 0);
|
|
108
|
+
assert.equal(tb.fromRemoteFallback, false);
|
|
109
|
+
});
|
|
110
|
+
it("classification beats remote (forks)", () => {
|
|
111
|
+
// Repo's remote is the customer org but it's allow'd into the
|
|
112
|
+
// personal world (e.g. an internal mirror of an upstream).
|
|
113
|
+
const repo = makeRepo("ct-fork", {
|
|
114
|
+
remote: "git@github.com:alpha-org/x.git",
|
|
115
|
+
class: "public-eligible",
|
|
116
|
+
});
|
|
117
|
+
const reg = makeRegistry([E_ALPHA], ["de-otio"]);
|
|
118
|
+
const tb = computeTrustBoundary(repo, reg);
|
|
119
|
+
assert.deepEqual([...tb.orgs], ["de-otio"]);
|
|
120
|
+
assert.equal(tb.fromRemoteFallback, false);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
describe("trustBoundariesOverlap", () => {
|
|
124
|
+
const reg = makeRegistry([E_ALPHA, E_BETA], ["de-otio"]);
|
|
125
|
+
it("returns true when both repos sit in the same engagement orgs", () => {
|
|
126
|
+
const a = makeRepo("ov-a", { class: "customer-coupled", engagements: ["alpha"] });
|
|
127
|
+
const b = makeRepo("ov-b", { class: "customer-coupled", engagements: ["alpha"] });
|
|
128
|
+
assert.ok(trustBoundariesOverlap(computeTrustBoundary(a, reg), computeTrustBoundary(b, reg)));
|
|
129
|
+
});
|
|
130
|
+
it("returns true when repos share at least one githubOrg via different engagements", () => {
|
|
131
|
+
// Engagement γ shares one org with α
|
|
132
|
+
const E_GAMMA = {
|
|
133
|
+
id: "gamma",
|
|
134
|
+
name: "Gamma",
|
|
135
|
+
markers: [],
|
|
136
|
+
githubOrgs: ["alpha-mirror", "gamma-org"],
|
|
137
|
+
};
|
|
138
|
+
const reg2 = makeRegistry([E_ALPHA, E_GAMMA]);
|
|
139
|
+
const a = makeRepo("ov-shared-a", { class: "customer-coupled", engagements: ["alpha"] });
|
|
140
|
+
const b = makeRepo("ov-shared-b", { class: "customer-coupled", engagements: ["gamma"] });
|
|
141
|
+
assert.ok(trustBoundariesOverlap(computeTrustBoundary(a, reg2), computeTrustBoundary(b, reg2)));
|
|
142
|
+
});
|
|
143
|
+
it("returns false when engagements have disjoint orgs", () => {
|
|
144
|
+
const a = makeRepo("ov-x", { class: "customer-coupled", engagements: ["alpha"] });
|
|
145
|
+
const b = makeRepo("ov-y", { class: "customer-coupled", engagements: ["beta"] });
|
|
146
|
+
assert.ok(!trustBoundariesOverlap(computeTrustBoundary(a, reg), computeTrustBoundary(b, reg)));
|
|
147
|
+
});
|
|
148
|
+
it("returns false when one side is personal and the other customer-coupled", () => {
|
|
149
|
+
const a = makeRepo("ov-pers", {
|
|
150
|
+
remote: "git@github.com:de-otio/x.git",
|
|
151
|
+
class: "public-eligible",
|
|
152
|
+
});
|
|
153
|
+
const b = makeRepo("ov-cust", {
|
|
154
|
+
class: "customer-coupled",
|
|
155
|
+
engagements: ["alpha"],
|
|
156
|
+
});
|
|
157
|
+
assert.ok(!trustBoundariesOverlap(computeTrustBoundary(a, reg), computeTrustBoundary(b, reg)));
|
|
158
|
+
});
|
|
159
|
+
it("returns false when both sides have empty boundaries", () => {
|
|
160
|
+
const a = makeRepo("ov-empty-a");
|
|
161
|
+
const b = makeRepo("ov-empty-b");
|
|
162
|
+
assert.ok(!trustBoundariesOverlap(computeTrustBoundary(a, reg), computeTrustBoundary(b, reg)));
|
|
163
|
+
});
|
|
164
|
+
it("matches via remote fallback when neither repo is classified but they share an org", () => {
|
|
165
|
+
const a = makeRepo("ov-r-a", { remote: "git@github.com:de-otio/x.git" });
|
|
166
|
+
const b = makeRepo("ov-r-b", { remote: "git@github.com:de-otio/y.git" });
|
|
167
|
+
assert.ok(trustBoundariesOverlap(computeTrustBoundary(a, reg), computeTrustBoundary(b, reg)));
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
//# sourceMappingURL=trust-boundary.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust-boundary.test.js","sourceRoot":"","sources":["../src/trust-boundary.test.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type { Engagement, Registry, ResolveResult } from "./registry.js";
|
|
2
|
+
export type { RepoClass, RepoConfig } from "./repo.js";
|
|
3
|
+
export type { DenySet, DenySetFile, DenySetOptions } from "./deny-set.js";
|
|
4
|
+
export type { ScanHit, SkippedFile, ScanOptions } from "./scan.js";
|
|
5
|
+
export type { RenderOptions, RenderedFile, RenderResult } from "./render.js";
|
|
6
|
+
export type { PatternValidationResult } from "./regex-safety.js";
|
|
7
|
+
export type { RedactionMode } from "./redaction.js";
|
|
8
|
+
/**
|
|
9
|
+
* Canonical JSON shape for a repo across every CLI subcommand's output.
|
|
10
|
+
* Consumers of repo-aegis (other tools, AI agents) parse this once and
|
|
11
|
+
* reuse across allow/deny/status/check.
|
|
12
|
+
*
|
|
13
|
+
* `engagements` is **deliberately a list of bare ids** (`string[]`), not
|
|
14
|
+
* a list of {@link EngagementJson}. RepoJson describes the per-repo
|
|
15
|
+
* configured membership recorded by `git config --get-all
|
|
16
|
+
* repo-aegis.engagement` — it is the *reference set*, not a hydrated view
|
|
17
|
+
* of registry state. Resolving an id to its registry entry (name, active
|
|
18
|
+
* flag) is the consumer's responsibility, and the canonical hydrated
|
|
19
|
+
* shape is {@link EngagementJson}, which appears as a sibling field on
|
|
20
|
+
* commands that perform that resolution (allow, deny, status). The two
|
|
21
|
+
* are intentionally distinct and must not be conflated.
|
|
22
|
+
*/
|
|
23
|
+
export interface RepoJson {
|
|
24
|
+
cwd: string;
|
|
25
|
+
isGitRepo: boolean;
|
|
26
|
+
class: import("./repo.js").RepoClass;
|
|
27
|
+
classExplicit: boolean;
|
|
28
|
+
engagements: string[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Canonical JSON shape for an engagement reference in CLI output.
|
|
32
|
+
* Includes only the fields needed to identify and act on the engagement;
|
|
33
|
+
* full {@link Engagement} bodies (with markers) are never emitted to JSON
|
|
34
|
+
* outputs that flow through hook context.
|
|
35
|
+
*
|
|
36
|
+
* Relationship to {@link RepoJson}: `RepoJson.engagements` is `string[]`
|
|
37
|
+
* (the per-repo membership of bare ids); commands that hydrate those ids
|
|
38
|
+
* against the registry (e.g. `allow`, `deny`, `status`) emit a separate
|
|
39
|
+
* sibling field of type `EngagementJson` (or `EngagementJson[]`) with the
|
|
40
|
+
* resolved name + active flag. The shapes are not interchangeable.
|
|
41
|
+
*/
|
|
42
|
+
export interface EngagementJson {
|
|
43
|
+
id: string;
|
|
44
|
+
name: string;
|
|
45
|
+
active: boolean;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAOA,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACzE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvD,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC1E,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC7E,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,WAAW,EAAE,SAAS,CAAC;IACrC,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Richard Myers and contributors.
|
|
3
|
+
// Central type re-export. Every module in core defines its own types, but
|
|
4
|
+
// downstream consumers (cli, scan) should import from `@de-otio/repo-aegis-core`
|
|
5
|
+
// (which re-exports everything via index.ts). This file just makes sure the
|
|
6
|
+
// canonical TypeScript types are aggregated in one place for ease of review.
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,qDAAqD;AACrD,0EAA0E;AAC1E,iFAAiF;AACjF,4EAA4E;AAC5E,6EAA6E"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walk up from `startPath` until a directory containing `.git` (file or
|
|
3
|
+
* dir) is found. Returns the working tree root (the directory holding
|
|
4
|
+
* the `.git` entry), or `null` if none found within
|
|
5
|
+
* {@link MAX_ANCESTOR_HOPS} hops.
|
|
6
|
+
*
|
|
7
|
+
* Both git-worktree files (`.git` is a file containing `gitdir: ...`)
|
|
8
|
+
* and submodule `.git` files are recognised — the working tree is the
|
|
9
|
+
* directory containing the file in either case. The actual gitdir is
|
|
10
|
+
* resolved separately via {@link resolveGitDir}.
|
|
11
|
+
*
|
|
12
|
+
* `startPath` is realpath'd first to defeat symlink-tricks: a symlink
|
|
13
|
+
* inside repo A pointing to a file in repo B resolves to repo B, and
|
|
14
|
+
* the hook applies repo B's rules — not repo A's.
|
|
15
|
+
*/
|
|
16
|
+
export declare function findEnclosingWorkingTree(startPath: string): string | null;
|
|
17
|
+
/**
|
|
18
|
+
* Given a working-tree root (from {@link findEnclosingWorkingTree}),
|
|
19
|
+
* return the absolute path of the actual git directory.
|
|
20
|
+
*
|
|
21
|
+
* - Regular repo: `<wt>/.git` is a directory; return that.
|
|
22
|
+
* - Worktree / submodule: `<wt>/.git` is a file with `gitdir: <path>`;
|
|
23
|
+
* resolve `<path>` relative to `<wt>` and return the absolute form.
|
|
24
|
+
* - Anything else (`.git` missing, malformed `gitdir:` line): `null`.
|
|
25
|
+
*
|
|
26
|
+
* Used to find the right `config` file to read remotes from.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveGitDir(workingTree: string): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Read `remote.origin.url` from the working tree's git config and
|
|
31
|
+
* return the GitHub org (lowercased), or `null` if no remote, the
|
|
32
|
+
* remote isn't GitHub, or anything fails.
|
|
33
|
+
*
|
|
34
|
+
* Total: never throws. Used by the hook to decide whether a
|
|
35
|
+
* cross-tree write stays inside one trust boundary.
|
|
36
|
+
*/
|
|
37
|
+
export declare function getRemoteOrg(workingTree: string): string | null;
|
|
38
|
+
//# sourceMappingURL=working-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"working-tree.d.ts","sourceRoot":"","sources":["../src/working-tree.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAqBzE;AAcD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmBhE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkB/D"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2026 Richard Myers and contributors.
|
|
3
|
+
//
|
|
4
|
+
// Working-tree resolution for the path-aware PostToolUse hook.
|
|
5
|
+
//
|
|
6
|
+
// Given an arbitrary file path the agent just wrote, find the git
|
|
7
|
+
// working tree it lives in (regular repo, worktree, or submodule), so
|
|
8
|
+
// the hook can apply *that* repo's classification + deny set rather
|
|
9
|
+
// than the launcher's cwd.
|
|
10
|
+
//
|
|
11
|
+
// Pure-ish: stat/realpath the path's ancestors; for org resolution,
|
|
12
|
+
// shells out to `git config --file <wt>/.git/config` (or the worktree's
|
|
13
|
+
// resolved gitdir/config). Total — never throws.
|
|
14
|
+
import { execFileSync } from "node:child_process";
|
|
15
|
+
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
16
|
+
import { dirname, join, resolve } from "node:path";
|
|
17
|
+
import { parseRemoteUrl } from "./remote-url.js";
|
|
18
|
+
const MAX_ANCESTOR_HOPS = 64;
|
|
19
|
+
/**
|
|
20
|
+
* Walk up from `startPath` until a directory containing `.git` (file or
|
|
21
|
+
* dir) is found. Returns the working tree root (the directory holding
|
|
22
|
+
* the `.git` entry), or `null` if none found within
|
|
23
|
+
* {@link MAX_ANCESTOR_HOPS} hops.
|
|
24
|
+
*
|
|
25
|
+
* Both git-worktree files (`.git` is a file containing `gitdir: ...`)
|
|
26
|
+
* and submodule `.git` files are recognised — the working tree is the
|
|
27
|
+
* directory containing the file in either case. The actual gitdir is
|
|
28
|
+
* resolved separately via {@link resolveGitDir}.
|
|
29
|
+
*
|
|
30
|
+
* `startPath` is realpath'd first to defeat symlink-tricks: a symlink
|
|
31
|
+
* inside repo A pointing to a file in repo B resolves to repo B, and
|
|
32
|
+
* the hook applies repo B's rules — not repo A's.
|
|
33
|
+
*/
|
|
34
|
+
export function findEnclosingWorkingTree(startPath) {
|
|
35
|
+
let real;
|
|
36
|
+
try {
|
|
37
|
+
// Resolve as much of the path as exists. If the file itself doesn't
|
|
38
|
+
// exist (rare in PostToolUse — the write just happened — but
|
|
39
|
+
// possible if the file was concurrently removed), walk up to the
|
|
40
|
+
// first existing ancestor and realpath that.
|
|
41
|
+
real = realpathExisting(startPath);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
let cur = statSync(real).isDirectory() ? real : dirname(real);
|
|
47
|
+
for (let i = 0; i < MAX_ANCESTOR_HOPS; i++) {
|
|
48
|
+
const dotGit = join(cur, ".git");
|
|
49
|
+
if (existsSync(dotGit))
|
|
50
|
+
return cur;
|
|
51
|
+
const parent = dirname(cur);
|
|
52
|
+
if (parent === cur)
|
|
53
|
+
return null;
|
|
54
|
+
cur = parent;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
function realpathExisting(p) {
|
|
59
|
+
let cur = resolve(p);
|
|
60
|
+
// Walk up until we find a path that exists (or hit /).
|
|
61
|
+
for (let i = 0; i < MAX_ANCESTOR_HOPS; i++) {
|
|
62
|
+
if (existsSync(cur))
|
|
63
|
+
return realpathSync(cur);
|
|
64
|
+
const parent = dirname(cur);
|
|
65
|
+
if (parent === cur)
|
|
66
|
+
throw new Error("path has no existing ancestor");
|
|
67
|
+
cur = parent;
|
|
68
|
+
}
|
|
69
|
+
throw new Error("path has no existing ancestor within hop budget");
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Given a working-tree root (from {@link findEnclosingWorkingTree}),
|
|
73
|
+
* return the absolute path of the actual git directory.
|
|
74
|
+
*
|
|
75
|
+
* - Regular repo: `<wt>/.git` is a directory; return that.
|
|
76
|
+
* - Worktree / submodule: `<wt>/.git` is a file with `gitdir: <path>`;
|
|
77
|
+
* resolve `<path>` relative to `<wt>` and return the absolute form.
|
|
78
|
+
* - Anything else (`.git` missing, malformed `gitdir:` line): `null`.
|
|
79
|
+
*
|
|
80
|
+
* Used to find the right `config` file to read remotes from.
|
|
81
|
+
*/
|
|
82
|
+
export function resolveGitDir(workingTree) {
|
|
83
|
+
const dotGit = join(workingTree, ".git");
|
|
84
|
+
if (!existsSync(dotGit))
|
|
85
|
+
return null;
|
|
86
|
+
const st = statSync(dotGit);
|
|
87
|
+
if (st.isDirectory())
|
|
88
|
+
return dotGit;
|
|
89
|
+
if (!st.isFile())
|
|
90
|
+
return null;
|
|
91
|
+
let body;
|
|
92
|
+
try {
|
|
93
|
+
body = readFileSync(dotGit, "utf8");
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
// Format: `gitdir: <path>\n`. The path may be relative to the .git
|
|
99
|
+
// file's directory.
|
|
100
|
+
const m = /^gitdir:\s*(.+?)\s*$/m.exec(body);
|
|
101
|
+
if (!m || !m[1])
|
|
102
|
+
return null;
|
|
103
|
+
const target = m[1];
|
|
104
|
+
return resolve(workingTree, target);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Read `remote.origin.url` from the working tree's git config and
|
|
108
|
+
* return the GitHub org (lowercased), or `null` if no remote, the
|
|
109
|
+
* remote isn't GitHub, or anything fails.
|
|
110
|
+
*
|
|
111
|
+
* Total: never throws. Used by the hook to decide whether a
|
|
112
|
+
* cross-tree write stays inside one trust boundary.
|
|
113
|
+
*/
|
|
114
|
+
export function getRemoteOrg(workingTree) {
|
|
115
|
+
const gitDir = resolveGitDir(workingTree);
|
|
116
|
+
if (gitDir === null)
|
|
117
|
+
return null;
|
|
118
|
+
const configPath = join(gitDir, "config");
|
|
119
|
+
if (!existsSync(configPath))
|
|
120
|
+
return null;
|
|
121
|
+
let url;
|
|
122
|
+
try {
|
|
123
|
+
url = execFileSync("git", ["config", "--file", configPath, "--get", "remote.origin.url"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
if (url.length === 0)
|
|
129
|
+
return null;
|
|
130
|
+
const parsed = parseRemoteUrl(url);
|
|
131
|
+
return parsed?.org ?? null;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=working-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"working-tree.js","sourceRoot":"","sources":["../src/working-tree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"working-tree.test.d.ts","sourceRoot":"","sources":["../src/working-tree.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,162 @@
|
|
|
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, symlinkSync, rmSync, realpathSync, } from "node:fs";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { findEnclosingWorkingTree, resolveGitDir, getRemoteOrg, } from "./working-tree.js";
|
|
10
|
+
let tmp;
|
|
11
|
+
before(() => {
|
|
12
|
+
tmp = realpathSync(mkdtempSync(join(tmpdir(), "repo-aegis-wt-")));
|
|
13
|
+
});
|
|
14
|
+
after(() => {
|
|
15
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
16
|
+
});
|
|
17
|
+
function gitInit(dir) {
|
|
18
|
+
execFileSync("git", ["init", "-q", "--initial-branch=main", dir], { stdio: "ignore" });
|
|
19
|
+
}
|
|
20
|
+
function gitConfig(dir, key, value) {
|
|
21
|
+
execFileSync("git", ["-C", dir, "config", key, value], { stdio: "ignore" });
|
|
22
|
+
}
|
|
23
|
+
function commitNothing(dir) {
|
|
24
|
+
// Need at least one commit before `git worktree add`.
|
|
25
|
+
gitConfig(dir, "user.email", "test@example.com");
|
|
26
|
+
gitConfig(dir, "user.name", "Test");
|
|
27
|
+
writeFileSync(join(dir, "README.md"), "x");
|
|
28
|
+
execFileSync("git", ["-C", dir, "add", "README.md"], { stdio: "ignore" });
|
|
29
|
+
execFileSync("git", ["-C", dir, "commit", "-q", "-m", "initial"], { stdio: "ignore" });
|
|
30
|
+
}
|
|
31
|
+
describe("findEnclosingWorkingTree", () => {
|
|
32
|
+
it("finds the enclosing working tree of a file in a regular repo", () => {
|
|
33
|
+
const repo = join(tmp, "regular");
|
|
34
|
+
mkdirSync(repo);
|
|
35
|
+
gitInit(repo);
|
|
36
|
+
const file = join(repo, "src", "foo.ts");
|
|
37
|
+
mkdirSync(join(repo, "src"));
|
|
38
|
+
writeFileSync(file, "x");
|
|
39
|
+
assert.equal(findEnclosingWorkingTree(file), repo);
|
|
40
|
+
});
|
|
41
|
+
it("finds the working tree from a nested subdirectory", () => {
|
|
42
|
+
const repo = join(tmp, "nested");
|
|
43
|
+
mkdirSync(repo);
|
|
44
|
+
gitInit(repo);
|
|
45
|
+
const deep = join(repo, "a", "b", "c");
|
|
46
|
+
mkdirSync(deep, { recursive: true });
|
|
47
|
+
const file = join(deep, "deep.ts");
|
|
48
|
+
writeFileSync(file, "x");
|
|
49
|
+
assert.equal(findEnclosingWorkingTree(file), repo);
|
|
50
|
+
});
|
|
51
|
+
it("returns the worktree (not the parent repo) for a git worktree", () => {
|
|
52
|
+
const main = join(tmp, "main-repo");
|
|
53
|
+
mkdirSync(main);
|
|
54
|
+
gitInit(main);
|
|
55
|
+
commitNothing(main);
|
|
56
|
+
const wt = join(tmp, "wt-feature");
|
|
57
|
+
execFileSync("git", ["-C", main, "worktree", "add", "-q", "-b", "feat", wt], {
|
|
58
|
+
stdio: "ignore",
|
|
59
|
+
});
|
|
60
|
+
const file = join(wt, "newfile.ts");
|
|
61
|
+
writeFileSync(file, "x");
|
|
62
|
+
assert.equal(findEnclosingWorkingTree(file), wt);
|
|
63
|
+
});
|
|
64
|
+
it("returns null for a path outside any git repo", () => {
|
|
65
|
+
const outside = join(tmp, "no-git");
|
|
66
|
+
mkdirSync(outside);
|
|
67
|
+
writeFileSync(join(outside, "loose.txt"), "x");
|
|
68
|
+
assert.equal(findEnclosingWorkingTree(join(outside, "loose.txt")), null);
|
|
69
|
+
});
|
|
70
|
+
it("follows symlinks (resolves to the destination's working tree)", () => {
|
|
71
|
+
const repo = join(tmp, "sym-target");
|
|
72
|
+
mkdirSync(repo);
|
|
73
|
+
gitInit(repo);
|
|
74
|
+
const target = join(repo, "real.ts");
|
|
75
|
+
writeFileSync(target, "x");
|
|
76
|
+
const linkDir = join(tmp, "sym-link");
|
|
77
|
+
mkdirSync(linkDir);
|
|
78
|
+
const link = join(linkDir, "alias.ts");
|
|
79
|
+
symlinkSync(target, link);
|
|
80
|
+
// Even though `link` lives outside `repo`, realpath resolves to
|
|
81
|
+
// inside `repo`, and that's what we apply rules to.
|
|
82
|
+
assert.equal(findEnclosingWorkingTree(link), repo);
|
|
83
|
+
});
|
|
84
|
+
it("works when the file does not yet exist (walks up to first existing ancestor)", () => {
|
|
85
|
+
const repo = join(tmp, "no-file");
|
|
86
|
+
mkdirSync(repo);
|
|
87
|
+
gitInit(repo);
|
|
88
|
+
const ghost = join(repo, "src", "not-yet.ts");
|
|
89
|
+
// Don't create the file or its dir.
|
|
90
|
+
assert.equal(findEnclosingWorkingTree(ghost), repo);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe("resolveGitDir", () => {
|
|
94
|
+
it("returns <wt>/.git for a regular repo", () => {
|
|
95
|
+
const repo = join(tmp, "rgd-regular");
|
|
96
|
+
mkdirSync(repo);
|
|
97
|
+
gitInit(repo);
|
|
98
|
+
const gitDir = resolveGitDir(repo);
|
|
99
|
+
assert.equal(gitDir, join(repo, ".git"));
|
|
100
|
+
});
|
|
101
|
+
it("resolves the linked gitdir for a worktree", () => {
|
|
102
|
+
const main = join(tmp, "rgd-main");
|
|
103
|
+
mkdirSync(main);
|
|
104
|
+
gitInit(main);
|
|
105
|
+
commitNothing(main);
|
|
106
|
+
const wt = join(tmp, "rgd-wt");
|
|
107
|
+
execFileSync("git", ["-C", main, "worktree", "add", "-q", "-b", "feat", wt], {
|
|
108
|
+
stdio: "ignore",
|
|
109
|
+
});
|
|
110
|
+
const gitDir = resolveGitDir(wt);
|
|
111
|
+
assert.ok(gitDir !== null);
|
|
112
|
+
// Should point to <main>/.git/worktrees/<name>
|
|
113
|
+
assert.match(gitDir, /worktrees/);
|
|
114
|
+
});
|
|
115
|
+
it("returns null when .git is missing", () => {
|
|
116
|
+
const dir = join(tmp, "rgd-bare");
|
|
117
|
+
mkdirSync(dir);
|
|
118
|
+
assert.equal(resolveGitDir(dir), null);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe("getRemoteOrg", () => {
|
|
122
|
+
it("parses GitHub HTTPS URLs", () => {
|
|
123
|
+
const repo = join(tmp, "remote-https");
|
|
124
|
+
mkdirSync(repo);
|
|
125
|
+
gitInit(repo);
|
|
126
|
+
gitConfig(repo, "remote.origin.url", "https://github.com/Foo-Org/Bar.git");
|
|
127
|
+
assert.equal(getRemoteOrg(repo), "foo-org");
|
|
128
|
+
});
|
|
129
|
+
it("parses GitHub SSH URLs", () => {
|
|
130
|
+
const repo = join(tmp, "remote-ssh");
|
|
131
|
+
mkdirSync(repo);
|
|
132
|
+
gitInit(repo);
|
|
133
|
+
gitConfig(repo, "remote.origin.url", "git@github.com:de-otio/repo-aegis.git");
|
|
134
|
+
assert.equal(getRemoteOrg(repo), "de-otio");
|
|
135
|
+
});
|
|
136
|
+
it("parses ssh-config-alias URLs (`github.com-personal`)", () => {
|
|
137
|
+
const repo = join(tmp, "remote-alias");
|
|
138
|
+
mkdirSync(repo);
|
|
139
|
+
gitInit(repo);
|
|
140
|
+
gitConfig(repo, "remote.origin.url", "git@github.com-personal:de-otio/foo.git");
|
|
141
|
+
assert.equal(getRemoteOrg(repo), "de-otio");
|
|
142
|
+
});
|
|
143
|
+
it("returns null when there is no origin remote", () => {
|
|
144
|
+
const repo = join(tmp, "remote-none");
|
|
145
|
+
mkdirSync(repo);
|
|
146
|
+
gitInit(repo);
|
|
147
|
+
assert.equal(getRemoteOrg(repo), null);
|
|
148
|
+
});
|
|
149
|
+
it("returns null for a non-GitHub remote", () => {
|
|
150
|
+
const repo = join(tmp, "remote-non-gh");
|
|
151
|
+
mkdirSync(repo);
|
|
152
|
+
gitInit(repo);
|
|
153
|
+
gitConfig(repo, "remote.origin.url", "https://gitlab.com/x/y.git");
|
|
154
|
+
assert.equal(getRemoteOrg(repo), null);
|
|
155
|
+
});
|
|
156
|
+
it("returns null when the directory is not a working tree", () => {
|
|
157
|
+
const dir = join(tmp, "remote-bare");
|
|
158
|
+
mkdirSync(dir);
|
|
159
|
+
assert.equal(getRemoteOrg(dir), null);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
//# sourceMappingURL=working-tree.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"working-tree.test.js","sourceRoot":"","sources":["../src/working-tree.test.ts"],"names":[],"mappings":"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"}
|