@jeger-ai/opengantry 3.7.1 → 3.8.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 +10 -0
- package/dist/cli/commands/cage.d.ts +10 -1
- package/dist/cli/commands/cage.d.ts.map +1 -1
- package/dist/cli/commands/cage.js +44 -7
- package/dist/cli/commands/cage.js.map +1 -1
- package/dist/cli/lib/cage/cage-config.d.ts +29 -0
- package/dist/cli/lib/cage/cage-config.d.ts.map +1 -0
- package/dist/cli/lib/cage/cage-config.js +143 -0
- package/dist/cli/lib/cage/cage-config.js.map +1 -0
- package/dist/cli/lib/cage/cage-push-guard.d.ts +5 -2
- package/dist/cli/lib/cage/cage-push-guard.d.ts.map +1 -1
- package/dist/cli/lib/cage/cage-push-guard.js +16 -18
- package/dist/cli/lib/cage/cage-push-guard.js.map +1 -1
- package/dist/cli/lib/cage/cage-report.d.ts +19 -1
- package/dist/cli/lib/cage/cage-report.d.ts.map +1 -1
- package/dist/cli/lib/cage/cage-report.js +16 -1
- package/dist/cli/lib/cage/cage-report.js.map +1 -1
- package/dist/cli/lib/cage/cage-revert.d.ts +1 -1
- package/dist/cli/lib/cage/cage-rules.d.ts +49 -3
- package/dist/cli/lib/cage/cage-rules.d.ts.map +1 -1
- package/dist/cli/lib/cage/cage-rules.js +145 -7
- package/dist/cli/lib/cage/cage-rules.js.map +1 -1
- package/dist/cli/lib/cage/cage-run.d.ts +7 -0
- package/dist/cli/lib/cage/cage-run.d.ts.map +1 -1
- package/dist/cli/lib/cage/cage-run.js +19 -7
- package/dist/cli/lib/cage/cage-run.js.map +1 -1
- package/dist/cli/lib/cage/cage-snapshot.d.ts +11 -0
- package/dist/cli/lib/cage/cage-snapshot.d.ts.map +1 -1
- package/dist/cli/lib/cage/cage-snapshot.js +60 -18
- package/dist/cli/lib/cage/cage-snapshot.js.map +1 -1
- package/dist/cli/lib/cage/cage-suggest.d.ts +28 -0
- package/dist/cli/lib/cage/cage-suggest.d.ts.map +1 -0
- package/dist/cli/lib/cage/cage-suggest.js +164 -0
- package/dist/cli/lib/cage/cage-suggest.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 +9 -2
- package/dist/cli/program-cage.d.ts.map +1 -1
- package/dist/cli/program-cage.js +40 -6
- package/dist/cli/program-cage.js.map +1 -1
- package/package.json +1 -1
- package/templates/.gitagent/foreman/SUBSTRATE.version.json +1 -1
- package/templates/integrations/compatibility.json +1 -1
package/README.md
CHANGED
|
@@ -152,6 +152,14 @@ While the session runs, cage checks about once a second and restores changes to
|
|
|
152
152
|
|
|
153
153
|
Nothing is printed into the agent's screen while it runs: events go to a session log in your temp dir (path shown at start), with a terminal bell per restore. If the agent keeps rewriting the same file, cage stops restoring it after 3 tries, marks it contested and restores it once at exit.
|
|
154
154
|
|
|
155
|
+
To protect more of your own repo (migrations, infrastructure, key files), let cage propose rules, review them, and commit `.cage.yaml`:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
gantry cage suggest --write # writes .cage.yaml.suggested; review it, keep what you want as .cage.yaml, commit
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`.cage.yaml` can only add protection; it can never switch a built-in rule off. To relax one path for a single run, pass `--allow-override <path>`: cage then reports that path instead of restoring it, and says so at start and in the report.
|
|
162
|
+
|
|
155
163
|
Cage restores; it does not block. A change can be committed in the second before the next check, `git push --no-verify` skips the push guard, and a committed change stays in local history (cage restores the working tree only). Reads, network calls and writes outside the protected set are not seen. `--no-watch` checks once at exit instead. For scope enforced on every write, use missions (below). Details: [`docs/FEATURES.md`](docs/FEATURES.md#zero-config-cage-gantry-cage).
|
|
156
164
|
|
|
157
165
|
---
|
|
@@ -231,6 +239,8 @@ On failure, external agents ingest `findings[]`:
|
|
|
231
239
|
}
|
|
232
240
|
```
|
|
233
241
|
|
|
242
|
+
**v3.8.0:** per-project cage rules: `.cage.yaml` adds paths and globs to the protected set (additive only, self-protected, fail closed), `gantry cage suggest` proposes them for review, and `--allow-override <path>` reports instead of restoring one path for a run, always announced ([ADR-0048](.gitagent/out-of-scope/ADR-0048-cage-trust-model.md)). See [Try it in 60 seconds](#try-it-in-60-seconds-gantry-cage).
|
|
243
|
+
|
|
234
244
|
**v3.7.1:** `gantry cage` restores protected files live during interactive agent sessions (default; `--no-watch` for exit-only) and refuses `git push` of protected paths from inside the session. See [Try it in 60 seconds](#try-it-in-60-seconds-gantry-cage).
|
|
235
245
|
|
|
236
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).
|
|
@@ -6,10 +6,19 @@ export interface CageCliOptions {
|
|
|
6
6
|
/** Commander sets false for `--no-watch`. */
|
|
7
7
|
watch?: boolean;
|
|
8
8
|
watchIntervalMs?: string;
|
|
9
|
+
allowOverride?: string[];
|
|
9
10
|
}
|
|
10
11
|
export declare function runCageCommand(options: CageCliOptions): Promise<void>;
|
|
11
|
-
/** `gantry cage-guard pre-push --root <dir
|
|
12
|
+
/** `gantry cage-guard pre-push --root <dir> [--plan <file>]`: called by the cage session pre-push hook. */
|
|
12
13
|
export declare function runCageGuardPrePush(options: {
|
|
13
14
|
root: string;
|
|
15
|
+
plan?: string;
|
|
14
16
|
}): Promise<void>;
|
|
17
|
+
export interface CageSuggestCliOptions {
|
|
18
|
+
write?: boolean;
|
|
19
|
+
force?: boolean;
|
|
20
|
+
json?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** `gantry cage suggest`: propose `.cage.yaml` entries; prints them, or writes `.cage.yaml.suggested`. */
|
|
23
|
+
export declare function runCageSuggestCommand(options: CageSuggestCliOptions): Promise<void>;
|
|
15
24
|
//# sourceMappingURL=cage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cage.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/cage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cage.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/cage.ts"],"names":[],"mappings":"AAgBA,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;IACtB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AASD,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C3E;AAED,2GAA2G;AAC3G,wBAAsB,mBAAmB,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAejG;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,0GAA0G;AAC1G,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBzF"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
2
3
|
import { logError, readStdinIfEmpty, setExitCode } from "../lib/cli-io.js";
|
|
3
4
|
import { emitCliJson, runUserCommandAsync } from "../lib/command-boundary.js";
|
|
4
5
|
import { CAGE_SESSION_LOG_ENV, findPushViolations } from "../lib/cage/cage-push-guard.js";
|
|
5
|
-
import { formatCageReport } from "../lib/cage/cage-report.js";
|
|
6
|
-
import { buildCagePlan } from "../lib/cage/cage-rules.js";
|
|
7
|
-
import { runCage } from "../lib/cage/cage-run.js";
|
|
6
|
+
import { formatCageOverrideBanner, formatCageReport } from "../lib/cage/cage-report.js";
|
|
7
|
+
import { buildCagePlan, parseSerializedCagePlan } from "../lib/cage/cage-rules.js";
|
|
8
|
+
import { resolveCageRoot, runCage } from "../lib/cage/cage-run.js";
|
|
9
|
+
import { assertOutsideCageSession, formatCageSuggestionsYaml, suggestCageRules, writeCageSuggestions, } from "../lib/cage/cage-suggest.js";
|
|
10
|
+
import { CAGE_CONFIG_FILE } from "../lib/cage/cage-config.js";
|
|
8
11
|
function parseNonNegativeInt(raw) {
|
|
9
12
|
if (raw === undefined)
|
|
10
13
|
return { ok: true, value: undefined };
|
|
@@ -34,11 +37,18 @@ export async function runCageCommand(options) {
|
|
|
34
37
|
maxFileBytes: max.value,
|
|
35
38
|
watch: options.watch !== false,
|
|
36
39
|
watchIntervalMs: interval.value,
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
allowOverride: options.allowOverride,
|
|
41
|
+
// The only lines printed before the command starts; nothing is written while it runs except a bell.
|
|
42
|
+
onStart: ({ sessionLog, protectedFiles, watch, overrides, configCommitted }) => {
|
|
39
43
|
const mode = watch ? "watching" : "checking at exit";
|
|
40
44
|
const logPart = sessionLog ? `; live events: ${sessionLog}` : "";
|
|
41
45
|
console.error(`cage: ${mode} ${String(protectedFiles)} protected file(s)${logPart}`);
|
|
46
|
+
if (configCommitted === false) {
|
|
47
|
+
console.error(`cage: warning: ${CAGE_CONFIG_FILE} is untracked or has uncommitted changes; review and commit it`);
|
|
48
|
+
}
|
|
49
|
+
const banner = formatCageOverrideBanner(overrides);
|
|
50
|
+
if (banner)
|
|
51
|
+
console.error(banner);
|
|
42
52
|
},
|
|
43
53
|
});
|
|
44
54
|
if (options.json) {
|
|
@@ -52,10 +62,12 @@ export async function runCageCommand(options) {
|
|
|
52
62
|
setExitCode(report.exit_code);
|
|
53
63
|
});
|
|
54
64
|
}
|
|
55
|
-
/** `gantry cage-guard pre-push --root <dir
|
|
65
|
+
/** `gantry cage-guard pre-push --root <dir> [--plan <file>]`: called by the cage session pre-push hook. */
|
|
56
66
|
export async function runCageGuardPrePush(options) {
|
|
57
67
|
const stdin = await readStdinIfEmpty("");
|
|
58
|
-
|
|
68
|
+
// The session plan (with its overrides) when the hook passes one; a fresh plan otherwise.
|
|
69
|
+
const plan = options.plan ? parseSerializedCagePlan(fs.readFileSync(options.plan, "utf8")) : buildCagePlan(options.root);
|
|
70
|
+
const violations = findPushViolations(plan, stdin);
|
|
59
71
|
if (violations.length === 0)
|
|
60
72
|
return;
|
|
61
73
|
const list = violations.map((v) => `${v.path} (${v.rule})`).join(", ");
|
|
@@ -68,4 +80,29 @@ export async function runCageGuardPrePush(options) {
|
|
|
68
80
|
}
|
|
69
81
|
setExitCode(1);
|
|
70
82
|
}
|
|
83
|
+
/** `gantry cage suggest`: propose `.cage.yaml` entries; prints them, or writes `.cage.yaml.suggested`. */
|
|
84
|
+
export async function runCageSuggestCommand(options) {
|
|
85
|
+
await runUserCommandAsync({ json: options.json }, () => {
|
|
86
|
+
assertOutsideCageSession();
|
|
87
|
+
const root = resolveCageRoot(process.cwd());
|
|
88
|
+
const result = suggestCageRules(root);
|
|
89
|
+
const yaml = formatCageSuggestionsYaml(result, fs.existsSync(path.join(root, CAGE_CONFIG_FILE)));
|
|
90
|
+
const n = result.suggestions.length;
|
|
91
|
+
let written = null;
|
|
92
|
+
if (options.write && n > 0)
|
|
93
|
+
written = writeCageSuggestions(root, yaml, options.force === true);
|
|
94
|
+
if (options.json) {
|
|
95
|
+
emitCliJson({ ...result, written: written ? path.basename(written) : null });
|
|
96
|
+
}
|
|
97
|
+
else if (!options.write) {
|
|
98
|
+
process.stdout.write(yaml);
|
|
99
|
+
}
|
|
100
|
+
const covered = `${String(result.already_covered)} already protected`;
|
|
101
|
+
if (written)
|
|
102
|
+
console.error(`cage suggest: wrote ${path.basename(written)} (${String(n)} entr${n === 1 ? "y" : "ies"}; ${covered}); review it, then move what you keep into ${CAGE_CONFIG_FILE}`);
|
|
103
|
+
else
|
|
104
|
+
console.error(`cage suggest: ${String(n)} new suggestion(s); ${covered}`);
|
|
105
|
+
return Promise.resolve();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
71
108
|
//# sourceMappingURL=cage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cage.js","sourceRoot":"","sources":["../../../src/cli/commands/cage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"cage.js","sourceRoot":"","sources":["../../../src/cli/commands/cage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Per-project cage config at the cage root. Additive only: it can protect more, never less. */
|
|
2
|
+
export declare const CAGE_CONFIG_FILE = ".cage.yaml";
|
|
3
|
+
export type CageConfigMode = "revert" | "report";
|
|
4
|
+
/** One `protect:` entry: a root-relative path (file or directory tree) or a glob over root-relative paths. */
|
|
5
|
+
export interface CageProtectEntry {
|
|
6
|
+
kind: "path" | "glob";
|
|
7
|
+
/** Normalized POSIX value: no leading `./`, no trailing `/`. */
|
|
8
|
+
value: string;
|
|
9
|
+
mode: CageConfigMode;
|
|
10
|
+
}
|
|
11
|
+
export interface CageConfig {
|
|
12
|
+
present: boolean;
|
|
13
|
+
entries: CageProtectEntry[];
|
|
14
|
+
}
|
|
15
|
+
/** Root-relative POSIX path or glob; rejects absolute, `..`, and empty values. */
|
|
16
|
+
export declare function normalizeCageRelPath(raw: string): string | null;
|
|
17
|
+
/**
|
|
18
|
+
* Read `.cage.yaml` at the cage root. A missing file is the zero-config default; anything unreadable,
|
|
19
|
+
* malformed or subtractive throws so cage fails closed before the wrapped command runs.
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadCageConfig(root: string): CageConfig;
|
|
22
|
+
/**
|
|
23
|
+
* Whether `.cage.yaml` is on record: tracked and identical to `HEAD`. Null outside a git work tree.
|
|
24
|
+
* Unreviewed rules can only protect more, so cage warns rather than refuses.
|
|
25
|
+
*/
|
|
26
|
+
export declare function cageConfigCommitted(root: string): boolean | null;
|
|
27
|
+
/** `*` and `?` stay inside one path segment; `**` spans any depth (`**\/x` also matches top-level `x`). */
|
|
28
|
+
export declare function cageGlobToRegExp(glob: string): RegExp;
|
|
29
|
+
//# sourceMappingURL=cage-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-config.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-config.ts"],"names":[],"mappings":"AAMA,gGAAgG;AAChG,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEjD,8GAA8G;AAC9G,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,cAAc,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAoCD,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK/D;AA2CD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAUvD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAMhE;AAED,2GAA2G;AAC3G,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiBrD"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseDocument } from "yaml";
|
|
4
|
+
import { GantryUserError } from "../errors.js";
|
|
5
|
+
import { gitRun } from "../git/git.js";
|
|
6
|
+
/** Per-project cage config at the cage root. Additive only: it can protect more, never less. */
|
|
7
|
+
export const CAGE_CONFIG_FILE = ".cage.yaml";
|
|
8
|
+
/** Keys that would loosen protection. Named in the error so authors know relaxation is a runtime flag. */
|
|
9
|
+
const SUBTRACTIVE_KEYS = new Set([
|
|
10
|
+
"relax",
|
|
11
|
+
"exclude",
|
|
12
|
+
"excludes",
|
|
13
|
+
"allow",
|
|
14
|
+
"allow_override",
|
|
15
|
+
"allow_overrides",
|
|
16
|
+
"ignore",
|
|
17
|
+
"unprotect",
|
|
18
|
+
"override",
|
|
19
|
+
"overrides",
|
|
20
|
+
"disable",
|
|
21
|
+
"skip",
|
|
22
|
+
]);
|
|
23
|
+
const ENTRY_KEYS = new Set(["path", "glob", "mode"]);
|
|
24
|
+
function configError(message) {
|
|
25
|
+
return new GantryUserError("GXT_CAGE_CONFIG_INVALID", `cage: ${CAGE_CONFIG_FILE}: ${message}`, `${CAGE_CONFIG_FILE} is additive only (protect: entries). Relax a rule for one run with --allow-override <path>.`, 2);
|
|
26
|
+
}
|
|
27
|
+
function unknownKey(key, where) {
|
|
28
|
+
if (SUBTRACTIVE_KEYS.has(key)) {
|
|
29
|
+
return configError(`${where}: "${key}" would remove protection; subtractive keys are not allowed`);
|
|
30
|
+
}
|
|
31
|
+
return configError(`${where}: unknown key "${key}"`);
|
|
32
|
+
}
|
|
33
|
+
/** Root-relative POSIX path or glob; rejects absolute, `..`, and empty values. */
|
|
34
|
+
export function normalizeCageRelPath(raw) {
|
|
35
|
+
const norm = raw.trim().replace(/\\/g, "/").replace(/^(\.\/)+/, "").replace(/\/+$/, "");
|
|
36
|
+
if (!norm || norm === "." || norm.startsWith("/") || /^[A-Za-z]:/.test(norm))
|
|
37
|
+
return null;
|
|
38
|
+
if (norm.split("/").some((seg) => seg === ".." || seg === "." || seg === ""))
|
|
39
|
+
return null;
|
|
40
|
+
return norm;
|
|
41
|
+
}
|
|
42
|
+
function parseEntry(raw, index) {
|
|
43
|
+
const where = `protect[${String(index)}]`;
|
|
44
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
45
|
+
throw configError(`${where}: expected a mapping with path: or glob:`);
|
|
46
|
+
}
|
|
47
|
+
const obj = raw;
|
|
48
|
+
for (const key of Object.keys(obj)) {
|
|
49
|
+
if (!ENTRY_KEYS.has(key))
|
|
50
|
+
throw unknownKey(key, where);
|
|
51
|
+
}
|
|
52
|
+
const hasPath = "path" in obj;
|
|
53
|
+
if (hasPath === "glob" in obj)
|
|
54
|
+
throw configError(`${where}: set exactly one of path: or glob:`);
|
|
55
|
+
const kind = hasPath ? "path" : "glob";
|
|
56
|
+
const rawValue = obj[kind];
|
|
57
|
+
const value = typeof rawValue === "string" ? normalizeCageRelPath(rawValue) : null;
|
|
58
|
+
if (!value)
|
|
59
|
+
throw configError(`${where}: ${kind} must be a root-relative path without ".." or a leading "/"`);
|
|
60
|
+
const mode = obj.mode ?? "revert";
|
|
61
|
+
if (mode !== "revert" && mode !== "report")
|
|
62
|
+
throw configError(`${where}: mode must be revert or report`);
|
|
63
|
+
return { kind, value, mode };
|
|
64
|
+
}
|
|
65
|
+
function parseConfigText(text) {
|
|
66
|
+
const doc = parseDocument(text, { uniqueKeys: true });
|
|
67
|
+
if (doc.errors.length > 0)
|
|
68
|
+
throw configError(`invalid YAML: ${doc.errors[0].message.split("\n")[0]}`);
|
|
69
|
+
let data;
|
|
70
|
+
try {
|
|
71
|
+
// No aliases: a protect list has no use for them, and they are the YAML expansion-bomb vector.
|
|
72
|
+
data = doc.toJS({ maxAliasCount: 0 });
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
throw configError(`invalid YAML: ${err instanceof Error ? err.message : String(err)}`);
|
|
76
|
+
}
|
|
77
|
+
if (data === null || data === undefined)
|
|
78
|
+
return { present: true, entries: [] };
|
|
79
|
+
if (typeof data !== "object" || Array.isArray(data))
|
|
80
|
+
throw configError("expected a mapping with a protect: list");
|
|
81
|
+
const obj = data;
|
|
82
|
+
for (const key of Object.keys(obj)) {
|
|
83
|
+
if (key !== "protect")
|
|
84
|
+
throw unknownKey(key, "top level");
|
|
85
|
+
}
|
|
86
|
+
const protect = obj.protect ?? [];
|
|
87
|
+
if (!Array.isArray(protect))
|
|
88
|
+
throw configError("protect: must be a list");
|
|
89
|
+
return { present: true, entries: protect.map((e, i) => parseEntry(e, i)) };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Read `.cage.yaml` at the cage root. A missing file is the zero-config default; anything unreadable,
|
|
93
|
+
* malformed or subtractive throws so cage fails closed before the wrapped command runs.
|
|
94
|
+
*/
|
|
95
|
+
export function loadCageConfig(root) {
|
|
96
|
+
const file = path.join(root, CAGE_CONFIG_FILE);
|
|
97
|
+
let text;
|
|
98
|
+
try {
|
|
99
|
+
text = fs.readFileSync(file, "utf8");
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
if (err.code === "ENOENT")
|
|
103
|
+
return { present: false, entries: [] };
|
|
104
|
+
throw configError(`unreadable (${err.code ?? "ERROR"})`);
|
|
105
|
+
}
|
|
106
|
+
return parseConfigText(text);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Whether `.cage.yaml` is on record: tracked and identical to `HEAD`. Null outside a git work tree.
|
|
110
|
+
* Unreviewed rules can only protect more, so cage warns rather than refuses.
|
|
111
|
+
*/
|
|
112
|
+
export function cageConfigCommitted(root) {
|
|
113
|
+
const tracked = gitRun(root, ["ls-files", "--", CAGE_CONFIG_FILE]);
|
|
114
|
+
if (!tracked.ok)
|
|
115
|
+
return null;
|
|
116
|
+
if (!tracked.stdout.trim())
|
|
117
|
+
return false;
|
|
118
|
+
const status = gitRun(root, ["status", "--porcelain", "--", CAGE_CONFIG_FILE]);
|
|
119
|
+
return status.ok ? status.stdout.trim() === "" : null;
|
|
120
|
+
}
|
|
121
|
+
/** `*` and `?` stay inside one path segment; `**` spans any depth (`**\/x` also matches top-level `x`). */
|
|
122
|
+
export function cageGlobToRegExp(glob) {
|
|
123
|
+
let re = "";
|
|
124
|
+
for (let i = 0; i < glob.length; i += 1) {
|
|
125
|
+
const ch = glob[i];
|
|
126
|
+
if (ch === "*" && glob[i + 1] === "*") {
|
|
127
|
+
const slash = glob[i + 2] === "/";
|
|
128
|
+
re += slash ? "(?:.*/)?" : ".*";
|
|
129
|
+
i += slash ? 2 : 1;
|
|
130
|
+
}
|
|
131
|
+
else if (ch === "*") {
|
|
132
|
+
re += "[^/]*";
|
|
133
|
+
}
|
|
134
|
+
else if (ch === "?") {
|
|
135
|
+
re += "[^/]";
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
re += ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return new RegExp(`^${re}$`);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=cage-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cage-config.js","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,8 +11,11 @@ export interface CagePushGuard {
|
|
|
11
11
|
* Create a temporary hooks dir outside the repo and the env that points the caged process tree at it.
|
|
12
12
|
* Returns null outside a git work tree. Nothing is written into the repository.
|
|
13
13
|
*/
|
|
14
|
-
export declare function createCagePushGuard(
|
|
15
|
-
/**
|
|
14
|
+
export declare function createCagePushGuard(plan: CagePlan, sessionLogPath: string | null): CagePushGuard | null;
|
|
15
|
+
/**
|
|
16
|
+
* Rule for a repo-relative path in an outgoing commit, resolved exactly like the live snapshot.
|
|
17
|
+
* Report-mode paths (lockfiles, report entries, `--allow-override`) never block a push.
|
|
18
|
+
*/
|
|
16
19
|
export declare function pushGuardRule(plan: CagePlan, rel: string): CageRuleId | null;
|
|
17
20
|
export interface PushGuardViolation {
|
|
18
21
|
path: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cage-push-guard.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-push-guard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cage-push-guard.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-push-guard.ts"],"names":[],"mappings":"AAKA,OAAO,EAAuC,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AA2BtG,mEAAmE;AACnE,eAAO,MAAM,oBAAoB,4BAA4B,CAAC;AAK9D,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,yGAAyG;IACzG,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,OAAO,IAAI,IAAI,CAAC;CACjB;AAwCD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,GAAG,IAAI,CAavG;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAG5E;AAMD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,oHAAoH;AACpH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAa7F"}
|
|
@@ -2,9 +2,8 @@ import fs from "node:fs";
|
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { toPosixRel } from "../cli-io.js";
|
|
6
5
|
import { gitRun } from "../git/git.js";
|
|
7
|
-
import {
|
|
6
|
+
import { classifyCagePath, serializeCagePlan } from "./cage-rules.js";
|
|
8
7
|
/** Standard client-side git hooks; each session wrapper chains to the repo's real hook of the same name. */
|
|
9
8
|
const GIT_HOOK_NAMES = [
|
|
10
9
|
"applypatch-msg",
|
|
@@ -30,6 +29,8 @@ const GIT_HOOK_NAMES = [
|
|
|
30
29
|
const ZERO_SHA = /^0+$/;
|
|
31
30
|
/** Env var the session hook reads to find the cage session log. */
|
|
32
31
|
export const CAGE_SESSION_LOG_ENV = "GANTRY_CAGE_SESSION_LOG";
|
|
32
|
+
/** The session plan, written next to the hooks so the push guard checks exactly what the session protects. */
|
|
33
|
+
const PLAN_FILE = "cage-plan.json";
|
|
33
34
|
function shellQuote(s) {
|
|
34
35
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
35
36
|
}
|
|
@@ -42,10 +43,10 @@ function activeHooksDir(root) {
|
|
|
42
43
|
function cliEntry() {
|
|
43
44
|
return fileURLToPath(new URL("../../index.js", import.meta.url));
|
|
44
45
|
}
|
|
45
|
-
function hookScript(name, realHooks, root) {
|
|
46
|
+
function hookScript(name, realHooks, root, planFile) {
|
|
46
47
|
const real = shellQuote(path.join(realHooks, name));
|
|
47
48
|
const guard = name === "pre-push"
|
|
48
|
-
? `stdin_copy="$(cat)"\nprintf '%s\\n' "$stdin_copy" | ${shellQuote(process.execPath)} ${shellQuote(cliEntry())} cage-guard pre-push --root ${shellQuote(root)} || exit 1\n`
|
|
49
|
+
? `stdin_copy="$(cat)"\nprintf '%s\\n' "$stdin_copy" | ${shellQuote(process.execPath)} ${shellQuote(cliEntry())} cage-guard pre-push --root ${shellQuote(root)} --plan ${shellQuote(planFile)} || exit 1\n`
|
|
49
50
|
: "";
|
|
50
51
|
const chain = name === "pre-push"
|
|
51
52
|
? `if [ -x ${real} ]; then printf '%s\\n' "$stdin_copy" | ${real} "$@"; exit $?; fi\n`
|
|
@@ -65,32 +66,29 @@ function gitConfigEnv(hooksDir) {
|
|
|
65
66
|
* Create a temporary hooks dir outside the repo and the env that points the caged process tree at it.
|
|
66
67
|
* Returns null outside a git work tree. Nothing is written into the repository.
|
|
67
68
|
*/
|
|
68
|
-
export function createCagePushGuard(
|
|
69
|
+
export function createCagePushGuard(plan, sessionLogPath) {
|
|
70
|
+
const root = plan.root;
|
|
69
71
|
const realHooks = activeHooksDir(root);
|
|
70
72
|
if (!realHooks)
|
|
71
73
|
return null;
|
|
72
74
|
const hooksDir = fs.mkdtempSync(path.join(os.tmpdir(), "gantry-cage-hooks-"));
|
|
75
|
+
const planFile = path.join(hooksDir, PLAN_FILE);
|
|
76
|
+
fs.writeFileSync(planFile, serializeCagePlan(plan), { mode: 0o600 });
|
|
73
77
|
for (const name of GIT_HOOK_NAMES) {
|
|
74
|
-
fs.writeFileSync(path.join(hooksDir, name), hookScript(name, realHooks, root), { mode: 0o755 });
|
|
78
|
+
fs.writeFileSync(path.join(hooksDir, name), hookScript(name, realHooks, root, planFile), { mode: 0o755 });
|
|
75
79
|
}
|
|
76
80
|
const env = { ...gitConfigEnv(hooksDir) };
|
|
77
81
|
if (sessionLogPath)
|
|
78
82
|
env[CAGE_SESSION_LOG_ENV] = sessionLogPath;
|
|
79
83
|
return { hooksDir, env, dispose: () => fs.rmSync(hooksDir, { recursive: true, force: true }) };
|
|
80
84
|
}
|
|
81
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* Rule for a repo-relative path in an outgoing commit, resolved exactly like the live snapshot.
|
|
87
|
+
* Report-mode paths (lockfiles, report entries, `--allow-override`) never block a push.
|
|
88
|
+
*/
|
|
82
89
|
export function pushGuardRule(plan, rel) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
continue;
|
|
86
|
-
const base = toPosixRel(plan.root, t.abs);
|
|
87
|
-
if (base.startsWith(".."))
|
|
88
|
-
continue;
|
|
89
|
-
if (rel === base || rel.startsWith(`${base}/`))
|
|
90
|
-
return t.rule;
|
|
91
|
-
}
|
|
92
|
-
const rule = cageBasenameRule(path.posix.basename(rel));
|
|
93
|
-
return rule && CAGE_RULE_MODES[rule] === "revert" ? rule : null;
|
|
90
|
+
const hit = classifyCagePath(plan, rel);
|
|
91
|
+
return hit && hit.mode === "revert" ? hit.rule : null;
|
|
94
92
|
}
|
|
95
93
|
function outgoingRange(localSha, remoteSha) {
|
|
96
94
|
return ZERO_SHA.test(remoteSha) ? [localSha, "--not", "--remotes"] : [`${remoteSha}..${localSha}`];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cage-push-guard.js","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-push-guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cage-push-guard.js","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-push-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CageRuleId, type CageRuleSource } from "./cage-rules.js";
|
|
2
2
|
import type { CageOutcome, CageResolvedChange } from "./cage-revert.js";
|
|
3
3
|
export declare const CAGE_REPORT_SCHEMA: "gantry.cage-report.v1";
|
|
4
4
|
/** Limits with `--no-watch` (after-exit check only), stated in every such report. */
|
|
@@ -17,6 +17,9 @@ export interface CageReportChange {
|
|
|
17
17
|
path: string;
|
|
18
18
|
kind: "added" | "modified" | "deleted";
|
|
19
19
|
rule: CageRuleId;
|
|
20
|
+
source: CageRuleSource;
|
|
21
|
+
/** A revert rule downgraded to report by `--allow-override`. */
|
|
22
|
+
overridden: boolean;
|
|
20
23
|
sha256_before: string | null;
|
|
21
24
|
sha256_after: string | null;
|
|
22
25
|
outcome: CageOutcome;
|
|
@@ -36,6 +39,17 @@ export interface CageReport {
|
|
|
36
39
|
max_file_bytes: number;
|
|
37
40
|
protected_files: number;
|
|
38
41
|
manifest_zones: number;
|
|
42
|
+
/**
|
|
43
|
+
* `.cage.yaml` at the cage root: whether it exists, how many protect entries it adds, and whether it is
|
|
44
|
+
* committed unchanged (null without a config or outside git).
|
|
45
|
+
*/
|
|
46
|
+
cage_config: {
|
|
47
|
+
present: boolean;
|
|
48
|
+
entries: number;
|
|
49
|
+
committed: boolean | null;
|
|
50
|
+
};
|
|
51
|
+
/** Paths downgraded from revert to report for this run by `--allow-override`. */
|
|
52
|
+
overrides: string[];
|
|
39
53
|
changes: CageReportChange[];
|
|
40
54
|
watch: {
|
|
41
55
|
enabled: boolean;
|
|
@@ -60,12 +74,16 @@ export interface CageReportInput {
|
|
|
60
74
|
maxFileBytes: number;
|
|
61
75
|
protectedFiles: number;
|
|
62
76
|
manifestZones: number;
|
|
77
|
+
cageConfig: CageReport["cage_config"];
|
|
78
|
+
overrides: readonly string[];
|
|
63
79
|
changes: readonly CageResolvedChange[];
|
|
64
80
|
watch: CageReport["watch"];
|
|
65
81
|
pushGuard: CageReport["push_guard"];
|
|
66
82
|
signalExitCode: (signal: NodeJS.Signals) => number;
|
|
67
83
|
}
|
|
68
84
|
export declare function buildCageReport(input: CageReportInput): CageReport;
|
|
85
|
+
/** Stderr banner for `--allow-override`, printed at start and again in the exit summary. */
|
|
86
|
+
export declare function formatCageOverrideBanner(overrides: readonly string[]): string | null;
|
|
69
87
|
/** Human summary (stderr), so it never mixes into the wrapped command's stdout. */
|
|
70
88
|
export declare function formatCageReport(report: CageReport): string[];
|
|
71
89
|
//# sourceMappingURL=cage-report.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cage-report.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"cage-report.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-report.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cageRuleSource } from "./cage-rules.js";
|
|
1
2
|
export const CAGE_REPORT_SCHEMA = "gantry.cage-report.v1";
|
|
2
3
|
/** Limits with `--no-watch` (after-exit check only), stated in every such report. */
|
|
3
4
|
export const CAGE_LIMITS = [
|
|
@@ -55,10 +56,14 @@ export function buildCageReport(input) {
|
|
|
55
56
|
max_file_bytes: input.maxFileBytes,
|
|
56
57
|
protected_files: input.protectedFiles,
|
|
57
58
|
manifest_zones: input.manifestZones,
|
|
59
|
+
cage_config: input.cageConfig,
|
|
60
|
+
overrides: [...input.overrides],
|
|
58
61
|
changes: input.changes.map((c) => ({
|
|
59
62
|
path: c.rel,
|
|
60
63
|
kind: c.kind,
|
|
61
64
|
rule: c.rule,
|
|
65
|
+
source: cageRuleSource(c.rule),
|
|
66
|
+
overridden: c.overridden,
|
|
62
67
|
sha256_before: c.before?.sha256 ?? null,
|
|
63
68
|
sha256_after: c.after?.sha256 ?? null,
|
|
64
69
|
outcome: c.outcome,
|
|
@@ -71,7 +76,14 @@ export function buildCageReport(input) {
|
|
|
71
76
|
}
|
|
72
77
|
function changeLine(c) {
|
|
73
78
|
const err = c.error_code ? ` ${c.error_code}` : "";
|
|
74
|
-
|
|
79
|
+
const over = c.overridden ? ", overridden" : "";
|
|
80
|
+
return ` ${c.outcome.padEnd(13)} ${c.kind.padEnd(8)} ${c.path} (${c.rule}${over})${err}`;
|
|
81
|
+
}
|
|
82
|
+
/** Stderr banner for `--allow-override`, printed at start and again in the exit summary. */
|
|
83
|
+
export function formatCageOverrideBanner(overrides) {
|
|
84
|
+
if (overrides.length === 0)
|
|
85
|
+
return null;
|
|
86
|
+
return `cage: OVERRIDE (--allow-override): changes are reported, not restored, under: ${overrides.join(", ")}`;
|
|
75
87
|
}
|
|
76
88
|
function sessionLines(report) {
|
|
77
89
|
const out = [];
|
|
@@ -108,6 +120,9 @@ export function formatCageReport(report) {
|
|
|
108
120
|
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`);
|
|
109
121
|
}
|
|
110
122
|
lines.push(...sessionLines(report));
|
|
123
|
+
const banner = formatCageOverrideBanner(report.overrides);
|
|
124
|
+
if (banner)
|
|
125
|
+
lines.push(banner);
|
|
111
126
|
const summary = report.watch.enabled ? CAGE_WATCH_LIMITS_SUMMARY : CAGE_LIMITS_SUMMARY;
|
|
112
127
|
lines.push(`cage: exit ${String(report.exit_code)}; limits: ${summary}`);
|
|
113
128
|
if (report.status === "violations_reverted" || report.status === "violations_unresolved") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cage-report.js","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-report.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cage-report.js","sourceRoot":"","sources":["../../../../src/cli/lib/cage/cage-report.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import type { CageChange } from "./cage-snapshot.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* - `reverted`: baseline bytes (or symlink) restored
|
|
4
4
|
* - `removed`: an added file was deleted
|
|
5
|
-
* - `kept`: report-only rule (lockfiles); change left in place
|
|
5
|
+
* - `kept`: report-only rule (lockfiles, report entries, `--allow-override`); change left in place
|
|
6
6
|
* - `reported`: `--report-only` run; change left in place
|
|
7
7
|
* - `detect_only`: no baseline bytes (over size cap or budget); change left in place
|
|
8
8
|
* - `revert_failed`: restore attempted and failed (`error_code` says why)
|