@cleocode/git-shim 2026.4.154 → 2026.4.157

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 ADDED
@@ -0,0 +1,147 @@
1
+ # @cleocode/git-shim
2
+
3
+ Harness-agnostic `git` PATH override that fences agent (worker | lead |
4
+ subagent) git invocations. Provides two layers of enforcement:
5
+
6
+ 1. **T1118 denylist** — branch-mutation operations
7
+ (`checkout`, `switch`, `branch -D`, `worktree add`, `reset --hard`,
8
+ `rebase`, `push --force`, etc.).
9
+ 2. **T1591 boundary fence** — contextual rules tied to the
10
+ worktree-by-default model (ADR-055) + worktree-merge integration
11
+ (ADR-062):
12
+ - **(a)** `git add` MUST stage paths inside the active worktree.
13
+ - **(b)** `git commit -m "<msg>"` MUST embed a CLEO task ID
14
+ (`T<NUM>`).
15
+ - **(c)** `git merge` MUST be invoked by `completeAgentWorktreeViaMerge`
16
+ (signalled via `CLEO_ORCHESTRATE_MERGE=1`).
17
+ - **(d)** `git cherry-pick <ref>` MUST NOT take a `task/T<NUM>` source
18
+ (cherry-pick from worktree branches is the deprecated integration
19
+ path superseded by ADR-062).
20
+
21
+ Every block and every bypass is recorded in
22
+ `<XDG_DATA_HOME ?? ~/.local/share>/cleo/audit/git-shim.jsonl`.
23
+
24
+ ## Installation
25
+
26
+ The shim ships as the `git` bin entry of this package. The orchestrator
27
+ materialises a `git` symlink inside `<projectRoot>/.cleo/bin/` (or any
28
+ shim directory) via `installShimSymlink(...)` and prepends that
29
+ directory to the spawned agent's `PATH`.
30
+
31
+ ## Activation gate
32
+
33
+ The shim only enforces when the agent role is restricted:
34
+
35
+ ```bash
36
+ CLEO_AGENT_ROLE=worker # or lead, subagent
37
+ ```
38
+
39
+ Orchestrators (the absence of `CLEO_AGENT_ROLE` or
40
+ `CLEO_AGENT_ROLE=orchestrator`) bypass the shim entirely — this keeps
41
+ orchestration code paths fast and unencumbered.
42
+
43
+ ## Environment contract
44
+
45
+ | Variable | Set by | Purpose |
46
+ |---|---|---|
47
+ | `CLEO_AGENT_ROLE` | orchestrator (spawn) | Activates the fence for restricted roles. |
48
+ | `CLEO_WORKTREE_ROOT` | orchestrator (spawn) | Explicit worktree path; auto-detected from cwd otherwise. |
49
+ | `CLEO_TASK_ID` | orchestrator (spawn) | Active task ID; auto-derived from worktree path otherwise. |
50
+ | `CLEO_ORCHESTRATE_MERGE` | `completeAgentWorktreeViaMerge` (T1587) | Single-purpose grant — allows `git merge`. See below. |
51
+ | `CLEO_ALLOW_BRANCH_OPS` | operator (manual) | Single-shot bypass for the legacy denylist. Audited. |
52
+ | `CLEO_ALLOW_GIT` | operator (emergency) | Universal bypass for any T1591 boundary block. Audited. |
53
+ | `CLEO_AUDIT_LOG_PATH` | tests | Override audit log location. |
54
+ | `CLEO_REAL_GIT_PATH` | tests | Skip PATH walk; use this binary as real git. |
55
+ | `CLEO_SHIM_MARKER` | installer (optional) | Path-fragment that identifies the shim dir. Default: `.cleo/bin/git-shim`. |
56
+
57
+ ## `CLEO_ORCHESTRATE_MERGE=1` contract (T1587 / ADR-062 integration)
58
+
59
+ `packages/core/src/spawn/branch-lock.ts::completeAgentWorktreeViaMerge`
60
+ is the **only** sanctioned entry point for `git merge` on a CLEO task
61
+ branch. It MUST set `CLEO_ORCHESTRATE_MERGE=1` in the env passed to the
62
+ spawned `git merge --no-ff` process. The shim's boundary (c) refuses any
63
+ other `git merge` invocation from a restricted role.
64
+
65
+ Concretely (see `branch-lock.ts:830`):
66
+
67
+ ```ts
68
+ execFileSync('git', ['merge', '--no-ff', branch, '-m', subject], {
69
+ cwd: gitRoot,
70
+ encoding: 'utf-8',
71
+ stdio: ['pipe', 'pipe', 'pipe'],
72
+ env: { ...process.env, CLEO_ORCHESTRATE_MERGE: '1' },
73
+ });
74
+ ```
75
+
76
+ If you discover a code path that needs to invoke `git merge` from
77
+ restricted-role context **other than** `completeAgentWorktreeViaMerge`,
78
+ file a follow-up task — do NOT silently set `CLEO_ORCHESTRATE_MERGE=1`
79
+ elsewhere. The narrow scope of this env var is what makes the boundary
80
+ auditable.
81
+
82
+ `--abort`, `--continue`, and `--quit` flag invocations are exempt —
83
+ they do not perform a merge.
84
+
85
+ ## Bypass workflow
86
+
87
+ For a legitimate emergency (e.g. operator hotfix, incident triage):
88
+
89
+ ```bash
90
+ # One-off bypass; audit entry written to git-shim.jsonl.
91
+ CLEO_ALLOW_GIT=1 git <subcommand> ...
92
+ ```
93
+
94
+ The bypass is logged with full context (subcommand, args, cwd, role,
95
+ task_id, worktree_path). Reviewers can list bypasses via:
96
+
97
+ ```bash
98
+ jq 'select(.outcome | startswith("bypassed"))' \
99
+ ~/.local/share/cleo/audit/git-shim.jsonl
100
+ ```
101
+
102
+ ## Audit record schema
103
+
104
+ ```ts
105
+ interface AuditRecord {
106
+ ts: string; // ISO 8601
107
+ outcome: 'blocked' | 'bypassed-allow-git' | 'bypassed-orchestrate-merge';
108
+ boundary: 'a' | 'b' | 'c' | 'd' | 'denylist';
109
+ code: string; // E_GIT_OP_BLOCKED | E_GIT_BOUNDARY_*
110
+ subcommand: string;
111
+ args: string[];
112
+ cwd: string;
113
+ worktree_path: string | null;
114
+ task_id: string | null;
115
+ role: string | null;
116
+ context: Record<string, string>;
117
+ }
118
+ ```
119
+
120
+ The schema is project-agnostic: the audit log under
121
+ `~/.local/share/cleo/audit/` is shared across every CLEO-managed
122
+ project on the host.
123
+
124
+ ## Defense-in-depth pipeline
125
+
126
+ The git-binary fence (this package) is one layer in a multi-checkpoint
127
+ pipeline:
128
+
129
+ | Layer | Package | Catches |
130
+ |---|---|---|
131
+ | Git binary | `@cleocode/git-shim` (this) | Direct git invocations from agents |
132
+ | Commit-msg hook | `@cleocode/core` (T1588) | Editor-flow commits (no inline `-m`) |
133
+ | Drift watchdog | `@cleocode/core` (T1594) | Files modified outside worktree |
134
+ | Pre-push reconcile | `@cleocode/core` (T1595) | Branch state drift before push |
135
+ | Sync linter | CI (T1598) | Review-time policy mismatches |
136
+
137
+ Both T1588 (hook) and T1591 (shim, boundary b) enforce the
138
+ commit-subject T-ID rule. This is intentional defense in depth: a
139
+ developer who disables the local hook still trips the shim.
140
+
141
+ ## References
142
+
143
+ - ADR-055 — worktree-by-default agent isolation
144
+ - ADR-062 — worktree integration via `git merge --no-ff` (not cherry-pick)
145
+ - T1118 — original branch-lock engine (denylist)
146
+ - T1587 — `completeAgentWorktreeViaMerge` (sets `CLEO_ORCHESTRATE_MERGE=1`)
147
+ - T1591 — this fence (boundary a/b/c/d)
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=boundary-enforcement.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boundary-enforcement.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/boundary-enforcement.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Boundary-enforcement tests for the git-shim (T1591).
3
+ *
4
+ * Covers the four boundaries:
5
+ * (a) git add path inside agent worktree
6
+ * (b) git commit subject contains task ID
7
+ * (c) git merge requires CLEO_ORCHESTRATE_MERGE=1
8
+ * (d) git cherry-pick refuses task/T<NUM> sources
9
+ *
10
+ * Plus override (`CLEO_ALLOW_GIT=1`) + audit-log persistence.
11
+ *
12
+ * Tests are project-agnostic: fixture lives under a tmpdir using a fake
13
+ * project name (`fake-project-T1591`). No cleocode-specific paths.
14
+ *
15
+ * @task T1591
16
+ */
17
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
18
+ import { tmpdir } from 'node:os';
19
+ import { join } from 'node:path';
20
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
21
+ import { resolveAuditLogPath, writeAuditRecord } from '../audit-log.js';
22
+ import { validateAddPaths, validateCherryPickSource, validateCommitSubject, validateMergeAllowed, } from '../boundary.js';
23
+ import { extractTaskIdFromWorktreePath, isPathInsideWorktree, resolveActiveWorktree, resolveCleoWorktreesRoot, } from '../worktree-path.js';
24
+ let workspace;
25
+ let auditLogPath;
26
+ const ENV_KEYS = [
27
+ 'CLEO_AGENT_ROLE',
28
+ 'CLEO_WORKTREE_ROOT',
29
+ 'CLEO_TASK_ID',
30
+ 'CLEO_ALLOW_GIT',
31
+ 'CLEO_ORCHESTRATE_MERGE',
32
+ 'CLEO_AUDIT_LOG_PATH',
33
+ 'XDG_DATA_HOME',
34
+ ];
35
+ const savedEnv = {};
36
+ beforeEach(() => {
37
+ for (const key of ENV_KEYS)
38
+ savedEnv[key] = process.env[key];
39
+ workspace = mkdtempSync(join(tmpdir(), 'cleo-git-shim-T1591-'));
40
+ // Treat the workspace as a fake XDG_DATA_HOME so worktree paths land here.
41
+ process.env['XDG_DATA_HOME'] = workspace;
42
+ auditLogPath = join(workspace, 'audit', 'git-shim.jsonl');
43
+ process.env['CLEO_AUDIT_LOG_PATH'] = auditLogPath;
44
+ });
45
+ afterEach(() => {
46
+ for (const key of ENV_KEYS) {
47
+ const v = savedEnv[key];
48
+ if (v === undefined)
49
+ delete process.env[key];
50
+ else
51
+ process.env[key] = v;
52
+ }
53
+ if (existsSync(workspace))
54
+ rmSync(workspace, { recursive: true, force: true });
55
+ });
56
+ // ---------------------------------------------------------------------------
57
+ // worktree-path resolution (project-agnostic)
58
+ // ---------------------------------------------------------------------------
59
+ describe('worktree-path resolution', () => {
60
+ it('resolveCleoWorktreesRoot uses XDG_DATA_HOME', () => {
61
+ const root = resolveCleoWorktreesRoot();
62
+ expect(root).toBe(join(workspace, 'cleo', 'worktrees'));
63
+ });
64
+ it('extractTaskIdFromWorktreePath returns taskId from canonical layout', () => {
65
+ const wt = join(workspace, 'cleo', 'worktrees', 'abc123def4567890', 'T1591');
66
+ const taskId = extractTaskIdFromWorktreePath(wt);
67
+ expect(taskId).toBe('T1591');
68
+ });
69
+ it('extractTaskIdFromWorktreePath returns null outside worktree root', () => {
70
+ expect(extractTaskIdFromWorktreePath('/var/tmp/somewhere')).toBeNull();
71
+ });
72
+ it('isPathInsideWorktree detects descendants', () => {
73
+ const wt = join(workspace, 'cleo', 'worktrees', 'p1', 'T1591');
74
+ expect(isPathInsideWorktree(join(wt, 'src/file.ts'), wt)).toBe(true);
75
+ expect(isPathInsideWorktree(wt, wt)).toBe(true);
76
+ expect(isPathInsideWorktree('/var/tmp/other', wt)).toBe(false);
77
+ });
78
+ it('resolveActiveWorktree honours CLEO_WORKTREE_ROOT + CLEO_TASK_ID', () => {
79
+ const wt = join(workspace, 'cleo', 'worktrees', 'p1', 'T9999');
80
+ mkdirSync(wt, { recursive: true });
81
+ process.env['CLEO_WORKTREE_ROOT'] = wt;
82
+ process.env['CLEO_TASK_ID'] = 'T9999';
83
+ const active = resolveActiveWorktree('/some/unrelated/cwd');
84
+ expect(active).toEqual({ worktreePath: wt, taskId: 'T9999' });
85
+ });
86
+ it('resolveActiveWorktree walks up from cwd inside a worktree', () => {
87
+ const wt = join(workspace, 'cleo', 'worktrees', 'p1', 'T1591');
88
+ mkdirSync(join(wt, 'src'), { recursive: true });
89
+ const active = resolveActiveWorktree(join(wt, 'src'));
90
+ expect(active?.taskId).toBe('T1591');
91
+ expect(active?.worktreePath).toBe(wt);
92
+ });
93
+ it('resolveActiveWorktree returns null outside worktree tree', () => {
94
+ expect(resolveActiveWorktree('/tmp/random')).toBeNull();
95
+ });
96
+ });
97
+ // ---------------------------------------------------------------------------
98
+ // Boundary (a) — git add path inside worktree
99
+ // ---------------------------------------------------------------------------
100
+ describe('boundary (a): worktree-path enforcement', () => {
101
+ const worktreePath = '/var/tmp/wt/T1591';
102
+ it('allows git add . (no explicit path)', () => {
103
+ expect(validateAddPaths(['.'], worktreePath, worktreePath)).toBeNull();
104
+ });
105
+ it('allows git add inside worktree', () => {
106
+ expect(validateAddPaths(['src/file.ts'], worktreePath, worktreePath)).toBeNull();
107
+ });
108
+ it('allows git add with -A flag', () => {
109
+ expect(validateAddPaths(['-A'], worktreePath, worktreePath)).toBeNull();
110
+ });
111
+ it('refuses git add with absolute path outside worktree', () => {
112
+ const v = validateAddPaths(['/etc/passwd'], worktreePath, worktreePath);
113
+ expect(v).not.toBeNull();
114
+ expect(v?.code).toBe('E_GIT_BOUNDARY_WORKTREE_PATH');
115
+ expect(v?.boundary).toBe('a');
116
+ expect(v?.context['attempted_path']).toBe('/etc/passwd');
117
+ });
118
+ it('refuses git add with ../escape relative path', () => {
119
+ const v = validateAddPaths(['../../etc/passwd'], worktreePath, worktreePath);
120
+ expect(v).not.toBeNull();
121
+ expect(v?.code).toBe('E_GIT_BOUNDARY_WORKTREE_PATH');
122
+ });
123
+ });
124
+ // ---------------------------------------------------------------------------
125
+ // Boundary (b) — commit subject must contain task ID
126
+ // ---------------------------------------------------------------------------
127
+ describe('boundary (b): commit T-ID gate', () => {
128
+ it('allows commit with T<NUM> in subject (no expected ID)', () => {
129
+ expect(validateCommitSubject(['-m', 'feat(T1591): add boundary'], null)).toBeNull();
130
+ });
131
+ it('refuses commit without any T<NUM> token', () => {
132
+ const v = validateCommitSubject(['-m', 'wip: stuff'], null);
133
+ expect(v).not.toBeNull();
134
+ expect(v?.code).toBe('E_GIT_BOUNDARY_COMMIT_TASK_ID');
135
+ expect(v?.boundary).toBe('b');
136
+ });
137
+ it('refuses commit when expected ID is missing from subject', () => {
138
+ const v = validateCommitSubject(['-m', 'feat(T9999): wrong id'], 'T1591');
139
+ expect(v).not.toBeNull();
140
+ expect(v?.context['expected_task_id']).toBe('T1591');
141
+ });
142
+ it('allows commit with --message=… inline syntax', () => {
143
+ expect(validateCommitSubject(['--message=fix(T1591): boundary'], 'T1591')).toBeNull();
144
+ });
145
+ it('passes through commits with no inline -m (editor flow)', () => {
146
+ expect(validateCommitSubject([], null)).toBeNull();
147
+ expect(validateCommitSubject(['--amend'], null)).toBeNull();
148
+ });
149
+ });
150
+ // ---------------------------------------------------------------------------
151
+ // Boundary (c) — merge requires CLEO_ORCHESTRATE_MERGE
152
+ // ---------------------------------------------------------------------------
153
+ describe('boundary (c): merge restriction', () => {
154
+ it('refuses git merge without CLEO_ORCHESTRATE_MERGE', () => {
155
+ const v = validateMergeAllowed(['task/T1591'], {});
156
+ expect(v).not.toBeNull();
157
+ expect(v?.code).toBe('E_GIT_BOUNDARY_MERGE_FORBIDDEN');
158
+ expect(v?.boundary).toBe('c');
159
+ });
160
+ it('allows git merge when CLEO_ORCHESTRATE_MERGE=1', () => {
161
+ expect(validateMergeAllowed(['task/T1591'], { CLEO_ORCHESTRATE_MERGE: '1' })).toBeNull();
162
+ });
163
+ it('allows control-flow flags --abort/--continue/--quit without env', () => {
164
+ expect(validateMergeAllowed(['--abort'], {})).toBeNull();
165
+ expect(validateMergeAllowed(['--continue'], {})).toBeNull();
166
+ expect(validateMergeAllowed(['--quit'], {})).toBeNull();
167
+ });
168
+ it('refuses when env value is not exactly "1"', () => {
169
+ const v = validateMergeAllowed(['task/T1591'], { CLEO_ORCHESTRATE_MERGE: 'true' });
170
+ expect(v).not.toBeNull();
171
+ });
172
+ });
173
+ // ---------------------------------------------------------------------------
174
+ // Boundary (d) — cherry-pick refuses task/T<NUM> sources
175
+ // ---------------------------------------------------------------------------
176
+ describe('boundary (d): cherry-pick from worktree branches', () => {
177
+ it('refuses cherry-pick of task/T1591', () => {
178
+ const v = validateCherryPickSource(['task/T1591']);
179
+ expect(v).not.toBeNull();
180
+ expect(v?.code).toBe('E_GIT_BOUNDARY_CHERRY_PICK_TASK_BRANCH');
181
+ expect(v?.boundary).toBe('d');
182
+ });
183
+ it('refuses cherry-pick of range task/T1591..HEAD', () => {
184
+ const v = validateCherryPickSource(['task/T1591..HEAD']);
185
+ expect(v).not.toBeNull();
186
+ expect(v?.context['source_ref']).toBe('task/T1591');
187
+ });
188
+ it('refuses cherry-pick of triple-dot range', () => {
189
+ const v = validateCherryPickSource(['main...task/T1591']);
190
+ expect(v).not.toBeNull();
191
+ });
192
+ it('allows cherry-pick of regular branch', () => {
193
+ expect(validateCherryPickSource(['feature/regular-branch'])).toBeNull();
194
+ });
195
+ it('allows cherry-pick of explicit SHA', () => {
196
+ expect(validateCherryPickSource(['abc123def456'])).toBeNull();
197
+ });
198
+ it('allows cherry-pick of HEAD~3', () => {
199
+ expect(validateCherryPickSource(['HEAD~3'])).toBeNull();
200
+ });
201
+ });
202
+ // ---------------------------------------------------------------------------
203
+ // Audit log
204
+ // ---------------------------------------------------------------------------
205
+ describe('audit log', () => {
206
+ it('resolveAuditLogPath honours CLEO_AUDIT_LOG_PATH override', () => {
207
+ expect(resolveAuditLogPath()).toBe(auditLogPath);
208
+ });
209
+ it('resolveAuditLogPath defaults to XDG-conformant path', () => {
210
+ delete process.env['CLEO_AUDIT_LOG_PATH'];
211
+ expect(resolveAuditLogPath()).toBe(join(workspace, 'cleo', 'audit', 'git-shim.jsonl'));
212
+ });
213
+ it('writeAuditRecord persists a JSONL entry', () => {
214
+ const record = {
215
+ ts: '2026-04-29T00:00:00.000Z',
216
+ outcome: 'blocked',
217
+ boundary: 'a',
218
+ code: 'E_GIT_BOUNDARY_WORKTREE_PATH',
219
+ subcommand: 'add',
220
+ args: ['/etc/passwd'],
221
+ cwd: '/var/tmp/wt/T1591',
222
+ worktree_path: '/var/tmp/wt/T1591',
223
+ task_id: 'T1591',
224
+ role: 'worker',
225
+ context: { attempted_path: '/etc/passwd' },
226
+ };
227
+ writeAuditRecord(record);
228
+ expect(existsSync(auditLogPath)).toBe(true);
229
+ const content = readFileSync(auditLogPath, 'utf-8').trim();
230
+ const parsed = JSON.parse(content);
231
+ expect(parsed.code).toBe('E_GIT_BOUNDARY_WORKTREE_PATH');
232
+ expect(parsed.outcome).toBe('blocked');
233
+ expect(parsed.boundary).toBe('a');
234
+ });
235
+ it('writeAuditRecord appends rather than overwrites', () => {
236
+ const base = {
237
+ ts: '2026-04-29T00:00:00.000Z',
238
+ outcome: 'blocked',
239
+ boundary: 'b',
240
+ code: 'E_GIT_BOUNDARY_COMMIT_TASK_ID',
241
+ subcommand: 'commit',
242
+ args: ['-m', 'wip'],
243
+ cwd: '/var/tmp/wt/T1591',
244
+ worktree_path: null,
245
+ task_id: null,
246
+ role: 'worker',
247
+ context: {},
248
+ };
249
+ writeAuditRecord(base);
250
+ writeAuditRecord({ ...base, outcome: 'bypassed-allow-git' });
251
+ const lines = readFileSync(auditLogPath, 'utf-8').trim().split('\n');
252
+ expect(lines).toHaveLength(2);
253
+ expect(JSON.parse(lines[0] ?? '{}').outcome).toBe('blocked');
254
+ expect(JSON.parse(lines[1] ?? '{}').outcome).toBe('bypassed-allow-git');
255
+ });
256
+ });
257
+ // ---------------------------------------------------------------------------
258
+ // Project-agnostic verification (no cleocode-specific paths)
259
+ // ---------------------------------------------------------------------------
260
+ describe('project-agnostic verification', () => {
261
+ it('worktree path uses a fake project name without hardcoding "cleocode"', () => {
262
+ // Resolve a worktree path for a fake project at /home/user/projects/fake-app.
263
+ // The sha256-derived hash should never contain "cleocode".
264
+ const fakeProjectRoot = '/home/user/projects/fake-app';
265
+ const wt = join(workspace, 'cleo', 'worktrees', 'someProjectHash', 'T1591');
266
+ mkdirSync(wt, { recursive: true });
267
+ process.env['CLEO_WORKTREE_ROOT'] = wt;
268
+ process.env['CLEO_TASK_ID'] = 'T1591';
269
+ const active = resolveActiveWorktree('/totally/elsewhere');
270
+ expect(active?.worktreePath).toBe(wt);
271
+ expect(active?.worktreePath.includes('cleocode')).toBe(false);
272
+ // Reference to fakeProjectRoot to keep the test self-documenting.
273
+ expect(fakeProjectRoot.includes('cleocode')).toBe(false);
274
+ });
275
+ it('audit log path uses XDG conventions, not project name', () => {
276
+ delete process.env['CLEO_AUDIT_LOG_PATH'];
277
+ const path = resolveAuditLogPath();
278
+ expect(path.includes('cleocode')).toBe(false);
279
+ expect(path.endsWith(join('cleo', 'audit', 'git-shim.jsonl'))).toBe(true);
280
+ });
281
+ });
282
+ //# sourceMappingURL=boundary-enforcement.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boundary-enforcement.test.js","sourceRoot":"","sources":["../../src/__tests__/boundary-enforcement.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Outcome of a shim invocation that warrants an audit entry.
3
+ *
4
+ * @task T1591
5
+ */
6
+ export type AuditOutcome = 'blocked' | 'bypassed-allow-git' | 'bypassed-orchestrate-merge';
7
+ /**
8
+ * Single JSONL record written to the audit log.
9
+ *
10
+ * @task T1591
11
+ */
12
+ export interface AuditRecord {
13
+ /** ISO 8601 UTC timestamp. */
14
+ ts: string;
15
+ /** What happened. */
16
+ outcome: AuditOutcome;
17
+ /** Boundary letter (a-d) or "denylist" for legacy denylist hits. */
18
+ boundary: 'a' | 'b' | 'c' | 'd' | 'denylist';
19
+ /** CLEO error code, when blocked. */
20
+ code: string;
21
+ /** Git subcommand. */
22
+ subcommand: string;
23
+ /** Argv tail after subcommand. */
24
+ args: string[];
25
+ /** Working directory at invocation time. */
26
+ cwd: string;
27
+ /** Active worktree, when resolvable. */
28
+ worktree_path: string | null;
29
+ /** Task ID extracted from the worktree, when resolvable. */
30
+ task_id: string | null;
31
+ /** Agent role from CLEO_AGENT_ROLE. */
32
+ role: string | null;
33
+ /** Free-form context from the boundary predicate. */
34
+ context: Record<string, string>;
35
+ }
36
+ /**
37
+ * Resolve the audit log file path.
38
+ *
39
+ * Honours `CLEO_AUDIT_LOG_PATH` (test/owner override), otherwise defaults
40
+ * to the XDG-conformant location.
41
+ *
42
+ * @returns Absolute path to the jsonl file.
43
+ *
44
+ * @task T1591
45
+ */
46
+ export declare function resolveAuditLogPath(): string;
47
+ /**
48
+ * Append a single record to the audit log.
49
+ *
50
+ * Best-effort: failures are swallowed so the shim can never wedge a git
51
+ * invocation. The record is also echoed to stderr so operators see it
52
+ * even if the file write fails.
53
+ *
54
+ * @param record - The audit record to persist.
55
+ *
56
+ * @task T1591
57
+ */
58
+ export declare function writeAuditRecord(record: AuditRecord): void;
59
+ //# sourceMappingURL=audit-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-log.d.ts","sourceRoot":"","sources":["../src/audit-log.ts"],"names":[],"mappings":"AAoBA;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,oBAAoB,GAAG,4BAA4B,CAAC;AAE3F;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB;IACrB,OAAO,EAAE,YAAY,CAAC;IACtB,oEAAoE;IACpE,QAAQ,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,UAAU,CAAC;IAC7C,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,wCAAwC;IACxC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4DAA4D;IAC5D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uCAAuC;IACvC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAK5C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAmB1D"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Append-only audit log for git-shim boundary events (T1591).
3
+ *
4
+ * Every block (refusal) and every bypass (`CLEO_ALLOW_GIT=1`) is recorded as
5
+ * one JSON line at:
6
+ *
7
+ * `<XDG_DATA_HOME ?? ~/.local/share>/cleo/audit/git-shim.jsonl`
8
+ *
9
+ * Tests override the path via `CLEO_AUDIT_LOG_PATH`.
10
+ *
11
+ * Records use a stable, project-agnostic shape so downstream tooling
12
+ * (`cleo audit show`, dashboards) can consume them without parsing knowledge
13
+ * of any particular project.
14
+ *
15
+ * @task T1591
16
+ */
17
+ import { appendFileSync, mkdirSync } from 'node:fs';
18
+ import { homedir } from 'node:os';
19
+ import { dirname, join } from 'node:path';
20
+ /**
21
+ * Resolve the audit log file path.
22
+ *
23
+ * Honours `CLEO_AUDIT_LOG_PATH` (test/owner override), otherwise defaults
24
+ * to the XDG-conformant location.
25
+ *
26
+ * @returns Absolute path to the jsonl file.
27
+ *
28
+ * @task T1591
29
+ */
30
+ export function resolveAuditLogPath() {
31
+ const override = process.env['CLEO_AUDIT_LOG_PATH'];
32
+ if (override)
33
+ return override;
34
+ const xdgData = process.env['XDG_DATA_HOME'] ?? join(homedir(), '.local', 'share');
35
+ return join(xdgData, 'cleo', 'audit', 'git-shim.jsonl');
36
+ }
37
+ /**
38
+ * Append a single record to the audit log.
39
+ *
40
+ * Best-effort: failures are swallowed so the shim can never wedge a git
41
+ * invocation. The record is also echoed to stderr so operators see it
42
+ * even if the file write fails.
43
+ *
44
+ * @param record - The audit record to persist.
45
+ *
46
+ * @task T1591
47
+ */
48
+ export function writeAuditRecord(record) {
49
+ const line = `${JSON.stringify(record)}\n`;
50
+ const path = resolveAuditLogPath();
51
+ try {
52
+ mkdirSync(dirname(path), { recursive: true });
53
+ appendFileSync(path, line, { encoding: 'utf-8' });
54
+ }
55
+ catch {
56
+ // Best-effort — shim must never block on log failure.
57
+ }
58
+ // Always echo to stderr for human visibility.
59
+ if (record.outcome === 'blocked') {
60
+ process.stderr.write(`[git-shim] AUDIT block boundary=${record.boundary} code=${record.code}\n`);
61
+ }
62
+ else {
63
+ process.stderr.write(`[git-shim] AUDIT bypass boundary=${record.boundary} via=${record.outcome}\n`);
64
+ }
65
+ }
66
+ //# sourceMappingURL=audit-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-log.js","sourceRoot":"","sources":["../src/audit-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAuC1C;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACpD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnF,OAAO,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAmB;IAClD,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;IAC3C,MAAM,IAAI,GAAG,mBAAmB,EAAE,CAAC;IACnC,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,sDAAsD;IACxD,CAAC;IACD,8CAA8C;IAC9C,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,mCAAmC,MAAM,CAAC,QAAQ,SAAS,MAAM,CAAC,IAAI,IAAI,CAC3E,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,oCAAoC,MAAM,CAAC,QAAQ,QAAQ,MAAM,CAAC,OAAO,IAAI,CAC9E,CAAC;IACJ,CAAC;AACH,CAAC"}