@guilz-dev/belay 0.9.0 → 0.9.1
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 +7 -1
- package/dist/adapters/claude/runtime-entry.js +2 -0
- package/dist/adapters/codex/runtime-entry.js +2 -0
- package/dist/adapters/cursor/hooks.d.ts +5 -1
- package/dist/adapters/cursor/hooks.js +37 -2
- package/dist/adapters/cursor/runtime-entry.js +5 -0
- package/dist/adapters/shared/gate-runtime.d.ts +1 -0
- package/dist/adapters/shared/gate-runtime.js +49 -52
- package/dist/bundle/claude-runtime.mjs +3831 -3581
- package/dist/bundle/codex-runtime.mjs +3671 -3421
- package/dist/bundle/cursor-runtime.mjs +3677 -3424
- package/dist/commands/doctor.js +15 -3
- package/dist/core/audit-analysis.js +7 -4
- package/dist/core/audit-io.d.ts +1 -0
- package/dist/core/audit-io.js +8 -6
- package/dist/core/audit-legacy-archive.d.ts +6 -0
- package/dist/core/audit-legacy-archive.js +51 -0
- package/dist/core/audit-metrics.d.ts +4 -0
- package/dist/core/audit-metrics.js +2 -2
- package/dist/core/audit-query.d.ts +2 -0
- package/dist/core/audit-query.js +33 -9
- package/dist/core/audit-recovery-metrics.js +2 -2
- package/dist/core/audit-serialize.d.ts +9 -0
- package/dist/core/audit-serialize.js +179 -0
- package/dist/core/audit-types.d.ts +1 -0
- package/dist/core/capability/policy-engine.js +32 -13
- package/dist/core/decision-config-fingerprint.d.ts +3 -0
- package/dist/core/decision-config-fingerprint.js +6 -0
- package/dist/core/effect-ir/shell-lower.js +3 -0
- package/dist/core/verdict/egress-classify.js +1 -0
- package/dist/defaults.js +0 -8
- package/dist/egress-daemon.js +20 -4
- package/dist/installer.js +3 -0
- package/dist/runtime-provenance.d.ts +10 -0
- package/dist/runtime-provenance.js +63 -0
- package/dist/templates.js +12 -7
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -122,7 +122,13 @@ approved shell action first, then lets the remaining prompt continue. CLI replay
|
|
|
122
122
|
|
|
123
123
|
Approvals are one-shot and expire after 15 minutes by default. Every decision is
|
|
124
124
|
written to `.cursor/belay/audit.ndjson`, `.claude/belay/audit.ndjson`, or
|
|
125
|
-
`.codex/belay/audit.ndjson` (depending on the adapter).
|
|
125
|
+
`.codex/belay/audit.ndjson` (depending on the adapter). Schema v3 preserves ISO
|
|
126
|
+
timestamps, fingerprints, and `approvalCorrelationId` for metrics joins. Dogfood
|
|
127
|
+
readiness counts only the active cohort (runtime bundle + authorization-relevant
|
|
128
|
+
config + boundary profile); legacy placeholder logs should be archived via
|
|
129
|
+
`belay upgrade` before trusting readiness. See
|
|
130
|
+
[config schema — audit log](./docs/config-schema.md#audit-log-ndjson-schema-v3) and
|
|
131
|
+
[dogfood audit remediation](./docs/dogfood-audit-remediation-2026-08-22.ja.md).
|
|
126
132
|
|
|
127
133
|
In **audit mode** (`mode: "audit"`), would-be denials are recorded
|
|
128
134
|
(`wouldBlock: true`) but execution still continues, and no approval IDs are
|
|
@@ -162,6 +162,7 @@ export async function runShellGateHook() {
|
|
|
162
162
|
command,
|
|
163
163
|
payload,
|
|
164
164
|
toolName: 'Bash',
|
|
165
|
+
sourceEvent: 'PreToolUse',
|
|
165
166
|
});
|
|
166
167
|
jsonResponse(gateVerdictToClaudePreToolUseResponse(verdict));
|
|
167
168
|
}
|
|
@@ -261,6 +262,7 @@ export async function runToolGateHook(_eventName) {
|
|
|
261
262
|
cwd,
|
|
262
263
|
payload: normalizedPayload,
|
|
263
264
|
toolName,
|
|
265
|
+
sourceEvent: 'PreToolUse',
|
|
264
266
|
});
|
|
265
267
|
jsonResponse(gateVerdictToClaudePreToolUseResponse(verdict));
|
|
266
268
|
}
|
|
@@ -180,6 +180,7 @@ export async function runToolGateHook(eventName) {
|
|
|
180
180
|
command: kind === 'shell' ? extractString(normalizedPayload.tool_input, 'command') : undefined,
|
|
181
181
|
payload: normalizedPayload,
|
|
182
182
|
toolName,
|
|
183
|
+
sourceEvent: eventName,
|
|
183
184
|
});
|
|
184
185
|
jsonResponse(gateVerdictToCodexPreToolUseResponse(verdict));
|
|
185
186
|
}
|
|
@@ -209,6 +210,7 @@ export async function runShellGateHook() {
|
|
|
209
210
|
command,
|
|
210
211
|
payload,
|
|
211
212
|
toolName: 'Shell',
|
|
213
|
+
sourceEvent: 'PreToolUse',
|
|
212
214
|
});
|
|
213
215
|
jsonResponse(gateVerdictToCodexPreToolUseResponse(verdict));
|
|
214
216
|
}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
import type { HooksFile } from '../../types.js';
|
|
1
|
+
import type { HookEntry, HooksFile } from '../../types.js';
|
|
2
|
+
/** Legacy Belay-managed Shell preToolUse gate duplicated beforeShellExecution. */
|
|
3
|
+
export declare function legacyManagedShellPreToolUseEntry(platform: NodeJS.Platform, hooksDir: string, repoRoot: string): HookEntry;
|
|
4
|
+
export declare function removeLegacyManagedShellPreToolUse(hooks: HooksFile, platform: NodeJS.Platform, hooksDir: string, repoRoot: string): HooksFile;
|
|
2
5
|
export declare function mergeCursorHooksFile(current: HooksFile, platform: NodeJS.Platform, hooksDir: string, repoRoot: string): HooksFile;
|
|
6
|
+
export declare function hasDuplicateCursorShellGates(hooks: HooksFile, platform: NodeJS.Platform, hooksDir: string, repoRoot: string): boolean;
|
|
@@ -10,10 +10,37 @@ function mergeHookEntry(current, expected, placement) {
|
|
|
10
10
|
}
|
|
11
11
|
return [...filtered, expected];
|
|
12
12
|
}
|
|
13
|
+
/** Legacy Belay-managed Shell preToolUse gate duplicated beforeShellExecution. */
|
|
14
|
+
export function legacyManagedShellPreToolUseEntry(platform, hooksDir, repoRoot) {
|
|
15
|
+
const managed = getManagedHookEntries(platform, hooksDir, repoRoot);
|
|
16
|
+
const referencePreToolUse = managed.find((entry) => entry.event === 'preToolUse' && entry.definition.matcher === 'Write')?.definition;
|
|
17
|
+
if (!referencePreToolUse) {
|
|
18
|
+
throw new Error('managed hook definitions missing for legacy Shell migration');
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
command: referencePreToolUse.command,
|
|
22
|
+
matcher: 'Shell',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function removeLegacyManagedShellPreToolUse(hooks, platform, hooksDir, repoRoot) {
|
|
26
|
+
const legacy = legacyManagedShellPreToolUseEntry(platform, hooksDir, repoRoot);
|
|
27
|
+
const preToolUse = hooks.hooks.preToolUse;
|
|
28
|
+
if (!Array.isArray(preToolUse)) {
|
|
29
|
+
return hooks;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
...hooks,
|
|
33
|
+
hooks: {
|
|
34
|
+
...hooks.hooks,
|
|
35
|
+
preToolUse: preToolUse.filter((entry) => !entryMatches(entry, legacy)),
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
13
39
|
export function mergeCursorHooksFile(current, platform, hooksDir, repoRoot) {
|
|
40
|
+
const withoutLegacyShell = removeLegacyManagedShellPreToolUse(current, platform, hooksDir, repoRoot);
|
|
14
41
|
const next = {
|
|
15
|
-
version:
|
|
16
|
-
hooks: { ...
|
|
42
|
+
version: withoutLegacyShell.version || 1,
|
|
43
|
+
hooks: { ...withoutLegacyShell.hooks },
|
|
17
44
|
};
|
|
18
45
|
const managedEntries = getManagedHookEntries(platform, hooksDir, repoRoot);
|
|
19
46
|
for (const { event, definition } of managedEntries) {
|
|
@@ -24,3 +51,11 @@ export function mergeCursorHooksFile(current, platform, hooksDir, repoRoot) {
|
|
|
24
51
|
}
|
|
25
52
|
return next;
|
|
26
53
|
}
|
|
54
|
+
export function hasDuplicateCursorShellGates(hooks, platform, hooksDir, repoRoot) {
|
|
55
|
+
const legacy = legacyManagedShellPreToolUseEntry(platform, hooksDir, repoRoot);
|
|
56
|
+
const preToolUse = hooks.hooks.preToolUse;
|
|
57
|
+
if (!Array.isArray(preToolUse)) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return preToolUse.some((entry) => entryMatches(entry, legacy));
|
|
61
|
+
}
|
|
@@ -65,6 +65,7 @@ export async function runShellGateHook() {
|
|
|
65
65
|
kind: 'shell',
|
|
66
66
|
cwd,
|
|
67
67
|
command,
|
|
68
|
+
sourceEvent: 'beforeShellExecution',
|
|
68
69
|
});
|
|
69
70
|
jsonResponse(gateVerdictToCursorResponse(verdict));
|
|
70
71
|
}
|
|
@@ -87,6 +88,7 @@ export async function runToolGateHook(eventName) {
|
|
|
87
88
|
kind: 'subagent',
|
|
88
89
|
cwd,
|
|
89
90
|
payload,
|
|
91
|
+
sourceEvent: eventName,
|
|
90
92
|
});
|
|
91
93
|
jsonResponse(gateVerdictToCursorResponse(verdict));
|
|
92
94
|
return;
|
|
@@ -97,6 +99,7 @@ export async function runToolGateHook(eventName) {
|
|
|
97
99
|
cwd,
|
|
98
100
|
payload,
|
|
99
101
|
toolName,
|
|
102
|
+
sourceEvent: eventName,
|
|
100
103
|
});
|
|
101
104
|
jsonResponse(gateVerdictToCursorResponse(verdict));
|
|
102
105
|
return;
|
|
@@ -107,6 +110,7 @@ export async function runToolGateHook(eventName) {
|
|
|
107
110
|
cwd,
|
|
108
111
|
payload,
|
|
109
112
|
toolName,
|
|
113
|
+
sourceEvent: eventName,
|
|
110
114
|
});
|
|
111
115
|
jsonResponse(gateVerdictToCursorResponse(verdict));
|
|
112
116
|
return;
|
|
@@ -116,6 +120,7 @@ export async function runToolGateHook(eventName) {
|
|
|
116
120
|
kind: 'subagent',
|
|
117
121
|
cwd,
|
|
118
122
|
payload,
|
|
123
|
+
sourceEvent: eventName,
|
|
119
124
|
});
|
|
120
125
|
jsonResponse(gateVerdictToCursorResponse(verdict));
|
|
121
126
|
return;
|
|
@@ -46,6 +46,7 @@ export declare function evaluateGatedAction(ctx: GateRuntimeContext, deps: GateR
|
|
|
46
46
|
command?: string;
|
|
47
47
|
payload?: Record<string, unknown>;
|
|
48
48
|
toolName?: string;
|
|
49
|
+
sourceEvent?: string;
|
|
49
50
|
}): Promise<GateVerdict>;
|
|
50
51
|
/** R39: unmapped Codex tools ask via pending approval — not hard deny without approval path. */
|
|
51
52
|
export declare function gateUnmappedToolVerdict(ctx: GateRuntimeContext, deps: GateRuntimeDeps, toolName: string, payload: Record<string, unknown>): Promise<GateVerdict>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
@@ -7,6 +7,7 @@ import { buildReplayHint, buildRetryInstructionForConfig, canAutoReplay, getExec
|
|
|
7
7
|
import { claimApprovedForReplay, gateApprovalStoreFromDeps, recordApproval, } from '../../core/approval-service.js';
|
|
8
8
|
import { issueApprovalToken } from '../../core/approval-token.js';
|
|
9
9
|
import { buildAuditActionSnapshot, buildAuditReplayContext, } from '../../core/audit-replay-context.js';
|
|
10
|
+
import { approvalCorrelationId, serializeAuditRecordV3 } from '../../core/audit-serialize.js';
|
|
10
11
|
import { boundedUtf8Tail } from '../../core/bounded-output.js';
|
|
11
12
|
import { mutateApprovalStateWithRetry } from '../../core/capability/approval-state-mutation.js';
|
|
12
13
|
import { APPROVAL_STATE_VERSION_V3 } from '../../core/capability/approval-v3.js';
|
|
@@ -37,8 +38,8 @@ import { canonicalPath } from '../../core/path-utils.js';
|
|
|
37
38
|
import { recoveryFailClosedResult, recoveryFailReasonFromSkip, } from '../../core/recovery/fail-closed.js';
|
|
38
39
|
import { fingerprintReplayPayload } from '../../core/replay-scrub.js';
|
|
39
40
|
import { FILE_CHECKPOINT_ISOLATION_UNAVAILABLE, isTransactionalEligible, runTransactionalExecution, TRANSACTIONAL_ALREADY_APPLIED, TRANSACTIONAL_APPROVAL_BYPASS_REASONS, } from '../../core/transactional/index.js';
|
|
41
|
+
import { buildAuditProvenanceFields } from '../../runtime-provenance.js';
|
|
40
42
|
import { egressStatus } from '../../services/egress-service.js';
|
|
41
|
-
import { PACKAGE_VERSION } from '../../version.js';
|
|
42
43
|
import { protectedArtifactRoots } from '../layouts/protected-paths.js';
|
|
43
44
|
const EMPTY_APPROVALS = {
|
|
44
45
|
version: 1,
|
|
@@ -47,34 +48,7 @@ const EMPTY_APPROVALS = {
|
|
|
47
48
|
const RUNTIME_PROVENANCE_KEY = Symbol.for('agent-belay.runtime-provenance');
|
|
48
49
|
function auditProvenance(config) {
|
|
49
50
|
const runtime = globalThis[RUNTIME_PROVENANCE_KEY];
|
|
50
|
-
|
|
51
|
-
const runtimeBuildStamp = typeof runtime?.runtimeBuildStamp === 'string'
|
|
52
|
-
? runtime.runtimeBuildStamp
|
|
53
|
-
: `${PACKAGE_VERSION}@source`;
|
|
54
|
-
return {
|
|
55
|
-
runtimeVersion,
|
|
56
|
-
runtimeBuildStamp,
|
|
57
|
-
configFingerprint: hashValue(canonicalStringify(config)),
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
function preservedContainedAuditMetadata(record) {
|
|
61
|
-
const safe = {};
|
|
62
|
-
if (record.wouldMediate === true)
|
|
63
|
-
safe.wouldMediate = true;
|
|
64
|
-
if (typeof record.receiptHash === 'string' && /^[a-f0-9]{64}$/.test(record.receiptHash)) {
|
|
65
|
-
safe.receiptHash = record.receiptHash;
|
|
66
|
-
}
|
|
67
|
-
if (typeof record.imageId === 'string' && /^sha256:[a-f0-9]{64}$/.test(record.imageId)) {
|
|
68
|
-
safe.imageId = record.imageId;
|
|
69
|
-
}
|
|
70
|
-
if (record.mirrorBackend === 'file_copy')
|
|
71
|
-
safe.mirrorBackend = record.mirrorBackend;
|
|
72
|
-
if (record.exitCode === null || Number.isSafeInteger(record.exitCode)) {
|
|
73
|
-
safe.exitCode = record.exitCode;
|
|
74
|
-
}
|
|
75
|
-
if (typeof record.timedOut === 'boolean')
|
|
76
|
-
safe.timedOut = record.timedOut;
|
|
77
|
-
return safe;
|
|
51
|
+
return buildAuditProvenanceFields(config, runtime);
|
|
78
52
|
}
|
|
79
53
|
function adapterIdFromContext(ctx) {
|
|
80
54
|
if (ctx.config.adapter === 'cursor' ||
|
|
@@ -87,6 +61,14 @@ function adapterIdFromContext(ctx) {
|
|
|
87
61
|
}
|
|
88
62
|
return undefined;
|
|
89
63
|
}
|
|
64
|
+
function extractShellCommandFromPayload(payload) {
|
|
65
|
+
const toolInput = payload.tool_input;
|
|
66
|
+
if (!toolInput || typeof toolInput !== 'object') {
|
|
67
|
+
return '';
|
|
68
|
+
}
|
|
69
|
+
const input = toolInput;
|
|
70
|
+
return typeof input.command === 'string' ? input.command : '';
|
|
71
|
+
}
|
|
90
72
|
const REPLAY_AUDIT_FAILURE_NOTE = ' Audit recording failed; inspect audit storage before the next approval.';
|
|
91
73
|
async function appendReplayAuditSafely(ctx, deps, event) {
|
|
92
74
|
try {
|
|
@@ -117,15 +99,15 @@ export function createDefaultGateRuntimeDeps() {
|
|
|
117
99
|
const provenance = auditProvenance(ctx.config);
|
|
118
100
|
const record = {
|
|
119
101
|
timestamp: new Date().toISOString(),
|
|
102
|
+
mode: ctx.config.mode,
|
|
120
103
|
...event,
|
|
121
104
|
...provenance,
|
|
122
105
|
};
|
|
123
106
|
if (!ctx.config.audit.includeAssessment) {
|
|
124
107
|
delete record.assessment;
|
|
125
108
|
}
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
await writeFile(auditPath, `${JSON.stringify(scrubbed)}\n`, {
|
|
109
|
+
const serialized = serializeAuditRecordV3(record, scrubOptionsFromConfig(ctx.config));
|
|
110
|
+
await writeFile(auditPath, `${JSON.stringify(serialized)}\n`, {
|
|
129
111
|
encoding: 'utf8',
|
|
130
112
|
flag: 'a',
|
|
131
113
|
});
|
|
@@ -210,6 +192,22 @@ function gateAuditEventName(kind) {
|
|
|
210
192
|
}
|
|
211
193
|
return 'subagentGate';
|
|
212
194
|
}
|
|
195
|
+
function resolveGateAuditEvent(sourceEvent, kind) {
|
|
196
|
+
if (!sourceEvent) {
|
|
197
|
+
return gateAuditEventName(kind);
|
|
198
|
+
}
|
|
199
|
+
switch (sourceEvent.toLowerCase()) {
|
|
200
|
+
case 'beforeshellexecution':
|
|
201
|
+
return 'beforeShellExecution';
|
|
202
|
+
case 'pretooluse':
|
|
203
|
+
return 'preToolUse';
|
|
204
|
+
case 'subagentstart':
|
|
205
|
+
case 'subagentgate':
|
|
206
|
+
return 'subagentGate';
|
|
207
|
+
default:
|
|
208
|
+
return gateAuditEventName(kind);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
213
211
|
async function ensurePendingApproval(ctx, deps, kind, result, approvalInput, scopeHint) {
|
|
214
212
|
const candidate = createApprovalRecordWithEnvelope({
|
|
215
213
|
kind,
|
|
@@ -245,17 +243,6 @@ async function ensurePendingApproval(ctx, deps, kind, result, approvalInput, sco
|
|
|
245
243
|
}
|
|
246
244
|
return outcome;
|
|
247
245
|
}
|
|
248
|
-
function approvalCorrelationId(approvalId) {
|
|
249
|
-
return createHash('sha256').update(approvalId).digest('hex').slice(0, 16);
|
|
250
|
-
}
|
|
251
|
-
function extractShellCommandFromPayload(payload) {
|
|
252
|
-
const toolInput = payload.tool_input;
|
|
253
|
-
if (!toolInput || typeof toolInput !== 'object') {
|
|
254
|
-
return '';
|
|
255
|
-
}
|
|
256
|
-
const input = toolInput;
|
|
257
|
-
return typeof input.command === 'string' ? input.command : '';
|
|
258
|
-
}
|
|
259
246
|
function deriveWorkspaceRootScopeHint(params) {
|
|
260
247
|
if (params.result.reason !== 'outside_repo_mutation' &&
|
|
261
248
|
params.result.reason !== 'outside_repo_redirect') {
|
|
@@ -408,10 +395,13 @@ function normalizeContainedFailure(error) {
|
|
|
408
395
|
}
|
|
409
396
|
return new ContainedExecutionFailureError('contained_execution_boundary_failed', { cause: error });
|
|
410
397
|
}
|
|
411
|
-
function containedAuditBase(kind, mode, result) {
|
|
398
|
+
function containedAuditBase(kind, mode, result, sourceEvent) {
|
|
412
399
|
const planFields = effectPlanAuditFields(result.effectPlan);
|
|
400
|
+
const rawSourceEvent = sourceEvent ?? gateAuditEventName(kind);
|
|
401
|
+
const auditEvent = resolveGateAuditEvent(rawSourceEvent, kind);
|
|
413
402
|
return {
|
|
414
|
-
event:
|
|
403
|
+
event: auditEvent,
|
|
404
|
+
sourceEvent: rawSourceEvent,
|
|
415
405
|
kind,
|
|
416
406
|
fingerprint: result.fingerprint,
|
|
417
407
|
mode,
|
|
@@ -426,11 +416,11 @@ function containedAuditBase(kind, mode, result) {
|
|
|
426
416
|
};
|
|
427
417
|
}
|
|
428
418
|
async function mediateContainedUnknownExecution(params) {
|
|
429
|
-
const { ctx, deps, action, command } = params;
|
|
419
|
+
const { ctx, deps, action, command, sourceEvent } = params;
|
|
430
420
|
const result = { ...params.result, wouldMediate: true };
|
|
431
421
|
if (ctx.config.mode === 'audit') {
|
|
432
422
|
await deps.appendAudit(ctx, {
|
|
433
|
-
...containedAuditBase(action.kind, ctx.config.mode, result),
|
|
423
|
+
...containedAuditBase(action.kind, ctx.config.mode, result, sourceEvent),
|
|
434
424
|
verdict: result.verdict,
|
|
435
425
|
reason: result.reason,
|
|
436
426
|
wouldBlock: true,
|
|
@@ -505,7 +495,7 @@ async function mediateContainedUnknownExecution(params) {
|
|
|
505
495
|
reason,
|
|
506
496
|
};
|
|
507
497
|
await deps.appendAudit(ctx, {
|
|
508
|
-
...containedAuditBase(action.kind, ctx.config.mode, failedResult),
|
|
498
|
+
...containedAuditBase(action.kind, ctx.config.mode, failedResult, sourceEvent),
|
|
509
499
|
verdict: failedResult.verdict,
|
|
510
500
|
reason,
|
|
511
501
|
wouldBlock: true,
|
|
@@ -546,7 +536,7 @@ async function mediateContainedUnknownExecution(params) {
|
|
|
546
536
|
mediatedExecution,
|
|
547
537
|
};
|
|
548
538
|
await deps.appendAudit(ctx, {
|
|
549
|
-
...containedAuditBase(action.kind, ctx.config.mode, mediatedResult),
|
|
539
|
+
...containedAuditBase(action.kind, ctx.config.mode, mediatedResult, sourceEvent),
|
|
550
540
|
verdict: mediatedResult.verdict,
|
|
551
541
|
reason,
|
|
552
542
|
wouldBlock: false,
|
|
@@ -621,8 +611,10 @@ export async function evaluateGatedAction(ctx, deps, params) {
|
|
|
621
611
|
effectFree: false,
|
|
622
612
|
}),
|
|
623
613
|
};
|
|
614
|
+
const sourceEvent = params.sourceEvent ?? gateAuditEventName(params.kind);
|
|
624
615
|
await deps.appendAudit(ctx, {
|
|
625
|
-
event:
|
|
616
|
+
event: resolveGateAuditEvent(sourceEvent, params.kind),
|
|
617
|
+
sourceEvent,
|
|
626
618
|
kind: params.kind,
|
|
627
619
|
fingerprint: verdict.fingerprint,
|
|
628
620
|
verdict: verdict.verdict,
|
|
@@ -690,6 +682,7 @@ export async function evaluateGatedAction(ctx, deps, params) {
|
|
|
690
682
|
action,
|
|
691
683
|
command: action.command,
|
|
692
684
|
result: predicted,
|
|
685
|
+
sourceEvent: params.sourceEvent,
|
|
693
686
|
});
|
|
694
687
|
if (mediated) {
|
|
695
688
|
return mediated;
|
|
@@ -785,6 +778,7 @@ export async function evaluateGatedAction(ctx, deps, params) {
|
|
|
785
778
|
const scrubOpts = scrubOptionsFromConfig(ctx.config);
|
|
786
779
|
const scrubbedPayload = fingerprintReplayPayload(params.kind, params.payload, scrubOpts);
|
|
787
780
|
return gateDecisionToVerdict(ctx, deps, params.kind, result, {
|
|
781
|
+
sourceEvent: params.sourceEvent,
|
|
788
782
|
predictedAssessment,
|
|
789
783
|
observedAssessment,
|
|
790
784
|
transactionalLayer,
|
|
@@ -904,8 +898,11 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
|
|
|
904
898
|
(kind === 'shell' ? auditExtras.approvalInput?.input : undefined),
|
|
905
899
|
stateDir,
|
|
906
900
|
});
|
|
901
|
+
const sourceEvent = auditExtras.sourceEvent ?? gateAuditEventName(kind);
|
|
902
|
+
const auditEvent = resolveGateAuditEvent(sourceEvent, kind);
|
|
907
903
|
const gateBase = {
|
|
908
|
-
event:
|
|
904
|
+
event: auditEvent,
|
|
905
|
+
sourceEvent,
|
|
909
906
|
kind,
|
|
910
907
|
fingerprint: result.fingerprint,
|
|
911
908
|
summary: result.normalizedCommand ?? result.summary ?? '',
|