@jeger-ai/opengantry 3.6.0 → 3.7.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/README.md +31 -0
- package/dist/cli/cage-bin.d.ts +3 -0
- package/dist/cli/cage-bin.d.ts.map +1 -0
- package/dist/cli/cage-bin.js +11 -0
- package/dist/cli/cage-bin.js.map +1 -0
- package/dist/cli/commands/cage.d.ts +8 -0
- package/dist/cli/commands/cage.d.ts.map +1 -0
- package/dist/cli/commands/cage.js +39 -0
- package/dist/cli/commands/cage.js.map +1 -0
- package/dist/cli/lib/cage/cage-process.d.ts +18 -0
- package/dist/cli/lib/cage/cage-process.d.ts.map +1 -0
- package/dist/cli/lib/cage/cage-process.js +39 -0
- package/dist/cli/lib/cage/cage-process.js.map +1 -0
- package/dist/cli/lib/cage/cage-report.d.ts +54 -0
- package/dist/cli/lib/cage/cage-report.d.ts.map +1 -0
- package/dist/cli/lib/cage/cage-report.js +87 -0
- package/dist/cli/lib/cage/cage-report.js.map +1 -0
- package/dist/cli/lib/cage/cage-revert.d.ts +18 -0
- package/dist/cli/lib/cage/cage-revert.d.ts.map +1 -0
- package/dist/cli/lib/cage/cage-revert.js +56 -0
- package/dist/cli/lib/cage/cage-revert.js.map +1 -0
- package/dist/cli/lib/cage/cage-rules.d.ts +24 -0
- package/dist/cli/lib/cage/cage-rules.d.ts.map +1 -0
- package/dist/cli/lib/cage/cage-rules.js +94 -0
- package/dist/cli/lib/cage/cage-rules.js.map +1 -0
- package/dist/cli/lib/cage/cage-run.d.ts +21 -0
- package/dist/cli/lib/cage/cage-run.d.ts.map +1 -0
- package/dist/cli/lib/cage/cage-run.js +51 -0
- package/dist/cli/lib/cage/cage-run.js.map +1 -0
- package/dist/cli/lib/cage/cage-snapshot.d.ts +36 -0
- package/dist/cli/lib/cage/cage-snapshot.d.ts.map +1 -0
- package/dist/cli/lib/cage/cage-snapshot.js +128 -0
- package/dist/cli/lib/cage/cage-snapshot.js.map +1 -0
- package/dist/cli/lib/version.gen.d.ts +1 -1
- package/dist/cli/lib/version.gen.js +1 -1
- package/dist/cli/program-cage.d.ts +5 -0
- package/dist/cli/program-cage.d.ts.map +1 -0
- package/dist/cli/program-cage.js +19 -0
- package/dist/cli/program-cage.js.map +1 -0
- package/dist/cli/program.d.ts.map +1 -1
- package/dist/cli/program.js +2 -0
- package/dist/cli/program.js.map +1 -1
- package/package.json +3 -2
- package/templates/.gitagent/foreman/SUBSTRATE.version.json +1 -1
- package/templates/integrations/compatibility.json +1 -1
package/README.md
CHANGED
|
@@ -139,6 +139,35 @@ See [`docs/DOMAINS.md`](docs/DOMAINS.md) for adapter details and [`docs/AGENT-GR
|
|
|
139
139
|
|
|
140
140
|
---
|
|
141
141
|
|
|
142
|
+
## Try it in 60 seconds: `gantry cage`
|
|
143
|
+
|
|
144
|
+
No setup. Wrap any agent command:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
npx -p @jeger-ai/opengantry opengantry-cage -- <agent command>
|
|
148
|
+
# installed: gantry cage -- <agent command>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Cage checks once, after the command exits, so use it for one-shot, headless agent runs rather than interactive sessions (install once; `npx` re-resolves the package on each launch):
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm install -g @jeger-ai/opengantry
|
|
155
|
+
gantry cage -- claude -p "Fix the failing test in auth.spec.ts"
|
|
156
|
+
gantry cage -- aider --message "Refactor DB queries" --no-auto-commits --yes-always
|
|
157
|
+
|
|
158
|
+
# single-task shell functions
|
|
159
|
+
c-run() { gantry cage -- claude -p "$*"; }
|
|
160
|
+
a-run() { gantry cage -- aider --message "$*" --no-auto-commits --yes-always; }
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Don't alias `claude` or `aider` themselves: both open an interactive REPL, and a protected-file edit early in a long session stays in place (and can be pushed) until you quit. Keep Aider's auto-commits off: cage restores the working tree, not git history or a remote, so a committed or pushed change needs a manual fix.
|
|
164
|
+
|
|
165
|
+
After the command exits, cage restores changes to CI configs, `.env` / `.env.*`, `.git/config`, `.git/hooks/` (and `core.hooksPath`), and your manifest `forbidden_zones`. Lockfile changes are listed but kept. Exit `3` means something was reverted; otherwise the command's own exit code passes through.
|
|
166
|
+
|
|
167
|
+
Cage detects and reverts **after** the command exits. It does not see reads, network calls, or writes outside the protected set. For scope enforcement during a run, use missions (below). Details: [`docs/FEATURES.md`](docs/FEATURES.md#zero-config-cage-gantry-cage).
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
142
171
|
## Feature tour: what to try first
|
|
143
172
|
|
|
144
173
|
### 1. Bootstrap a repo
|
|
@@ -214,6 +243,8 @@ On failure, external agents ingest `findings[]`:
|
|
|
214
243
|
}
|
|
215
244
|
```
|
|
216
245
|
|
|
246
|
+
**v3.7.0:** zero-config `gantry cage -- <cmd>` (and `npx -p @jeger-ai/opengantry opengantry-cage -- <cmd>`) restores CI configs, `.env*`, git hooks/config and manifest forbidden zones after a one-shot agent run, reports lockfile changes, and exits 3 on tampering. See [Try it in 60 seconds](#try-it-in-60-seconds-gantry-cage).
|
|
247
|
+
|
|
217
248
|
**v3.6.0:** `gate_adapter: tsc|eslint` fails closed on chained `gate_command`s (`GXT_GATE_ADAPTER_MISCONFIG`). `gantry hooks install` arms the tracked pre-commit hook so `gantry tmvc guard --strict` blocks commits outside the pinned mission. Optional local sqlite-vec contract drift index (`gantry contract embed`, `legislate --from-intent --embedding-file`). See [`docs/CHANGELOG.md`](docs/CHANGELOG.md) upgrade notes.
|
|
218
249
|
|
|
219
250
|
**v3.5.0:** Cursor MCP uses a byte-identical `./scripts/mcp-launcher.sh` (no mcp.json parity exemption). `gantry verify --format sarif|junit` writes the document only on stdout and diagnostics on stderr ([`docs/CI.md`](docs/CI.md)). `gantry contract preflight` is advisory and fail-open ([ADR-0046](.gitagent/out-of-scope/ADR-0046-experimental-contract-preflight.md)).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-bin.d.ts","sourceRoot":"","sources":["../../src/cli/cage-bin.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { CLI_VERSION } from "./lib/constants.js";
|
|
4
|
+
import { reportUserFacingError } from "./lib/errors.js";
|
|
5
|
+
import { resetOutputContext } from "./lib/output-context.js";
|
|
6
|
+
import { configureCageCommand } from "./program-cage.js";
|
|
7
|
+
/** Standalone `opengantry-cage [options] -- <command...>`, equivalent to `gantry cage`. */
|
|
8
|
+
resetOutputContext();
|
|
9
|
+
const program = configureCageCommand(new Command("opengantry-cage")).version(CLI_VERSION);
|
|
10
|
+
program.parseAsync(process.argv).catch(reportUserFacingError);
|
|
11
|
+
//# sourceMappingURL=cage-bin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-bin.js","sourceRoot":"","sources":["../../src/cli/cage-bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,2FAA2F;AAC3F,kBAAkB,EAAE,CAAC;AACrB,MAAM,OAAO,GAAG,oBAAoB,CAAC,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AAC1F,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/cage.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AASD,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB3E"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { logError, setExitCode } from "../lib/cli-io.js";
|
|
2
|
+
import { emitCliJson, runUserCommandAsync } from "../lib/command-boundary.js";
|
|
3
|
+
import { formatCageReport } from "../lib/cage/cage-report.js";
|
|
4
|
+
import { runCage } from "../lib/cage/cage-run.js";
|
|
5
|
+
function parseMaxFileBytes(raw) {
|
|
6
|
+
if (raw === undefined)
|
|
7
|
+
return { ok: true, value: undefined };
|
|
8
|
+
const t = raw.trim();
|
|
9
|
+
if (!/^\d+$/.test(t))
|
|
10
|
+
return { ok: false };
|
|
11
|
+
return { ok: true, value: Number.parseInt(t, 10) };
|
|
12
|
+
}
|
|
13
|
+
export async function runCageCommand(options) {
|
|
14
|
+
const command = options.command[0] === "--" ? options.command.slice(1) : options.command;
|
|
15
|
+
if (command.length === 0) {
|
|
16
|
+
logError("cage: missing command. Use: gantry cage -- <command...>");
|
|
17
|
+
setExitCode(2);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const max = parseMaxFileBytes(options.maxFileBytes);
|
|
21
|
+
if (!max.ok) {
|
|
22
|
+
logError("cage: --max-file-bytes must be a non-negative integer");
|
|
23
|
+
setExitCode(2);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
await runUserCommandAsync({ json: options.json }, async () => {
|
|
27
|
+
const report = await runCage({ command, reportOnly: options.reportOnly, maxFileBytes: max.value });
|
|
28
|
+
if (options.json) {
|
|
29
|
+
emitCliJson(report);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
for (const line of formatCageReport(report))
|
|
33
|
+
console.error(line);
|
|
34
|
+
}
|
|
35
|
+
if (report.exit_code !== 0)
|
|
36
|
+
setExitCode(report.exit_code);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=cage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage.js","sourceRoot":"","sources":["../../../src/cli/commands/cage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AASlD,SAAS,iBAAiB,CAAC,GAAuB;IAChD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAC7D,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACrB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IAC3C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AACrD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAuB;IAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACzF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,QAAQ,CAAC,yDAAyD,CAAC,CAAC;QACpE,WAAW,CAAC,CAAC,CAAC,CAAC;QACf,OAAO;IACT,CAAC;IACD,MAAM,GAAG,GAAG,iBAAiB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,QAAQ,CAAC,uDAAuD,CAAC,CAAC;QAClE,WAAW,CAAC,CAAC,CAAC,CAAC;QACf,OAAO;IACT,CAAC;IAED,MAAM,mBAAmB,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,YAAY,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QACnG,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,WAAW,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,KAAK,MAAM,IAAI,IAAI,gBAAgB,CAAC,MAAM,CAAC;gBAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,MAAM,CAAC,SAAS,KAAK,CAAC;YAAE,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface CageProcessResult {
|
|
2
|
+
code: number | null;
|
|
3
|
+
signal: NodeJS.Signals | null;
|
|
4
|
+
/** Spawn failure (e.g. ENOENT); the command never ran. */
|
|
5
|
+
spawnError: string | null;
|
|
6
|
+
}
|
|
7
|
+
/** Shell convention: a child killed by signal N exits 128 + N. */
|
|
8
|
+
export declare function signalExitCode(signal: NodeJS.Signals): number;
|
|
9
|
+
/**
|
|
10
|
+
* Run the caged command with inherited stdio so interactive agents keep their TTY.
|
|
11
|
+
*
|
|
12
|
+
* The cage must outlive the child to diff and revert, so while it runs:
|
|
13
|
+
* - SIGINT is swallowed here; a terminal Ctrl-C already reaches the child through the
|
|
14
|
+
* shared process group, and forwarding it again would double-interrupt.
|
|
15
|
+
* - SIGTERM / SIGHUP are forwarded to the child instead of killing the cage.
|
|
16
|
+
*/
|
|
17
|
+
export declare function spawnCaged(argv: readonly string[], cwd: string): Promise<CageProcessResult>;
|
|
18
|
+
//# sourceMappingURL=cage-process.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-process.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-process.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC9B,0DAA0D;IAC1D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAG7D;AAID;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAkBjG"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
/** Shell convention: a child killed by signal N exits 128 + N. */
|
|
4
|
+
export function signalExitCode(signal) {
|
|
5
|
+
const n = os.constants.signals[signal];
|
|
6
|
+
return typeof n === "number" ? 128 + n : 1;
|
|
7
|
+
}
|
|
8
|
+
const FORWARDED_SIGNALS = ["SIGTERM", "SIGHUP"];
|
|
9
|
+
/**
|
|
10
|
+
* Run the caged command with inherited stdio so interactive agents keep their TTY.
|
|
11
|
+
*
|
|
12
|
+
* The cage must outlive the child to diff and revert, so while it runs:
|
|
13
|
+
* - SIGINT is swallowed here; a terminal Ctrl-C already reaches the child through the
|
|
14
|
+
* shared process group, and forwarding it again would double-interrupt.
|
|
15
|
+
* - SIGTERM / SIGHUP are forwarded to the child instead of killing the cage.
|
|
16
|
+
*/
|
|
17
|
+
export async function spawnCaged(argv, cwd) {
|
|
18
|
+
const [command, ...args] = argv;
|
|
19
|
+
const child = spawn(command, args, { cwd, stdio: "inherit", env: process.env });
|
|
20
|
+
const ignoreInt = () => { };
|
|
21
|
+
const forward = (sig) => {
|
|
22
|
+
child.kill(sig);
|
|
23
|
+
};
|
|
24
|
+
process.on("SIGINT", ignoreInt);
|
|
25
|
+
for (const sig of FORWARDED_SIGNALS)
|
|
26
|
+
process.on(sig, forward);
|
|
27
|
+
try {
|
|
28
|
+
return await new Promise((resolve) => {
|
|
29
|
+
child.on("error", (err) => resolve({ code: null, signal: null, spawnError: err.message }));
|
|
30
|
+
child.on("exit", (code, signal) => resolve({ code, signal, spawnError: null }));
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
process.off("SIGINT", ignoreInt);
|
|
35
|
+
for (const sig of FORWARDED_SIGNALS)
|
|
36
|
+
process.off(sig, forward);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=cage-process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-process.js","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,MAAM,SAAS,CAAC;AASzB,kEAAkE;AAClE,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,MAAM,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,iBAAiB,GAA8B,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAE3E;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAuB,EAAE,GAAW;IACnE,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAChC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAQ,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACjF,MAAM,SAAS,GAAG,GAAS,EAAE,GAAE,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,CAAC,GAAmB,EAAQ,EAAE;QAC5C,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAChC,KAAK,MAAM,GAAG,IAAI,iBAAiB;QAAE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,OAAO,CAAoB,CAAC,OAAO,EAAE,EAAE;YACtD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC3F,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAClF,CAAC,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACjC,KAAK,MAAM,GAAG,IAAI,iBAAiB;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { CageRuleId } from "./cage-rules.js";
|
|
2
|
+
import type { CageOutcome, CageResolvedChange } from "./cage-revert.js";
|
|
3
|
+
export declare const CAGE_REPORT_SCHEMA: "gantry.cage-report.v1";
|
|
4
|
+
/** Detect-after-the-fact limits, stated in every cage report. */
|
|
5
|
+
export declare const CAGE_LIMITS: readonly string[];
|
|
6
|
+
/** One-line stderr form of {@link CAGE_LIMITS}; `--json` keeps the full list. */
|
|
7
|
+
export declare const CAGE_LIMITS_SUMMARY = "after-exit check only; reads, network calls and writes outside the protected set are not detected";
|
|
8
|
+
/** Printed once under a violation report: the path from cage to project-specific missions. */
|
|
9
|
+
export declare const CAGE_UPGRADE_FOOTER = "Need project-specific boundaries or task contracts? Run: npx -p @jeger-ai/opengantry gantry init";
|
|
10
|
+
export type CageStatus = "ok" | "violations_reverted" | "violations_unresolved" | "runtime_error";
|
|
11
|
+
/** One changed protected path. Digests and outcomes only; never file bodies (ADR-0034). */
|
|
12
|
+
export interface CageReportChange {
|
|
13
|
+
path: string;
|
|
14
|
+
kind: "added" | "modified" | "deleted";
|
|
15
|
+
rule: CageRuleId;
|
|
16
|
+
sha256_before: string | null;
|
|
17
|
+
sha256_after: string | null;
|
|
18
|
+
outcome: CageOutcome;
|
|
19
|
+
error_code: string | null;
|
|
20
|
+
}
|
|
21
|
+
export interface CageReport {
|
|
22
|
+
report_schema: typeof CAGE_REPORT_SCHEMA;
|
|
23
|
+
status: CageStatus;
|
|
24
|
+
exit_code: number;
|
|
25
|
+
/** argv[0] only: arguments can carry tokens. */
|
|
26
|
+
command: string;
|
|
27
|
+
command_exit_code: number | null;
|
|
28
|
+
command_signal: string | null;
|
|
29
|
+
runtime_error: string | null;
|
|
30
|
+
root: string;
|
|
31
|
+
revert_mode: "revert" | "report_only";
|
|
32
|
+
max_file_bytes: number;
|
|
33
|
+
protected_files: number;
|
|
34
|
+
manifest_zones: number;
|
|
35
|
+
changes: CageReportChange[];
|
|
36
|
+
limits: readonly string[];
|
|
37
|
+
}
|
|
38
|
+
export interface CageReportInput {
|
|
39
|
+
command: string;
|
|
40
|
+
commandExitCode: number | null;
|
|
41
|
+
commandSignal: NodeJS.Signals | null;
|
|
42
|
+
runtimeError: string | null;
|
|
43
|
+
root: string;
|
|
44
|
+
reportOnly: boolean;
|
|
45
|
+
maxFileBytes: number;
|
|
46
|
+
protectedFiles: number;
|
|
47
|
+
manifestZones: number;
|
|
48
|
+
changes: readonly CageResolvedChange[];
|
|
49
|
+
signalExitCode: (signal: NodeJS.Signals) => number;
|
|
50
|
+
}
|
|
51
|
+
export declare function buildCageReport(input: CageReportInput): CageReport;
|
|
52
|
+
/** Human summary (stderr), so it never mixes into the wrapped command's stdout. */
|
|
53
|
+
export declare function formatCageReport(report: CageReport): string[];
|
|
54
|
+
//# sourceMappingURL=cage-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-report.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAExE,eAAO,MAAM,kBAAkB,EAAG,uBAAgC,CAAC;AAEnE,iEAAiE;AACjE,eAAO,MAAM,WAAW,EAAE,SAAS,MAAM,EAMxC,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,mBAAmB,sGACqE,CAAC;AAEtG,8FAA8F;AAC9F,eAAO,MAAM,mBAAmB,qGACoE,CAAC;AAErG,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,qBAAqB,GAAG,uBAAuB,GAAG,eAAe,CAAC;AAElG,2FAA2F;AAC3F,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,WAAW,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,OAAO,kBAAkB,CAAC;IACzC,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,QAAQ,GAAG,aAAa,CAAC;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IACrC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACvC,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC;CACpD;AAqBD,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,UAAU,CA0BlE;AAOD,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAoB7D"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export const CAGE_REPORT_SCHEMA = "gantry.cage-report.v1";
|
|
2
|
+
/** Detect-after-the-fact limits, stated in every cage report. */
|
|
3
|
+
export const CAGE_LIMITS = [
|
|
4
|
+
"detects protected-path writes after the command exits; it does not block them while it runs",
|
|
5
|
+
"reads are not detected: the command can still read .env and other secrets",
|
|
6
|
+
"network and API side effects are not detected",
|
|
7
|
+
"writes outside the protected set, and outside the repository, are not checked",
|
|
8
|
+
"background processes that outlive the command can still write after the check",
|
|
9
|
+
];
|
|
10
|
+
/** One-line stderr form of {@link CAGE_LIMITS}; `--json` keeps the full list. */
|
|
11
|
+
export const CAGE_LIMITS_SUMMARY = "after-exit check only; reads, network calls and writes outside the protected set are not detected";
|
|
12
|
+
/** Printed once under a violation report: the path from cage to project-specific missions. */
|
|
13
|
+
export const CAGE_UPGRADE_FOOTER = "Need project-specific boundaries or task contracts? Run: npx -p @jeger-ai/opengantry gantry init";
|
|
14
|
+
const VIOLATION_EXIT_CODE = 3;
|
|
15
|
+
const RUNTIME_ERROR_EXIT_CODE = 2;
|
|
16
|
+
const RESOLVED_OUTCOMES = new Set(["reverted", "removed"]);
|
|
17
|
+
function cageStatus(input) {
|
|
18
|
+
const violations = input.changes.filter((c) => c.mode === "revert");
|
|
19
|
+
if (violations.length > 0) {
|
|
20
|
+
return violations.every((c) => RESOLVED_OUTCOMES.has(c.outcome)) ? "violations_reverted" : "violations_unresolved";
|
|
21
|
+
}
|
|
22
|
+
return input.runtimeError ? "runtime_error" : "ok";
|
|
23
|
+
}
|
|
24
|
+
function cageExitCode(status, input) {
|
|
25
|
+
if (status === "violations_reverted" || status === "violations_unresolved")
|
|
26
|
+
return VIOLATION_EXIT_CODE;
|
|
27
|
+
if (status === "runtime_error")
|
|
28
|
+
return RUNTIME_ERROR_EXIT_CODE;
|
|
29
|
+
if (input.commandSignal)
|
|
30
|
+
return input.signalExitCode(input.commandSignal);
|
|
31
|
+
return input.commandExitCode ?? RUNTIME_ERROR_EXIT_CODE;
|
|
32
|
+
}
|
|
33
|
+
export function buildCageReport(input) {
|
|
34
|
+
const status = cageStatus(input);
|
|
35
|
+
return {
|
|
36
|
+
report_schema: CAGE_REPORT_SCHEMA,
|
|
37
|
+
status,
|
|
38
|
+
exit_code: cageExitCode(status, input),
|
|
39
|
+
command: input.command,
|
|
40
|
+
command_exit_code: input.commandExitCode,
|
|
41
|
+
command_signal: input.commandSignal,
|
|
42
|
+
runtime_error: input.runtimeError,
|
|
43
|
+
root: input.root,
|
|
44
|
+
revert_mode: input.reportOnly ? "report_only" : "revert",
|
|
45
|
+
max_file_bytes: input.maxFileBytes,
|
|
46
|
+
protected_files: input.protectedFiles,
|
|
47
|
+
manifest_zones: input.manifestZones,
|
|
48
|
+
changes: input.changes.map((c) => ({
|
|
49
|
+
path: c.rel,
|
|
50
|
+
kind: c.kind,
|
|
51
|
+
rule: c.rule,
|
|
52
|
+
sha256_before: c.before?.sha256 ?? null,
|
|
53
|
+
sha256_after: c.after?.sha256 ?? null,
|
|
54
|
+
outcome: c.outcome,
|
|
55
|
+
error_code: c.errorCode,
|
|
56
|
+
})),
|
|
57
|
+
limits: CAGE_LIMITS,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function changeLine(c) {
|
|
61
|
+
const err = c.error_code ? ` ${c.error_code}` : "";
|
|
62
|
+
return ` ${c.outcome.padEnd(13)} ${c.kind.padEnd(8)} ${c.path} (${c.rule})${err}`;
|
|
63
|
+
}
|
|
64
|
+
/** Human summary (stderr), so it never mixes into the wrapped command's stdout. */
|
|
65
|
+
export function formatCageReport(report) {
|
|
66
|
+
const lines = [];
|
|
67
|
+
const n = report.changes.length;
|
|
68
|
+
if (report.runtime_error)
|
|
69
|
+
lines.push(`cage: command did not run: ${report.runtime_error}`);
|
|
70
|
+
if (n === 0) {
|
|
71
|
+
lines.push(`cage: ${report.status} — ${String(report.protected_files)} protected file(s) unchanged`);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
lines.push(`cage: ${report.status} — ${String(n)} protected change(s)`);
|
|
75
|
+
for (const c of report.changes)
|
|
76
|
+
lines.push(changeLine(c));
|
|
77
|
+
}
|
|
78
|
+
if (report.changes.some((c) => c.outcome === "detect_only")) {
|
|
79
|
+
lines.push(`cage: detect_only files exceeded the ${String(report.max_file_bytes)}-byte per-file cap or the total snapshot budget and were not restored`);
|
|
80
|
+
}
|
|
81
|
+
lines.push(`cage: exit ${String(report.exit_code)}; limits: ${CAGE_LIMITS_SUMMARY}`);
|
|
82
|
+
if (report.status === "violations_reverted" || report.status === "violations_unresolved") {
|
|
83
|
+
lines.push(`cage: ${CAGE_UPGRADE_FOOTER}`);
|
|
84
|
+
}
|
|
85
|
+
return lines;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=cage-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-report.js","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CageChange } from "./cage-snapshot.js";
|
|
2
|
+
/**
|
|
3
|
+
* - `reverted`: baseline bytes (or symlink) restored
|
|
4
|
+
* - `removed`: an added file was deleted
|
|
5
|
+
* - `kept`: report-only rule (lockfiles); change left in place
|
|
6
|
+
* - `reported`: `--report-only` run; change left in place
|
|
7
|
+
* - `detect_only`: no baseline bytes (over size cap or budget); change left in place
|
|
8
|
+
* - `revert_failed`: restore attempted and failed (`error_code` says why)
|
|
9
|
+
*/
|
|
10
|
+
export type CageOutcome = "reverted" | "removed" | "kept" | "reported" | "detect_only" | "revert_failed";
|
|
11
|
+
export interface CageResolvedChange extends CageChange {
|
|
12
|
+
outcome: CageOutcome;
|
|
13
|
+
errorCode: string | null;
|
|
14
|
+
}
|
|
15
|
+
export declare function resolveCageChanges(changes: readonly CageChange[], opts: {
|
|
16
|
+
reportOnly: boolean;
|
|
17
|
+
}): CageResolvedChange[];
|
|
18
|
+
//# sourceMappingURL=cage-revert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-revert.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-revert.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,oBAAoB,CAAC;AAEhE;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,aAAa,GAAG,eAAe,CAAC;AAEzG,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AA0CD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,IAAI,EAAE;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,GAC5B,kBAAkB,EAAE,CAUtB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
function errnoCode(err) {
|
|
5
|
+
const code = err?.code;
|
|
6
|
+
return typeof code === "string" ? code : "ERROR";
|
|
7
|
+
}
|
|
8
|
+
/** Write to a sibling temp file and rename over the target so a failed restore never truncates it. */
|
|
9
|
+
function restoreFile(abs, entry, bytes) {
|
|
10
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
11
|
+
const tmp = `${abs}.gantry-cage-${String(process.pid)}-${crypto.randomBytes(4).toString("hex")}`;
|
|
12
|
+
try {
|
|
13
|
+
fs.writeFileSync(tmp, bytes, { mode: entry.fileMode });
|
|
14
|
+
fs.chmodSync(tmp, entry.fileMode);
|
|
15
|
+
fs.renameSync(tmp, abs);
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
fs.rmSync(tmp, { force: true });
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function restoreSymlink(abs, target) {
|
|
23
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
24
|
+
fs.rmSync(abs, { force: true });
|
|
25
|
+
fs.symlinkSync(target, abs);
|
|
26
|
+
}
|
|
27
|
+
function revertChange(change) {
|
|
28
|
+
if (change.kind === "added") {
|
|
29
|
+
fs.rmSync(change.abs, { force: true });
|
|
30
|
+
return "removed";
|
|
31
|
+
}
|
|
32
|
+
const before = change.before;
|
|
33
|
+
if (before.type === "symlink") {
|
|
34
|
+
restoreSymlink(change.abs, before.linkTarget);
|
|
35
|
+
return "reverted";
|
|
36
|
+
}
|
|
37
|
+
if (!before.bytes)
|
|
38
|
+
return "detect_only";
|
|
39
|
+
restoreFile(change.abs, before, before.bytes);
|
|
40
|
+
return "reverted";
|
|
41
|
+
}
|
|
42
|
+
export function resolveCageChanges(changes, opts) {
|
|
43
|
+
return changes.map((change) => {
|
|
44
|
+
if (change.mode === "report")
|
|
45
|
+
return { ...change, outcome: "kept", errorCode: null };
|
|
46
|
+
if (opts.reportOnly)
|
|
47
|
+
return { ...change, outcome: "reported", errorCode: null };
|
|
48
|
+
try {
|
|
49
|
+
return { ...change, outcome: revertChange(change), errorCode: null };
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
return { ...change, outcome: "revert_failed", errorCode: errnoCode(err) };
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=cage-revert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-revert.js","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-revert.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-config protected set for `gantry cage`. Paths are matched without any
|
|
3
|
+
* manifest; manifest `forbidden_zones` are unioned in when the repo has one.
|
|
4
|
+
*/
|
|
5
|
+
export type CageRuleId = "ci_config" | "secrets" | "git_control" | "lockfile" | "manifest_forbidden_zone";
|
|
6
|
+
/** `revert`: restore baseline bytes and fail. `report`: list the change but keep it. */
|
|
7
|
+
export type CageRuleMode = "revert" | "report";
|
|
8
|
+
export declare const CAGE_RULE_MODES: Readonly<Record<CageRuleId, CageRuleMode>>;
|
|
9
|
+
/** Directory names skipped by the whole-tree basename scan (dependency and VCS bulk). */
|
|
10
|
+
export declare const CAGE_SCAN_SKIP_DIRS: ReadonlySet<string>;
|
|
11
|
+
/** A file or directory tree protected by absolute path. */
|
|
12
|
+
export interface CageTarget {
|
|
13
|
+
abs: string;
|
|
14
|
+
rule: CageRuleId;
|
|
15
|
+
}
|
|
16
|
+
export interface CagePlan {
|
|
17
|
+
root: string;
|
|
18
|
+
targets: CageTarget[];
|
|
19
|
+
manifestZoneCount: number;
|
|
20
|
+
}
|
|
21
|
+
/** Rule for a file found by the whole-tree scan, keyed on its basename. */
|
|
22
|
+
export declare function cageBasenameRule(name: string): CageRuleId | null;
|
|
23
|
+
export declare function buildCagePlan(root: string): CagePlan;
|
|
24
|
+
//# sourceMappingURL=cage-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-rules.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-rules.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,UAAU,GAAG,yBAAyB,CAAC;AAE1G,wFAAwF;AACxF,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE/C,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,YAAY,CAAC,CAOtE,CAAC;AAqBF,yFAAyF;AACzF,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,MAAM,CAMlD,CAAC;AAEH,2DAA2D;AAC3D,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAIhE;AAwCD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAQpD"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { REL_MANIFEST } from "../constants.js";
|
|
4
|
+
import { gitRun } from "../git/git.js";
|
|
5
|
+
import { loadManifest } from "../manifest.js";
|
|
6
|
+
export const CAGE_RULE_MODES = {
|
|
7
|
+
ci_config: "revert",
|
|
8
|
+
secrets: "revert",
|
|
9
|
+
git_control: "revert",
|
|
10
|
+
// Package managers legitimately rewrite lockfiles; surface the change, never undo it.
|
|
11
|
+
lockfile: "report",
|
|
12
|
+
manifest_forbidden_zone: "revert",
|
|
13
|
+
};
|
|
14
|
+
/** Root-anchored CI paths (files or directory trees). */
|
|
15
|
+
const CI_CONFIG_PATHS = [".github/workflows", ".gitlab-ci.yml", ".circleci", "azure-pipelines.yml"];
|
|
16
|
+
const LOCKFILE_NAMES = new Set([
|
|
17
|
+
"package-lock.json",
|
|
18
|
+
"npm-shrinkwrap.json",
|
|
19
|
+
"pnpm-lock.yaml",
|
|
20
|
+
"yarn.lock",
|
|
21
|
+
"bun.lock",
|
|
22
|
+
"bun.lockb",
|
|
23
|
+
"Cargo.lock",
|
|
24
|
+
"poetry.lock",
|
|
25
|
+
"Pipfile.lock",
|
|
26
|
+
"uv.lock",
|
|
27
|
+
"go.sum",
|
|
28
|
+
"Gemfile.lock",
|
|
29
|
+
"composer.lock",
|
|
30
|
+
]);
|
|
31
|
+
/** Directory names skipped by the whole-tree basename scan (dependency and VCS bulk). */
|
|
32
|
+
export const CAGE_SCAN_SKIP_DIRS = new Set([
|
|
33
|
+
"node_modules",
|
|
34
|
+
".git",
|
|
35
|
+
".venv",
|
|
36
|
+
"venv",
|
|
37
|
+
"__pycache__",
|
|
38
|
+
]);
|
|
39
|
+
/** Rule for a file found by the whole-tree scan, keyed on its basename. */
|
|
40
|
+
export function cageBasenameRule(name) {
|
|
41
|
+
if (name === ".env" || (name.startsWith(".env.") && name !== ".env.example"))
|
|
42
|
+
return "secrets";
|
|
43
|
+
if (LOCKFILE_NAMES.has(name))
|
|
44
|
+
return "lockfile";
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
function rootJoin(root, posixRel) {
|
|
48
|
+
return path.join(root, ...posixRel.split("/"));
|
|
49
|
+
}
|
|
50
|
+
function gitPathAbs(root, args) {
|
|
51
|
+
const r = gitRun(root, ["rev-parse", "--path-format=absolute", ...args]);
|
|
52
|
+
const out = r.stdout.trim();
|
|
53
|
+
return r.ok && out ? out : null;
|
|
54
|
+
}
|
|
55
|
+
/** `.git/config`, `.git/hooks/`, and the active `core.hooksPath` when it differs. */
|
|
56
|
+
function gitControlTargets(root) {
|
|
57
|
+
const common = gitPathAbs(root, ["--git-common-dir"]);
|
|
58
|
+
if (!common)
|
|
59
|
+
return [];
|
|
60
|
+
const out = [path.join(common, "config"), path.join(common, "hooks")];
|
|
61
|
+
const activeHooks = gitPathAbs(root, ["--git-path", "hooks"]);
|
|
62
|
+
if (activeHooks)
|
|
63
|
+
out.push(activeHooks);
|
|
64
|
+
return [...new Set(out.map((p) => path.resolve(p)))];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Union of every skill's `forbidden_zones` when a manifest exists. An unreadable or
|
|
68
|
+
* invalid manifest throws so cage fails closed before the wrapped command runs.
|
|
69
|
+
*/
|
|
70
|
+
function manifestZoneTargets(root) {
|
|
71
|
+
if (!fs.existsSync(rootJoin(root, REL_MANIFEST)))
|
|
72
|
+
return [];
|
|
73
|
+
const manifest = loadManifest(root);
|
|
74
|
+
const zones = new Set();
|
|
75
|
+
for (const skill of Object.values(manifest.skills)) {
|
|
76
|
+
for (const raw of skill.forbidden_zones ?? []) {
|
|
77
|
+
const norm = raw.trim().replace(/\\/g, "/").replace(/\/+$/, "");
|
|
78
|
+
if (!norm || norm.startsWith("/") || norm.split("/").includes(".."))
|
|
79
|
+
continue;
|
|
80
|
+
zones.add(norm);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return [...zones].sort().map((z) => rootJoin(root, z));
|
|
84
|
+
}
|
|
85
|
+
export function buildCagePlan(root) {
|
|
86
|
+
const zones = manifestZoneTargets(root);
|
|
87
|
+
const targets = [
|
|
88
|
+
...CI_CONFIG_PATHS.map((rel) => ({ abs: rootJoin(root, rel), rule: "ci_config" })),
|
|
89
|
+
...gitControlTargets(root).map((abs) => ({ abs, rule: "git_control" })),
|
|
90
|
+
...zones.map((abs) => ({ abs, rule: "manifest_forbidden_zone" })),
|
|
91
|
+
];
|
|
92
|
+
return { root, targets, manifestZoneCount: zones.length };
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=cage-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-rules.js","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type CageReport } from "./cage-report.js";
|
|
2
|
+
/** Per-file in-memory snapshot cap; larger revert-mode files are detect-only. */
|
|
3
|
+
export declare const CAGE_DEFAULT_MAX_FILE_BYTES: number;
|
|
4
|
+
/** Total in-memory snapshot budget across all protected files. */
|
|
5
|
+
export declare const CAGE_DEFAULT_MAX_TOTAL_BYTES: number;
|
|
6
|
+
export interface CageRunOptions {
|
|
7
|
+
command: readonly string[];
|
|
8
|
+
/** Working directory for the command; the cage root is its git top-level, else this dir. */
|
|
9
|
+
cwd?: string;
|
|
10
|
+
reportOnly?: boolean;
|
|
11
|
+
maxFileBytes?: number;
|
|
12
|
+
maxTotalBytes?: number;
|
|
13
|
+
}
|
|
14
|
+
/** Zero-config root: the enclosing git work tree when there is one, otherwise the directory itself. */
|
|
15
|
+
export declare function resolveCageRoot(cwd: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Snapshot the protected set, run the command, diff, and revert protected changes.
|
|
18
|
+
* Bytes stay in memory only; nothing is written outside the restored paths.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runCage(opts: CageRunOptions): Promise<CageReport>;
|
|
21
|
+
//# sourceMappingURL=cage-run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-run.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-run.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAMpE,iFAAiF;AACjF,eAAO,MAAM,2BAA2B,QAAkB,CAAC;AAC3D,kEAAkE;AAClE,eAAO,MAAM,4BAA4B,QAAmB,CAAC;AAE7D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,4FAA4F;IAC5F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,uGAAuG;AACvG,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CA2BvE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { getRepoRoot } from "../git/git.js";
|
|
3
|
+
import { buildCageReport } from "./cage-report.js";
|
|
4
|
+
import { resolveCageChanges } from "./cage-revert.js";
|
|
5
|
+
import { buildCagePlan } from "./cage-rules.js";
|
|
6
|
+
import { diffCageSnapshots, takeCageSnapshot } from "./cage-snapshot.js";
|
|
7
|
+
import { signalExitCode, spawnCaged } from "./cage-process.js";
|
|
8
|
+
/** Per-file in-memory snapshot cap; larger revert-mode files are detect-only. */
|
|
9
|
+
export const CAGE_DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
10
|
+
/** Total in-memory snapshot budget across all protected files. */
|
|
11
|
+
export const CAGE_DEFAULT_MAX_TOTAL_BYTES = 64 * 1024 * 1024;
|
|
12
|
+
/** Zero-config root: the enclosing git work tree when there is one, otherwise the directory itself. */
|
|
13
|
+
export function resolveCageRoot(cwd) {
|
|
14
|
+
try {
|
|
15
|
+
return getRepoRoot(cwd);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return path.resolve(cwd);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Snapshot the protected set, run the command, diff, and revert protected changes.
|
|
23
|
+
* Bytes stay in memory only; nothing is written outside the restored paths.
|
|
24
|
+
*/
|
|
25
|
+
export async function runCage(opts) {
|
|
26
|
+
const cwd = path.resolve(opts.cwd ?? process.cwd());
|
|
27
|
+
const root = resolveCageRoot(cwd);
|
|
28
|
+
const maxFileBytes = opts.maxFileBytes ?? CAGE_DEFAULT_MAX_FILE_BYTES;
|
|
29
|
+
const maxTotalBytes = opts.maxTotalBytes ?? CAGE_DEFAULT_MAX_TOTAL_BYTES;
|
|
30
|
+
const reportOnly = opts.reportOnly === true;
|
|
31
|
+
// Plan before spawning: an invalid manifest fails closed and the command never runs.
|
|
32
|
+
const plan = buildCagePlan(root);
|
|
33
|
+
const before = takeCageSnapshot(plan, { keepBytes: !reportOnly, maxFileBytes, maxTotalBytes });
|
|
34
|
+
const proc = await spawnCaged(opts.command, cwd);
|
|
35
|
+
const after = takeCageSnapshot(plan, { keepBytes: false, maxFileBytes, maxTotalBytes });
|
|
36
|
+
const changes = resolveCageChanges(diffCageSnapshots(before, after), { reportOnly });
|
|
37
|
+
return buildCageReport({
|
|
38
|
+
command: opts.command[0] ?? "",
|
|
39
|
+
commandExitCode: proc.code,
|
|
40
|
+
commandSignal: proc.signal,
|
|
41
|
+
runtimeError: proc.spawnError,
|
|
42
|
+
root,
|
|
43
|
+
reportOnly,
|
|
44
|
+
maxFileBytes,
|
|
45
|
+
protectedFiles: before.entries.size,
|
|
46
|
+
manifestZones: plan.manifestZoneCount,
|
|
47
|
+
changes,
|
|
48
|
+
signalExitCode,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=cage-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-run.js","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-run.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAmB,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/D,iFAAiF;AACjF,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAC3D,kEAAkE;AAClE,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAW7D,uGAAuG;AACvG,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAoB;IAChD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,2BAA2B,CAAC;IACtE,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,4BAA4B,CAAC;IACzE,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC;IAE5C,qFAAqF;IACrF,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC,CAAC;IAC/F,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC,CAAC;IACxF,MAAM,OAAO,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;IAErF,OAAO,eAAe,CAAC;QACrB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE;QAC9B,eAAe,EAAE,IAAI,CAAC,IAAI;QAC1B,aAAa,EAAE,IAAI,CAAC,MAAM;QAC1B,YAAY,EAAE,IAAI,CAAC,UAAU;QAC7B,IAAI;QACJ,UAAU;QACV,YAAY;QACZ,cAAc,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;QACnC,aAAa,EAAE,IAAI,CAAC,iBAAiB;QACrC,OAAO;QACP,cAAc;KACf,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type CagePlan, type CageRuleId, type CageRuleMode } from "./cage-rules.js";
|
|
2
|
+
export interface CageEntry {
|
|
3
|
+
abs: string;
|
|
4
|
+
/** POSIX path relative to the cage root (may start with `../` for a linked worktree git dir). */
|
|
5
|
+
rel: string;
|
|
6
|
+
rule: CageRuleId;
|
|
7
|
+
mode: CageRuleMode;
|
|
8
|
+
type: "file" | "symlink";
|
|
9
|
+
sha256: string;
|
|
10
|
+
size: number;
|
|
11
|
+
fileMode: number;
|
|
12
|
+
/** Baseline bytes for revert; null when over the size cap, budget, or report-only. */
|
|
13
|
+
bytes: Buffer | null;
|
|
14
|
+
linkTarget: string | null;
|
|
15
|
+
}
|
|
16
|
+
export interface CageSnapshot {
|
|
17
|
+
entries: Map<string, CageEntry>;
|
|
18
|
+
}
|
|
19
|
+
export interface CageSnapshotOptions {
|
|
20
|
+
/** Keep file bytes in memory so the snapshot can restore them. */
|
|
21
|
+
keepBytes: boolean;
|
|
22
|
+
maxFileBytes: number;
|
|
23
|
+
maxTotalBytes: number;
|
|
24
|
+
}
|
|
25
|
+
export interface CageChange {
|
|
26
|
+
abs: string;
|
|
27
|
+
rel: string;
|
|
28
|
+
kind: "added" | "modified" | "deleted";
|
|
29
|
+
rule: CageRuleId;
|
|
30
|
+
mode: CageRuleMode;
|
|
31
|
+
before: CageEntry | null;
|
|
32
|
+
after: CageEntry | null;
|
|
33
|
+
}
|
|
34
|
+
export declare function takeCageSnapshot(plan: CagePlan, opts: CageSnapshotOptions): CageSnapshot;
|
|
35
|
+
export declare function diffCageSnapshots(before: CageSnapshot, after: CageSnapshot): CageChange[];
|
|
36
|
+
//# sourceMappingURL=cage-snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-snapshot.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-snapshot.ts"],"names":[],"mappings":"AAIA,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,YAAY,EAClB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,iGAAiG;IACjG,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,sFAAsF;IACtF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;CACzB;AA+FD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,mBAAmB,GAAG,YAAY,CAQxF;AAOD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,UAAU,EAAE,CAezF"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { toPosixRel } from "../cli-io.js";
|
|
5
|
+
import { CAGE_RULE_MODES, CAGE_SCAN_SKIP_DIRS, cageBasenameRule, } from "./cage-rules.js";
|
|
6
|
+
const HASH_CHUNK_BYTES = 1024 * 1024;
|
|
7
|
+
function sha256Hex(data) {
|
|
8
|
+
return crypto.createHash("sha256").update(data).digest("hex");
|
|
9
|
+
}
|
|
10
|
+
/** Streamed hash so files over the in-memory cap are still change-detected. */
|
|
11
|
+
function hashFileChunked(abs) {
|
|
12
|
+
const hash = crypto.createHash("sha256");
|
|
13
|
+
const fd = fs.openSync(abs, "r");
|
|
14
|
+
try {
|
|
15
|
+
const buf = Buffer.alloc(HASH_CHUNK_BYTES);
|
|
16
|
+
let n;
|
|
17
|
+
while ((n = fs.readSync(fd, buf, 0, buf.length, null)) > 0) {
|
|
18
|
+
hash.update(buf.subarray(0, n));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
fs.closeSync(fd);
|
|
23
|
+
}
|
|
24
|
+
return hash.digest("hex");
|
|
25
|
+
}
|
|
26
|
+
function readEntry(abs, rule, ctx) {
|
|
27
|
+
const st = fs.lstatSync(abs);
|
|
28
|
+
const mode = CAGE_RULE_MODES[rule];
|
|
29
|
+
const base = { abs, rel: toPosixRel(ctx.root, abs), rule, mode, fileMode: st.mode & 0o7777 };
|
|
30
|
+
if (st.isSymbolicLink()) {
|
|
31
|
+
const target = fs.readlinkSync(abs);
|
|
32
|
+
return { ...base, type: "symlink", sha256: sha256Hex(`symlink\0${target}`), size: 0, bytes: null, linkTarget: target };
|
|
33
|
+
}
|
|
34
|
+
if (!st.isFile())
|
|
35
|
+
return null;
|
|
36
|
+
const keep = ctx.opts.keepBytes && mode === "revert" && st.size <= ctx.opts.maxFileBytes && st.size <= ctx.budget;
|
|
37
|
+
if (!keep) {
|
|
38
|
+
return { ...base, type: "file", sha256: hashFileChunked(abs), size: st.size, bytes: null, linkTarget: null };
|
|
39
|
+
}
|
|
40
|
+
// One read for hash and bytes, so the restored content is exactly what was hashed.
|
|
41
|
+
const bytes = fs.readFileSync(abs);
|
|
42
|
+
ctx.budget -= bytes.length;
|
|
43
|
+
return { ...base, type: "file", sha256: sha256Hex(bytes), size: bytes.length, bytes, linkTarget: null };
|
|
44
|
+
}
|
|
45
|
+
function captureEntry(abs, rule, ctx) {
|
|
46
|
+
const existing = ctx.entries.get(abs);
|
|
47
|
+
// A path matched by several rules keeps the strictest one (revert beats report).
|
|
48
|
+
if (existing && (existing.mode === "revert" || CAGE_RULE_MODES[rule] === "report"))
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
const entry = readEntry(abs, rule, ctx);
|
|
52
|
+
if (entry)
|
|
53
|
+
ctx.entries.set(abs, entry);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Vanished or unreadable between listing and reading: not part of this snapshot.
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Visit files and symlinks under `absDir` without following directory symlinks. */
|
|
60
|
+
function walkTree(absDir, skipDirs, visit) {
|
|
61
|
+
let dirents;
|
|
62
|
+
try {
|
|
63
|
+
dirents = fs.readdirSync(absDir, { withFileTypes: true });
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
for (const d of dirents) {
|
|
69
|
+
const child = path.join(absDir, d.name);
|
|
70
|
+
if (d.isDirectory()) {
|
|
71
|
+
if (!skipDirs?.has(d.name))
|
|
72
|
+
walkTree(child, skipDirs, visit);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (d.isFile() || d.isSymbolicLink())
|
|
76
|
+
visit(child);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function captureTarget(abs, rule, ctx) {
|
|
80
|
+
let st;
|
|
81
|
+
try {
|
|
82
|
+
st = fs.lstatSync(abs);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (st.isDirectory()) {
|
|
88
|
+
walkTree(abs, null, (child) => captureEntry(child, rule, ctx));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
captureEntry(abs, rule, ctx);
|
|
92
|
+
}
|
|
93
|
+
export function takeCageSnapshot(plan, opts) {
|
|
94
|
+
const ctx = { root: plan.root, opts, budget: opts.maxTotalBytes, entries: new Map() };
|
|
95
|
+
for (const target of plan.targets)
|
|
96
|
+
captureTarget(target.abs, target.rule, ctx);
|
|
97
|
+
walkTree(plan.root, CAGE_SCAN_SKIP_DIRS, (abs) => {
|
|
98
|
+
const rule = cageBasenameRule(path.basename(abs));
|
|
99
|
+
if (rule)
|
|
100
|
+
captureEntry(abs, rule, ctx);
|
|
101
|
+
});
|
|
102
|
+
return { entries: ctx.entries };
|
|
103
|
+
}
|
|
104
|
+
function entryChanged(a, b) {
|
|
105
|
+
// mtime is ignored on purpose: a bare `touch` is not a mutation.
|
|
106
|
+
return a.sha256 !== b.sha256 || a.type !== b.type || a.fileMode !== b.fileMode;
|
|
107
|
+
}
|
|
108
|
+
export function diffCageSnapshots(before, after) {
|
|
109
|
+
const keys = new Set([...before.entries.keys(), ...after.entries.keys()]);
|
|
110
|
+
const changes = [];
|
|
111
|
+
for (const abs of keys) {
|
|
112
|
+
const b = before.entries.get(abs) ?? null;
|
|
113
|
+
const a = after.entries.get(abs) ?? null;
|
|
114
|
+
let kind = null;
|
|
115
|
+
if (b && !a)
|
|
116
|
+
kind = "deleted";
|
|
117
|
+
else if (!b && a)
|
|
118
|
+
kind = "added";
|
|
119
|
+
else if (b && a && entryChanged(b, a))
|
|
120
|
+
kind = "modified";
|
|
121
|
+
if (!kind)
|
|
122
|
+
continue;
|
|
123
|
+
const ref = (b ?? a);
|
|
124
|
+
changes.push({ abs, rel: ref.rel, kind, rule: ref.rule, mode: ref.mode, before: b, after: a });
|
|
125
|
+
}
|
|
126
|
+
return changes.sort((x, y) => x.rel.localeCompare(y.rel));
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=cage-snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-snapshot.js","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
/** Shared by `gantry cage` and the standalone `opengantry-cage` bin so the two never drift. */
|
|
3
|
+
export declare function configureCageCommand(cmd: Command): Command;
|
|
4
|
+
export declare function registerCageCommands(program: Command): void;
|
|
5
|
+
//# sourceMappingURL=program-cage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program-cage.d.ts","sourceRoot":"","sources":["../../src/cli/program-cage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,+FAA+F;AAC/F,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAc1D;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE3D"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { runCageCommand } from "./commands/cage.js";
|
|
2
|
+
/** Shared by `gantry cage` and the standalone `opengantry-cage` bin so the two never drift. */
|
|
3
|
+
export function configureCageCommand(cmd) {
|
|
4
|
+
return cmd
|
|
5
|
+
.description("Zero-config: run a command, then revert changes to CI configs, .env secrets, git hooks/config and manifest forbidden zones (lockfiles reported)")
|
|
6
|
+
.option("--json", "Emit the digest-only cage report as JSON on stdout")
|
|
7
|
+
.option("--report-only", "Detect and report protected changes without reverting them")
|
|
8
|
+
.option("--max-file-bytes <n>", "Per-file in-memory snapshot cap; larger files are detect-only")
|
|
9
|
+
.allowUnknownOption(true)
|
|
10
|
+
.passThroughOptions()
|
|
11
|
+
.argument("<command...>", "Command to run after --")
|
|
12
|
+
.action(async (command, opts) => {
|
|
13
|
+
await runCageCommand({ command, ...opts });
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function registerCageCommands(program) {
|
|
17
|
+
configureCageCommand(program.command("cage"));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=program-cage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program-cage.js","sourceRoot":"","sources":["../../src/cli/program-cage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,+FAA+F;AAC/F,MAAM,UAAU,oBAAoB,CAAC,GAAY;IAC/C,OAAO,GAAG;SACP,WAAW,CACV,iJAAiJ,CAClJ;SACA,MAAM,CAAC,QAAQ,EAAE,oDAAoD,CAAC;SACtE,MAAM,CAAC,eAAe,EAAE,4DAA4D,CAAC;SACrF,MAAM,CAAC,sBAAsB,EAAE,+DAA+D,CAAC;SAC/F,kBAAkB,CAAC,IAAI,CAAC;SACxB,kBAAkB,EAAE;SACpB,QAAQ,CAAC,cAAc,EAAE,yBAAyB,CAAC;SACnD,MAAM,CAAC,KAAK,EAAE,OAAiB,EAAE,IAAqE,EAAE,EAAE;QACzG,MAAM,cAAc,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,oBAAoB,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/cli/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/cli/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,wBAAgB,YAAY,IAAI,OAAO,CA6BtC"}
|
package/dist/cli/program.js
CHANGED
|
@@ -7,6 +7,7 @@ import { registerMissionCommands } from "./program-mission.js";
|
|
|
7
7
|
import { registerWorkflowCommands } from "./program-workflow.js";
|
|
8
8
|
import { registerOrgControlPlaneCommands } from "./program-org.js";
|
|
9
9
|
import { registerMcpCommands } from "./program-mcp.js";
|
|
10
|
+
import { registerCageCommands } from "./program-cage.js";
|
|
10
11
|
import { registerBuiltinDomains } from "./lib/domains/index.js";
|
|
11
12
|
export { CLI_VERSION } from "./lib/constants.js";
|
|
12
13
|
export function buildProgram() {
|
|
@@ -31,6 +32,7 @@ export function buildProgram() {
|
|
|
31
32
|
registerWorkflowCommands(program);
|
|
32
33
|
registerOrgControlPlaneCommands(program);
|
|
33
34
|
registerMcpCommands(program);
|
|
35
|
+
registerCageCommands(program);
|
|
34
36
|
return program;
|
|
35
37
|
}
|
|
36
38
|
//# sourceMappingURL=program.js.map
|
package/dist/cli/program.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.js","sourceRoot":"","sources":["../../src/cli/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,UAAU,YAAY;IAC1B,sBAAsB,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,OAAO,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9E,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,EAAE;QAC3B,IAAI,GAAG,CAAC,IAAI,KAAK,yBAAyB,IAAI,GAAG,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YAC/E,OAAO;QACT,CAAC;QACD,IAAI,GAAG,CAAC,IAAI,KAAK,2BAA2B,EAAE,CAAC;YAC7C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CACZ,mBAAmB,EACnB,kFAAkF,CACnF,CAAC;IACF,6BAA6B,CAAC,OAAO,CAAC,CAAC;IAEvC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,wBAAwB,CAAC,OAAO,CAAC,CAAC;IAClC,+BAA+B,CAAC,OAAO,CAAC,CAAC;IACzC,mBAAmB,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"program.js","sourceRoot":"","sources":["../../src/cli/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,UAAU,YAAY;IAC1B,sBAAsB,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,OAAO,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9E,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,EAAE;QAC3B,IAAI,GAAG,CAAC,IAAI,KAAK,yBAAyB,IAAI,GAAG,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YAC/E,OAAO;QACT,CAAC;QACD,IAAI,GAAG,CAAC,IAAI,KAAK,2BAA2B,EAAE,CAAC;YAC7C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CACZ,mBAAmB,EACnB,kFAAkF,CACnF,CAAC;IACF,6BAA6B,CAAC,OAAO,CAAC,CAAC;IAEvC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,wBAAwB,CAAC,OAAO,CAAC,CAAC;IAClC,+BAA+B,CAAC,OAAO,CAAC,CAAC;IACzC,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7B,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAE9B,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeger-ai/opengantry",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
4
4
|
"description": "Open Source Gantry — vendor-neutral GXT substrate and Gantry CLI for local git-native agent governance",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"gantry": "dist/cli/index.js",
|
|
8
|
-
"gapman": "dist/cli/index.js"
|
|
8
|
+
"gapman": "dist/cli/index.js",
|
|
9
|
+
"opengantry-cage": "dist/cli/cage-bin.js"
|
|
9
10
|
},
|
|
10
11
|
"exports": {
|
|
11
12
|
".": "./dist/cli/index.js",
|