@guilz-dev/belay 0.3.0 → 0.6.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 +7 -1
- package/dist/adapters/cursor/runtime-entry.js +1 -0
- package/dist/adapters/layouts/scope.js +3 -2
- package/dist/adapters/shared/gate-runtime.d.ts +12 -16
- package/dist/adapters/shared/gate-runtime.js +499 -43
- package/dist/bundle/claude-runtime.mjs +8004 -2676
- package/dist/bundle/codex-runtime.mjs +8021 -2683
- package/dist/bundle/cursor-runtime.mjs +7993 -2667
- package/dist/cli.js +180 -6
- package/dist/commands/approve.d.ts +1 -0
- package/dist/commands/approve.js +45 -26
- package/dist/commands/classify-for-report.js +1 -1
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.js +264 -58
- package/dist/commands/doctor.js +47 -2
- package/dist/commands/explain.js +17 -2
- package/dist/commands/harvest.d.ts +29 -0
- package/dist/commands/harvest.js +72 -0
- package/dist/commands/judge.d.ts +11 -1
- package/dist/commands/judge.js +24 -4
- package/dist/commands/metrics.js +34 -2
- package/dist/commands/quality.d.ts +38 -0
- package/dist/commands/quality.js +105 -0
- package/dist/commands/session.d.ts +20 -0
- package/dist/commands/session.js +51 -0
- package/dist/commands/simulate.d.ts +1 -0
- package/dist/commands/simulate.js +7 -2
- package/dist/commands/standing-allow.d.ts +10 -0
- package/dist/commands/standing-allow.js +26 -0
- package/dist/commands/tui.d.ts +48 -0
- package/dist/commands/tui.js +150 -0
- package/dist/config-io.js +59 -17
- package/dist/conformance/guarantee-posture.d.ts +21 -0
- package/dist/conformance/guarantee-posture.js +46 -0
- package/dist/conformance/guarantee-table.d.ts +1 -0
- package/dist/conformance/guarantee-table.js +14 -9
- package/dist/core/approval-replay-cli.d.ts +7 -0
- package/dist/core/approval-replay-cli.js +36 -0
- package/dist/core/approval-replay.d.ts +45 -0
- package/dist/core/approval-replay.js +141 -0
- package/dist/core/approval-service.d.ts +15 -0
- package/dist/core/approval-service.js +53 -4
- package/dist/core/approval.d.ts +26 -3
- package/dist/core/approval.js +61 -7
- package/dist/core/audit-analysis.d.ts +7 -1
- package/dist/core/audit-analysis.js +111 -0
- package/dist/core/audit-metrics.d.ts +7 -0
- package/dist/core/audit-metrics.js +24 -4
- package/dist/core/audit-query.d.ts +1 -0
- package/dist/core/audit-query.js +3 -0
- package/dist/core/audit-replay-context.d.ts +35 -0
- package/dist/core/audit-replay-context.js +88 -0
- package/dist/core/audit-types.d.ts +24 -1
- package/dist/core/audit-types.js +1 -1
- package/dist/core/capability/approval-state-mutation.d.ts +13 -0
- package/dist/core/capability/approval-state-mutation.js +92 -0
- package/dist/core/capability/approval-v3.d.ts +15 -0
- package/dist/core/capability/approval-v3.js +74 -0
- package/dist/core/capability/attestation.d.ts +13 -0
- package/dist/core/capability/attestation.js +55 -0
- package/dist/core/capability/boundary-attestation-sign.d.ts +21 -0
- package/dist/core/capability/boundary-attestation-sign.js +84 -0
- package/dist/core/capability/boundary-driver-container.d.ts +7 -0
- package/dist/core/capability/boundary-driver-container.js +122 -0
- package/dist/core/capability/boundary-driver.d.ts +29 -0
- package/dist/core/capability/boundary-driver.js +43 -0
- package/dist/core/capability/boundary-egress.d.ts +21 -0
- package/dist/core/capability/boundary-egress.js +109 -0
- package/dist/core/capability/boundary-grant-materialize.d.ts +13 -0
- package/dist/core/capability/boundary-grant-materialize.js +78 -0
- package/dist/core/capability/boundary-profile.d.ts +15 -0
- package/dist/core/capability/boundary-profile.js +25 -0
- package/dist/core/capability/boundary-run.d.ts +23 -0
- package/dist/core/capability/boundary-run.js +23 -0
- package/dist/core/capability/boundary-session.d.ts +57 -0
- package/dist/core/capability/boundary-session.js +129 -0
- package/dist/core/capability/capability-request-hash.d.ts +2 -0
- package/dist/core/capability/capability-request-hash.js +8 -0
- package/dist/core/capability/gate-latency-ratchet.d.ts +7 -0
- package/dist/core/capability/gate-latency-ratchet.js +18 -0
- package/dist/core/capability/gate-policy-shadow.d.ts +25 -0
- package/dist/core/capability/gate-policy-shadow.js +108 -0
- package/dist/core/capability/gate-shadow-audit.d.ts +1 -0
- package/dist/core/capability/gate-shadow-audit.js +1 -0
- package/dist/core/capability/gate-shadow-ratchet.d.ts +14 -0
- package/dist/core/capability/gate-shadow-ratchet.js +81 -0
- package/dist/core/capability/grant-lease.d.ts +9 -0
- package/dist/core/capability/grant-lease.js +46 -0
- package/dist/core/capability/grant-loader.d.ts +12 -0
- package/dist/core/capability/grant-loader.js +23 -0
- package/dist/core/capability/grant-match.d.ts +6 -0
- package/dist/core/capability/grant-match.js +93 -0
- package/dist/core/capability/grant.d.ts +16 -0
- package/dist/core/capability/grant.js +16 -0
- package/dist/core/capability/index.d.ts +10 -1
- package/dist/core/capability/index.js +8 -0
- package/dist/core/capability/limits.d.ts +7 -0
- package/dist/core/capability/limits.js +55 -0
- package/dist/core/capability/paths.d.ts +2 -2
- package/dist/core/capability/paths.js +9 -9
- package/dist/core/capability/policy-bridge.d.ts +18 -0
- package/dist/core/capability/policy-bridge.js +51 -0
- package/dist/core/capability/policy-engine.d.ts +70 -0
- package/dist/core/capability/policy-engine.js +476 -0
- package/dist/core/capability/policy-types.d.ts +20 -0
- package/dist/core/capability/policy-types.js +1 -0
- package/dist/core/capability/request.d.ts +45 -0
- package/dist/core/capability/request.js +1 -0
- package/dist/core/capability/resolver.d.ts +4 -0
- package/dist/core/capability/resolver.js +4 -0
- package/dist/core/capability/trusted-workspace-roots.d.ts +25 -0
- package/dist/core/capability/trusted-workspace-roots.js +149 -0
- package/dist/core/capability/types.d.ts +11 -1
- package/dist/core/capability-approval.d.ts +2 -1
- package/dist/core/capability-approval.js +100 -2
- package/dist/core/classify-subagent.d.ts +2 -1
- package/dist/core/classify-subagent.js +40 -22
- package/dist/core/classify-tool.js +157 -64
- package/dist/core/config.d.ts +32 -3
- package/dist/core/config.js +105 -3
- package/dist/core/gate-contract.d.ts +3 -0
- package/dist/core/gate-contract.js +3 -0
- package/dist/core/gate-engine.js +12 -7
- package/dist/core/harvest.d.ts +53 -0
- package/dist/core/harvest.js +276 -0
- package/dist/core/index.d.ts +9 -3
- package/dist/core/index.js +6 -2
- package/dist/core/judge-doctor.d.ts +3 -0
- package/dist/core/judge-doctor.js +90 -11
- package/dist/core/judge-fallback-hints.d.ts +13 -0
- package/dist/core/judge-fallback-hints.js +108 -0
- package/dist/core/path-utils.d.ts +12 -0
- package/dist/core/path-utils.js +60 -7
- package/dist/core/reclassify.d.ts +3 -0
- package/dist/core/reclassify.js +44 -14
- package/dist/core/recovery/capability.d.ts +3 -0
- package/dist/core/recovery/capability.js +22 -0
- package/dist/core/recovery/fail-closed.d.ts +6 -0
- package/dist/core/recovery/fail-closed.js +25 -0
- package/dist/core/recovery/index.d.ts +3 -0
- package/dist/core/recovery/index.js +2 -0
- package/dist/core/recovery/types.d.ts +20 -0
- package/dist/core/recovery/types.js +1 -0
- package/dist/core/replay-scrub.d.ts +9 -0
- package/dist/core/replay-scrub.js +43 -0
- package/dist/core/shell-tokenizer.d.ts +2 -0
- package/dist/core/shell-tokenizer.js +82 -23
- package/dist/core/standing-allow.d.ts +50 -0
- package/dist/core/standing-allow.js +178 -0
- package/dist/core/transactional/diff-evaluator.js +4 -1
- package/dist/core/transactional/eligibility.js +4 -0
- package/dist/core/transactional/git-worktree.d.ts +10 -3
- package/dist/core/transactional/git-worktree.js +81 -11
- package/dist/core/transactional/reasons.d.ts +1 -0
- package/dist/core/transactional/reasons.js +4 -0
- package/dist/core/transactional/runner.js +22 -6
- package/dist/core/transactional/types.d.ts +4 -0
- package/dist/core/types.d.ts +36 -3
- package/dist/core/verdict/adapter.d.ts +3 -4
- package/dist/core/verdict/adapter.js +19 -6
- package/dist/core/verdict/containment.d.ts +4 -3
- package/dist/core/verdict/containment.js +17 -12
- package/dist/core/verdict/cursor-acp-client.d.ts +67 -0
- package/dist/core/verdict/cursor-acp-client.js +345 -0
- package/dist/core/verdict/egress-classify.d.ts +2 -2
- package/dist/core/verdict/egress-classify.js +2 -2
- package/dist/core/verdict/git-classifier.d.ts +26 -0
- package/dist/core/verdict/git-classifier.js +533 -0
- package/dist/core/verdict/judge-audit.d.ts +1 -0
- package/dist/core/verdict/judge-audit.js +33 -1
- package/dist/core/verdict/judge-baseline.d.ts +20 -0
- package/dist/core/verdict/judge-baseline.js +49 -0
- package/dist/core/verdict/judge-broker-service.d.ts +42 -0
- package/dist/core/verdict/judge-broker-service.js +291 -0
- package/dist/core/verdict/judge-catalog.js +1 -0
- package/dist/core/verdict/judge-cli-fingerprint.d.ts +6 -0
- package/dist/core/verdict/judge-cli-fingerprint.js +67 -0
- package/dist/core/verdict/judge-cli.d.ts +23 -0
- package/dist/core/verdict/judge-cli.js +139 -16
- package/dist/core/verdict/judge-factory.js +13 -4
- package/dist/core/verdict/judge-provider-matrix.d.ts +20 -0
- package/dist/core/verdict/judge-provider-matrix.js +66 -0
- package/dist/core/verdict/judge-runtime-config.d.ts +44 -0
- package/dist/core/verdict/judge-runtime-config.js +96 -0
- package/dist/core/verdict/judge-session-broker.d.ts +48 -0
- package/dist/core/verdict/judge-session-broker.js +200 -0
- package/dist/core/verdict/judge-session-guard.d.ts +27 -0
- package/dist/core/verdict/judge-session-guard.js +91 -0
- package/dist/core/verdict/judge-session-kill-switch.d.ts +11 -0
- package/dist/core/verdict/judge-session-kill-switch.js +43 -0
- package/dist/core/verdict/judge-session-mutex.d.ts +9 -0
- package/dist/core/verdict/judge-session-mutex.js +23 -0
- package/dist/core/verdict/judge-shadow.d.ts +24 -0
- package/dist/core/verdict/judge-shadow.js +116 -0
- package/dist/core/verdict/judge-transport.d.ts +44 -0
- package/dist/core/verdict/judge-transport.js +268 -0
- package/dist/core/verdict/judge.d.ts +14 -14
- package/dist/core/verdict/judge.js +5 -67
- package/dist/core/verdict/launcher-resolve.d.ts +2 -0
- package/dist/core/verdict/launcher-resolve.js +16 -0
- package/dist/core/verdict/parser.js +6 -1
- package/dist/core/verdict/prescan.d.ts +15 -0
- package/dist/core/verdict/prescan.js +68 -0
- package/dist/core/verdict/shell-policy.d.ts +25 -0
- package/dist/core/verdict/shell-policy.js +40 -0
- package/dist/core/verdict/shell-semantics.d.ts +24 -0
- package/dist/core/verdict/shell-semantics.js +225 -0
- package/dist/core/verdict/types.d.ts +26 -1
- package/dist/core/verdict/verdict.js +300 -179
- package/dist/corpus/adversarial-probe.d.ts +86 -0
- package/dist/corpus/adversarial-probe.js +220 -0
- package/dist/corpus/evaluate.d.ts +45 -12
- package/dist/corpus/evaluate.js +61 -8
- package/dist/corpus/gate-latency-budget.d.ts +39 -0
- package/dist/corpus/gate-latency-budget.js +33 -0
- package/dist/corpus/gates.d.ts +35 -0
- package/dist/corpus/gates.js +81 -0
- package/dist/corpus/judge-accuracy.d.ts +8 -0
- package/dist/corpus/judge-accuracy.js +39 -0
- package/dist/corpus/must-allow-commands.d.ts +5 -0
- package/dist/corpus/must-allow-commands.js +13 -0
- package/dist/corpus/mutators.d.ts +28 -0
- package/dist/corpus/mutators.js +162 -0
- package/dist/corpus/ratchet.d.ts +42 -0
- package/dist/corpus/ratchet.js +116 -0
- package/dist/corpus/runtime-match.d.ts +19 -0
- package/dist/corpus/runtime-match.js +43 -0
- package/dist/corpus/standing-allow-catalog.generated.d.ts +13 -0
- package/dist/corpus/standing-allow-catalog.generated.js +99 -0
- package/dist/corpus/types.d.ts +47 -0
- package/dist/corpus/types.js +157 -0
- package/dist/installer.js +4 -1
- package/dist/judge-broker-daemon.d.ts +1 -0
- package/dist/judge-broker-daemon.js +137 -0
- package/dist/services/sandbox-service.d.ts +5 -0
- package/dist/services/sandbox-service.js +30 -2
- package/dist/types.d.ts +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -3
- package/skills/belay/SKILL.md +7 -1
- package/skills/belay/belay-approve.md +17 -0
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import { BOUNDARY_PROFILE_L3_L4_ONLY } from './capability/boundary-profile.js';
|
|
3
|
+
import { policyReasonToLegacyReason } from './capability/policy-bridge.js';
|
|
4
|
+
import { evaluateFileMutationPolicy, policyDecisionRequiresAsk, } from './capability/policy-engine.js';
|
|
2
5
|
import { canonicalStringify, toolFingerprint } from './fingerprint.js';
|
|
3
6
|
import { matchesSensitivePath } from './glob.js';
|
|
4
|
-
import { pathWithinRoot,
|
|
7
|
+
import { pathWithinRoot, resolveWorkspaceRootMatch } from './path-utils.js';
|
|
5
8
|
import { scrubValue } from './scrub.js';
|
|
6
9
|
import { classifyShell, resolveClassifierTrustedCwd } from './verdict/adapter.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
10
|
+
import { isGitPath } from './verdict/containment.js';
|
|
11
|
+
import { mutationPrescanRequiresAsk } from './verdict/prescan.js';
|
|
9
12
|
const DEFAULT_SENSITIVE_PATHS = ['.env', '.env.*', '**/credentials/**'];
|
|
10
13
|
const FILE_WRITE_TOOL_NAMES = new Set(['write']);
|
|
11
14
|
const FILE_EDIT_TOOL_NAMES = new Set([
|
|
@@ -18,6 +21,19 @@ const FILE_EDIT_TOOL_NAMES = new Set([
|
|
|
18
21
|
]);
|
|
19
22
|
const FILE_DELETE_TOOL_NAMES = new Set(['delete']);
|
|
20
23
|
const APPLY_PATCH_TOOL_NAMES = new Set(['apply_patch', 'applypatch']);
|
|
24
|
+
function policyAuth(options) {
|
|
25
|
+
if (!options.grants &&
|
|
26
|
+
options.attestation === undefined &&
|
|
27
|
+
options.egressProxyActive === undefined) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
grants: options.grants,
|
|
32
|
+
attestation: options.attestation,
|
|
33
|
+
egressProxyActive: options.egressProxyActive,
|
|
34
|
+
sensitivePaths: options.sensitivePaths,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
21
37
|
function scrubPayload(value, options) {
|
|
22
38
|
return scrubValue(value, options.scrubOptions);
|
|
23
39
|
}
|
|
@@ -76,25 +92,40 @@ function applyPatchTargets(patch) {
|
|
|
76
92
|
function normalizedToolName(toolName) {
|
|
77
93
|
return toolName.trim().toLowerCase();
|
|
78
94
|
}
|
|
79
|
-
function
|
|
80
|
-
return options.tier1Judge ?? createJudgeFromConfig(config, { repoRoot });
|
|
81
|
-
}
|
|
82
|
-
async function classifyFileMutationWithTier1(params) {
|
|
83
|
-
const judge = resolveFileTier1Judge(params.config, params.options, params.repoRoot);
|
|
95
|
+
function classifyFileMutationWithPolicy(params) {
|
|
84
96
|
const trustedCwd = resolveClassifierTrustedCwd(params.cwd, params.options);
|
|
85
97
|
const prescan = mutationPrescanRequiresAsk({
|
|
86
98
|
targets: [params.filePath],
|
|
87
99
|
cwd: params.cwd,
|
|
88
100
|
repoRoot: params.repoRoot,
|
|
89
101
|
trustedCwd,
|
|
102
|
+
trustedWorkspaceRoots: params.options.trustedWorkspaceRoots,
|
|
90
103
|
sensitivePaths: params.options.sensitivePaths ?? params.config.classifier.sensitivePaths,
|
|
91
104
|
});
|
|
92
105
|
if (prescan) {
|
|
106
|
+
const fingerprint = toolFingerprint(params.toolName, { path: params.filePath }, params.repoRoot);
|
|
107
|
+
const { request, decision } = evaluateFileMutationPolicy({
|
|
108
|
+
hookKind: 'tool',
|
|
109
|
+
toolKind: params.toolKind,
|
|
110
|
+
filePath: params.filePath,
|
|
111
|
+
resolvedPath: params.resolvedPath,
|
|
112
|
+
repoRoot: params.repoRoot,
|
|
113
|
+
cwd: params.cwd,
|
|
114
|
+
inputFingerprint: fingerprint,
|
|
115
|
+
signals: [...params.signals, 'tier1_catastrophic', prescan.reason],
|
|
116
|
+
isDelete: params.isDelete,
|
|
117
|
+
locationLabel: params.locationLabel,
|
|
118
|
+
trustedWorkspaceRoots: params.options.trustedWorkspaceRoots,
|
|
119
|
+
sensitivePaths: params.options.sensitivePaths ?? params.config.classifier.sensitivePaths,
|
|
120
|
+
}, params.config, policyAuth(params.options));
|
|
121
|
+
const legacyReason = policyDecisionRequiresAsk(decision)
|
|
122
|
+
? policyReasonToLegacyReason(decision)
|
|
123
|
+
: 'tier1_catastrophic';
|
|
93
124
|
return {
|
|
94
125
|
verdict: 'deny_pending_approval',
|
|
95
|
-
reason:
|
|
126
|
+
reason: legacyReason,
|
|
96
127
|
summary: params.filePath,
|
|
97
|
-
fingerprint
|
|
128
|
+
fingerprint,
|
|
98
129
|
assessment: {
|
|
99
130
|
reversibility: 'irreversible',
|
|
100
131
|
external: params.locationLabel === 'outside_repo',
|
|
@@ -102,20 +133,32 @@ async function classifyFileMutationWithTier1(params) {
|
|
|
102
133
|
? 'outside the repository'
|
|
103
134
|
: 'sensitive repository file',
|
|
104
135
|
confidence: 0.95,
|
|
105
|
-
signals: [...params.signals, 'tier1_catastrophic', prescan.reason],
|
|
136
|
+
signals: [...params.signals, 'tier1_catastrophic', prescan.reason, ...decision.signals],
|
|
106
137
|
},
|
|
138
|
+
capabilityRequests: [request],
|
|
139
|
+
authorizationDecision: decision,
|
|
140
|
+
boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY,
|
|
107
141
|
};
|
|
108
142
|
}
|
|
109
|
-
const tier1Text = `file_mutation: ${params.toolKind} path=${params.resolvedPath} location=${params.locationLabel}`;
|
|
110
|
-
const tier1 = await judge.evaluate({
|
|
111
|
-
text: tier1Text,
|
|
112
|
-
context: { cwd: params.cwd, repoRoot: params.repoRoot },
|
|
113
|
-
});
|
|
114
143
|
const fingerprint = toolFingerprint(params.toolName, { path: params.filePath }, params.repoRoot);
|
|
115
|
-
|
|
144
|
+
const { request, decision } = evaluateFileMutationPolicy({
|
|
145
|
+
hookKind: 'tool',
|
|
146
|
+
toolKind: params.toolKind,
|
|
147
|
+
filePath: params.filePath,
|
|
148
|
+
resolvedPath: params.resolvedPath,
|
|
149
|
+
repoRoot: params.repoRoot,
|
|
150
|
+
cwd: params.cwd,
|
|
151
|
+
inputFingerprint: fingerprint,
|
|
152
|
+
signals: params.signals,
|
|
153
|
+
isDelete: params.isDelete,
|
|
154
|
+
locationLabel: params.locationLabel,
|
|
155
|
+
trustedWorkspaceRoots: params.options.trustedWorkspaceRoots,
|
|
156
|
+
sensitivePaths: params.options.sensitivePaths ?? params.config.classifier.sensitivePaths,
|
|
157
|
+
}, params.config, policyAuth(params.options));
|
|
158
|
+
if (policyDecisionRequiresAsk(decision)) {
|
|
116
159
|
return {
|
|
117
160
|
verdict: 'deny_pending_approval',
|
|
118
|
-
reason:
|
|
161
|
+
reason: policyReasonToLegacyReason(decision),
|
|
119
162
|
summary: params.filePath,
|
|
120
163
|
fingerprint,
|
|
121
164
|
assessment: {
|
|
@@ -124,9 +167,12 @@ async function classifyFileMutationWithTier1(params) {
|
|
|
124
167
|
blastRadius: params.locationLabel === 'outside_repo'
|
|
125
168
|
? 'outside the repository'
|
|
126
169
|
: 'sensitive repository file',
|
|
127
|
-
confidence: 0.
|
|
128
|
-
signals: [...params.signals,
|
|
170
|
+
confidence: 0.95,
|
|
171
|
+
signals: [...params.signals, ...decision.signals],
|
|
129
172
|
},
|
|
173
|
+
capabilityRequests: [request],
|
|
174
|
+
authorizationDecision: decision,
|
|
175
|
+
boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY,
|
|
130
176
|
};
|
|
131
177
|
}
|
|
132
178
|
const reason = params.isDelete ? 'file_delete' : 'file_mutation';
|
|
@@ -140,8 +186,11 @@ async function classifyFileMutationWithTier1(params) {
|
|
|
140
186
|
external: params.locationLabel === 'outside_repo',
|
|
141
187
|
blastRadius: params.locationLabel === 'outside_repo' ? 'outside the repository' : 'this repository',
|
|
142
188
|
confidence: 0.72,
|
|
143
|
-
signals: [...params.signals,
|
|
189
|
+
signals: [...params.signals, ...decision.signals],
|
|
144
190
|
},
|
|
191
|
+
capabilityRequests: [request],
|
|
192
|
+
authorizationDecision: decision,
|
|
193
|
+
boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY,
|
|
145
194
|
};
|
|
146
195
|
}
|
|
147
196
|
export async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
@@ -229,24 +278,24 @@ export async function classifyToolUse(payload, repoRoot, cwd, config, options =
|
|
|
229
278
|
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
230
279
|
if (hitsProtectedRoot) {
|
|
231
280
|
signals.push('control_plane_path');
|
|
232
|
-
return {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
};
|
|
281
|
+
return classifyFileMutationWithPolicy({
|
|
282
|
+
toolName,
|
|
283
|
+
toolKind,
|
|
284
|
+
filePath,
|
|
285
|
+
resolvedPath,
|
|
286
|
+
repoRoot,
|
|
287
|
+
cwd,
|
|
288
|
+
config,
|
|
289
|
+
options,
|
|
290
|
+
signals,
|
|
291
|
+
isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
|
|
292
|
+
locationLabel: 'control_plane',
|
|
293
|
+
});
|
|
245
294
|
}
|
|
246
|
-
const
|
|
247
|
-
if (
|
|
295
|
+
const workspaceMatch = resolveWorkspaceRootMatch(repoRoot, options.trustedWorkspaceRoots, resolvedPath);
|
|
296
|
+
if (workspaceMatch === null) {
|
|
248
297
|
signals.push('outside_repo_path');
|
|
249
|
-
return
|
|
298
|
+
return classifyFileMutationWithPolicy({
|
|
250
299
|
toolName,
|
|
251
300
|
toolKind,
|
|
252
301
|
filePath,
|
|
@@ -260,9 +309,37 @@ export async function classifyToolUse(payload, repoRoot, cwd, config, options =
|
|
|
260
309
|
locationLabel: 'outside_repo',
|
|
261
310
|
});
|
|
262
311
|
}
|
|
312
|
+
if (workspaceMatch.kind === 'trusted') {
|
|
313
|
+
signals.push('trusted_workspace_root');
|
|
314
|
+
}
|
|
315
|
+
const trustedCwd = resolveClassifierTrustedCwd(cwd, options);
|
|
316
|
+
const workspacePrescan = mutationPrescanRequiresAsk({
|
|
317
|
+
targets: [filePath],
|
|
318
|
+
cwd,
|
|
319
|
+
repoRoot,
|
|
320
|
+
trustedCwd,
|
|
321
|
+
trustedWorkspaceRoots: options.trustedWorkspaceRoots,
|
|
322
|
+
sensitivePaths,
|
|
323
|
+
});
|
|
324
|
+
if (workspacePrescan) {
|
|
325
|
+
return classifyFileMutationWithPolicy({
|
|
326
|
+
toolName,
|
|
327
|
+
toolKind,
|
|
328
|
+
filePath,
|
|
329
|
+
resolvedPath,
|
|
330
|
+
repoRoot,
|
|
331
|
+
cwd,
|
|
332
|
+
config,
|
|
333
|
+
options,
|
|
334
|
+
signals,
|
|
335
|
+
isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
|
|
336
|
+
locationLabel: 'sensitive_path',
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
const relativePath = workspaceMatch.relativePath;
|
|
263
340
|
if (matchesSensitivePath(relativePath, sensitivePaths)) {
|
|
264
341
|
signals.push('sensitive_path');
|
|
265
|
-
return
|
|
342
|
+
return classifyFileMutationWithPolicy({
|
|
266
343
|
toolName,
|
|
267
344
|
toolKind,
|
|
268
345
|
filePath,
|
|
@@ -277,35 +354,51 @@ export async function classifyToolUse(payload, repoRoot, cwd, config, options =
|
|
|
277
354
|
});
|
|
278
355
|
}
|
|
279
356
|
if (FILE_DELETE_TOOL_NAMES.has(toolKind)) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
357
|
+
if (isGitPath(resolvedPath, repoRoot)) {
|
|
358
|
+
signals.push('protected_artifact');
|
|
359
|
+
return classifyFileMutationWithPolicy({
|
|
360
|
+
toolName,
|
|
361
|
+
toolKind,
|
|
362
|
+
filePath,
|
|
363
|
+
resolvedPath,
|
|
364
|
+
repoRoot,
|
|
365
|
+
cwd,
|
|
366
|
+
config,
|
|
367
|
+
options,
|
|
291
368
|
signals,
|
|
292
|
-
|
|
293
|
-
|
|
369
|
+
isDelete: true,
|
|
370
|
+
locationLabel: 'sensitive_path',
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
signals.push('file_delete');
|
|
374
|
+
return classifyFileMutationWithPolicy({
|
|
375
|
+
toolName,
|
|
376
|
+
toolKind,
|
|
377
|
+
filePath,
|
|
378
|
+
resolvedPath,
|
|
379
|
+
repoRoot,
|
|
380
|
+
cwd,
|
|
381
|
+
config,
|
|
382
|
+
options,
|
|
383
|
+
signals,
|
|
384
|
+
isDelete: true,
|
|
385
|
+
locationLabel: 'repo_local',
|
|
386
|
+
});
|
|
294
387
|
}
|
|
295
388
|
signals.push('file_mutation');
|
|
296
|
-
return {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
};
|
|
389
|
+
return classifyFileMutationWithPolicy({
|
|
390
|
+
toolName,
|
|
391
|
+
toolKind,
|
|
392
|
+
filePath,
|
|
393
|
+
resolvedPath,
|
|
394
|
+
repoRoot,
|
|
395
|
+
cwd,
|
|
396
|
+
config,
|
|
397
|
+
options,
|
|
398
|
+
signals,
|
|
399
|
+
isDelete: false,
|
|
400
|
+
locationLabel: 'repo_local',
|
|
401
|
+
});
|
|
309
402
|
}
|
|
310
403
|
if (APPLY_PATCH_TOOL_NAMES.has(toolKind)) {
|
|
311
404
|
const patch = extractPatch(payload);
|
package/dist/core/config.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { BoundaryDriverId } from './capability/attestation.js';
|
|
2
|
+
import type { BelayMode, ClassifierOptions, ControlPlaneIntegrity, ScrubOptions, UnknownLocalEffectPolicy, UnparseableShellPolicy } from './types.js';
|
|
3
|
+
import { type BelayJudgeRuntimeConfig } from './verdict/judge-runtime-config.js';
|
|
3
4
|
export type { UnknownLocalEffectPolicy };
|
|
4
5
|
export interface BelayConfigV1 {
|
|
5
6
|
version: 1;
|
|
@@ -93,7 +94,10 @@ export interface JudgeCloudConsent {
|
|
|
93
94
|
endpoint: string;
|
|
94
95
|
by: string;
|
|
95
96
|
}
|
|
97
|
+
export type BelayJudgeMode = 'shadow' | 'off';
|
|
96
98
|
export interface BelayJudgeConfig {
|
|
99
|
+
/** Gate uses PolicyEngine; judge runs async shadow/compare only. */
|
|
100
|
+
mode?: BelayJudgeMode;
|
|
97
101
|
provider: JudgeProvider;
|
|
98
102
|
providerId?: JudgeProviderId | DeprecatedJudgeProviderId;
|
|
99
103
|
model: string;
|
|
@@ -102,6 +106,7 @@ export interface BelayJudgeConfig {
|
|
|
102
106
|
keepAlive: string | null;
|
|
103
107
|
cloudConsent?: JudgeCloudConsent;
|
|
104
108
|
credential?: JudgeCredentialConfig;
|
|
109
|
+
runtime?: BelayJudgeRuntimeConfig;
|
|
105
110
|
}
|
|
106
111
|
export declare const DEFAULT_JUDGE_LOCAL_OLLAMA: BelayJudgeConfig;
|
|
107
112
|
export declare const DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE: BelayJudgeConfig;
|
|
@@ -137,6 +142,17 @@ export interface BelayApprovalSigningConfig {
|
|
|
137
142
|
/** When true, out-of-band approvals must present a signed token. */
|
|
138
143
|
required: boolean;
|
|
139
144
|
}
|
|
145
|
+
export type ApprovalFlow = 'one_step' | 'two_step';
|
|
146
|
+
export interface BelayApprovalAutoReplayScopes {
|
|
147
|
+
shell: boolean;
|
|
148
|
+
tool: boolean;
|
|
149
|
+
subagent: boolean;
|
|
150
|
+
}
|
|
151
|
+
export interface BelayApprovalConfig {
|
|
152
|
+
flow: ApprovalFlow;
|
|
153
|
+
autoReplayScopes: BelayApprovalAutoReplayScopes;
|
|
154
|
+
executionLeaseMs: number;
|
|
155
|
+
}
|
|
140
156
|
export interface BelayEgressConfig {
|
|
141
157
|
enabled: boolean;
|
|
142
158
|
listenHost: string;
|
|
@@ -144,8 +160,14 @@ export interface BelayEgressConfig {
|
|
|
144
160
|
/** When true with egress enabled, L3 external command lists become hints only. */
|
|
145
161
|
demoteL3External: boolean;
|
|
146
162
|
}
|
|
163
|
+
export interface BelayCapabilityConfig {
|
|
164
|
+
grantsEnabled?: boolean;
|
|
165
|
+
boundaryDriver?: BoundaryDriverId;
|
|
166
|
+
attestationRelPath?: string;
|
|
167
|
+
}
|
|
168
|
+
export declare const DEFAULT_CAPABILITY_V5: BelayCapabilityConfig;
|
|
147
169
|
export interface BelayConfigV4 {
|
|
148
|
-
version: 4;
|
|
170
|
+
version: 4 | 5;
|
|
149
171
|
adapter?: 'cursor' | 'claude' | 'codex';
|
|
150
172
|
/** Where hooks/runtime/skill artifacts are installed. Defaults to project. */
|
|
151
173
|
installScope?: 'project' | 'global';
|
|
@@ -160,10 +182,12 @@ export interface BelayConfigV4 {
|
|
|
160
182
|
controlPlane: BelayControlPlaneConfig;
|
|
161
183
|
notifications: BelayNotificationsConfig;
|
|
162
184
|
approvalSigning: BelayApprovalSigningConfig;
|
|
185
|
+
approval: BelayApprovalConfig;
|
|
163
186
|
egress: BelayEgressConfig;
|
|
164
187
|
sandbox: BelaySandboxConfig;
|
|
165
188
|
audit: BelayConfigV2['audit'];
|
|
166
189
|
judge: BelayJudgeConfig;
|
|
190
|
+
capability?: BelayCapabilityConfig;
|
|
167
191
|
}
|
|
168
192
|
/** @deprecated Use BelayConfigV4 */
|
|
169
193
|
export type BelayConfigV3 = BelayConfigV4;
|
|
@@ -184,6 +208,7 @@ export declare const DEFAULT_CONTROL_PLANE_V3: BelayControlPlaneConfig;
|
|
|
184
208
|
export declare const DEFAULT_SANDBOX_V3: BelaySandboxConfig;
|
|
185
209
|
export declare const DEFAULT_NOTIFICATIONS_V3: BelayNotificationsConfig;
|
|
186
210
|
export declare const DEFAULT_APPROVAL_SIGNING_V3: BelayApprovalSigningConfig;
|
|
211
|
+
export declare const DEFAULT_APPROVAL_CONFIG: BelayApprovalConfig;
|
|
187
212
|
export declare const DEFAULT_EGRESS_V3: BelayEgressConfig;
|
|
188
213
|
export declare function normalizeEgressListenHost(host: string): string;
|
|
189
214
|
export declare const DEFAULT_CONFIG_V2: BelayConfigV2;
|
|
@@ -217,10 +242,14 @@ type RawConfigInput = Partial<{
|
|
|
217
242
|
controlPlane: Partial<BelayControlPlaneConfig>;
|
|
218
243
|
notifications: Partial<BelayNotificationsConfig>;
|
|
219
244
|
approvalSigning: Partial<BelayApprovalSigningConfig>;
|
|
245
|
+
approval: Partial<BelayApprovalConfig> & {
|
|
246
|
+
autoReplayScopes?: Partial<BelayApprovalAutoReplayScopes>;
|
|
247
|
+
};
|
|
220
248
|
egress: Partial<BelayEgressConfig>;
|
|
221
249
|
sandbox: Partial<BelaySandboxConfig>;
|
|
222
250
|
audit: Partial<BelayConfigV2['audit']>;
|
|
223
251
|
installScope: 'project' | 'global';
|
|
252
|
+
capability: Partial<BelayCapabilityConfig>;
|
|
224
253
|
}>;
|
|
225
254
|
export declare function migrateConfig(loaded: unknown): BelayConfigV4;
|
|
226
255
|
export declare function normalizeConfigV2(config: BelayConfigV2): BelayConfigV2;
|
package/dist/core/config.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { warnDeprecatedJudgeModelAuto } from './judge-model-policy.js';
|
|
3
3
|
import { getJudgeProviderSpec, inferProviderIdFromConfig, isRemovedProviderId, normalizeLegacyProviderId, warnRemovedProviderId, } from './verdict/judge-catalog.js';
|
|
4
|
+
import { normalizeJudgeRuntimeConfig, } from './verdict/judge-runtime-config.js';
|
|
4
5
|
export const DEFAULT_JUDGE_LOCAL_OLLAMA = {
|
|
6
|
+
mode: 'shadow',
|
|
5
7
|
provider: 'ollama',
|
|
6
8
|
providerId: 'ollama',
|
|
7
9
|
model: 'gemma4:e2b',
|
|
@@ -10,6 +12,7 @@ export const DEFAULT_JUDGE_LOCAL_OLLAMA = {
|
|
|
10
12
|
keepAlive: '30m',
|
|
11
13
|
};
|
|
12
14
|
export const DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE = {
|
|
15
|
+
mode: 'shadow',
|
|
13
16
|
provider: 'openai-compatible',
|
|
14
17
|
providerId: 'codex',
|
|
15
18
|
model: 'gpt-5.3-codex-high',
|
|
@@ -19,6 +22,23 @@ export const DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE = {
|
|
|
19
22
|
};
|
|
20
23
|
/** @deprecated Use DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE */
|
|
21
24
|
export const DEFAULT_JUDGE_CURSOR_COMPOSER = DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE;
|
|
25
|
+
export const DEFAULT_CAPABILITY_V5 = {
|
|
26
|
+
grantsEnabled: true,
|
|
27
|
+
boundaryDriver: 'host-integration',
|
|
28
|
+
attestationRelPath: '.belay/attestation.json',
|
|
29
|
+
};
|
|
30
|
+
function normalizeCapabilityConfig(capability) {
|
|
31
|
+
if (!capability) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
...DEFAULT_CAPABILITY_V5,
|
|
36
|
+
...capability,
|
|
37
|
+
grantsEnabled: capability.grantsEnabled !== false,
|
|
38
|
+
boundaryDriver: capability.boundaryDriver ?? DEFAULT_CAPABILITY_V5.boundaryDriver,
|
|
39
|
+
attestationRelPath: capability.attestationRelPath ?? DEFAULT_CAPABILITY_V5.attestationRelPath,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
22
42
|
/** Pre-v0.4 defaults preserved when migrating existing v1/v2/v3 configs. */
|
|
23
43
|
import { DEFAULT_SILENT_PASS_THRESHOLD } from './audit-summary.js';
|
|
24
44
|
/** @deprecated Use DEFAULT_SILENT_PASS_THRESHOLD from audit-summary.js */
|
|
@@ -95,6 +115,15 @@ export const DEFAULT_NOTIFICATIONS_V3 = {};
|
|
|
95
115
|
export const DEFAULT_APPROVAL_SIGNING_V3 = {
|
|
96
116
|
required: false,
|
|
97
117
|
};
|
|
118
|
+
export const DEFAULT_APPROVAL_CONFIG = {
|
|
119
|
+
flow: 'one_step',
|
|
120
|
+
autoReplayScopes: {
|
|
121
|
+
shell: true,
|
|
122
|
+
tool: false,
|
|
123
|
+
subagent: false,
|
|
124
|
+
},
|
|
125
|
+
executionLeaseMs: 60_000,
|
|
126
|
+
};
|
|
98
127
|
export const DEFAULT_EGRESS_V3 = {
|
|
99
128
|
enabled: false,
|
|
100
129
|
listenHost: '127.0.0.1',
|
|
@@ -148,6 +177,7 @@ export const DEFAULT_CONFIG_V4 = {
|
|
|
148
177
|
controlPlane: { ...DEFAULT_CONTROL_PLANE_V3 },
|
|
149
178
|
notifications: { ...DEFAULT_NOTIFICATIONS_V3 },
|
|
150
179
|
approvalSigning: { ...DEFAULT_APPROVAL_SIGNING_V3 },
|
|
180
|
+
approval: { ...DEFAULT_APPROVAL_CONFIG },
|
|
151
181
|
egress: { ...DEFAULT_EGRESS_V3 },
|
|
152
182
|
sandbox: { ...DEFAULT_SANDBOX_V3 },
|
|
153
183
|
audit: { ...DEFAULT_CONFIG_V2.audit },
|
|
@@ -190,6 +220,7 @@ export function migrateV2ToV3(v2, rawOverrides) {
|
|
|
190
220
|
controlPlane: { ...LEGACY_CONTROL_PLANE_V3 },
|
|
191
221
|
notifications: { ...DEFAULT_NOTIFICATIONS_V3 },
|
|
192
222
|
approvalSigning: { ...DEFAULT_APPROVAL_SIGNING_V3 },
|
|
223
|
+
approval: { ...DEFAULT_APPROVAL_CONFIG },
|
|
193
224
|
egress: { ...DEFAULT_EGRESS_V3 },
|
|
194
225
|
sandbox: { ...DEFAULT_SANDBOX_V3 },
|
|
195
226
|
audit: v2.audit,
|
|
@@ -210,7 +241,8 @@ export function isConfigV3(value) {
|
|
|
210
241
|
return version === 3 || version === 4;
|
|
211
242
|
}
|
|
212
243
|
export function isConfigV4(value) {
|
|
213
|
-
|
|
244
|
+
const version = typeof value === 'object' && value !== null ? value.version : null;
|
|
245
|
+
return version === 4 || version === 5;
|
|
214
246
|
}
|
|
215
247
|
export function normalizeJudgeProvider(provider) {
|
|
216
248
|
if (provider === 'anthropic') {
|
|
@@ -227,6 +259,7 @@ function defaultJudgeTemplateForProvider(provider) {
|
|
|
227
259
|
}
|
|
228
260
|
if (provider === 'anthropic') {
|
|
229
261
|
return {
|
|
262
|
+
mode: 'shadow',
|
|
230
263
|
provider: 'anthropic',
|
|
231
264
|
providerId: 'claude',
|
|
232
265
|
model: 'claude-sonnet-4-6',
|
|
@@ -271,6 +304,7 @@ export function normalizeJudgeConfig(judge) {
|
|
|
271
304
|
const timeoutMs = typeof judge.timeoutMs === 'number' && judge.timeoutMs > 0 ? judge.timeoutMs : base.timeoutMs;
|
|
272
305
|
const endpoint = typeof judge.endpoint === 'string' && judge.endpoint.trim() ? judge.endpoint.trim() : null;
|
|
273
306
|
return {
|
|
307
|
+
mode: judge.mode === 'off' ? 'off' : 'shadow',
|
|
274
308
|
provider,
|
|
275
309
|
providerId: rawProviderId,
|
|
276
310
|
model,
|
|
@@ -283,6 +317,7 @@ export function normalizeJudgeConfig(judge) {
|
|
|
283
317
|
: null,
|
|
284
318
|
...(judge.cloudConsent ? { cloudConsent: judge.cloudConsent } : {}),
|
|
285
319
|
...(judge.credential ? { credential: judge.credential } : {}),
|
|
320
|
+
runtime: normalizeJudgeRuntimeConfig(judge.runtime),
|
|
286
321
|
};
|
|
287
322
|
}
|
|
288
323
|
let providerId = rawProviderId && normalizeLegacyProviderId(rawProviderId)
|
|
@@ -307,6 +342,7 @@ export function normalizeJudgeConfig(judge) {
|
|
|
307
342
|
endpoint = catalogSpec.defaultEndpoint;
|
|
308
343
|
}
|
|
309
344
|
const normalized = {
|
|
345
|
+
mode: judge.mode === 'off' ? 'off' : 'shadow',
|
|
310
346
|
provider,
|
|
311
347
|
providerId,
|
|
312
348
|
model,
|
|
@@ -333,6 +369,7 @@ export function normalizeJudgeConfig(judge) {
|
|
|
333
369
|
...(judge.credential.ref ? { ref: judge.credential.ref } : {}),
|
|
334
370
|
};
|
|
335
371
|
}
|
|
372
|
+
normalized.runtime = normalizeJudgeRuntimeConfig(judge.runtime);
|
|
336
373
|
return normalized;
|
|
337
374
|
}
|
|
338
375
|
export function rejectTeamLayerJudgeSecrets(judge, source) {
|
|
@@ -395,6 +432,14 @@ function mergeV3FromRaw(base, raw) {
|
|
|
395
432
|
...base.approvalSigning,
|
|
396
433
|
...(raw.approvalSigning ?? {}),
|
|
397
434
|
},
|
|
435
|
+
approval: {
|
|
436
|
+
...base.approval,
|
|
437
|
+
...(raw.approval ?? {}),
|
|
438
|
+
autoReplayScopes: {
|
|
439
|
+
...base.approval.autoReplayScopes,
|
|
440
|
+
...(raw.approval?.autoReplayScopes ?? {}),
|
|
441
|
+
},
|
|
442
|
+
},
|
|
398
443
|
egress: {
|
|
399
444
|
...base.egress,
|
|
400
445
|
...(raw.egress ?? {}),
|
|
@@ -446,6 +491,14 @@ function normalizeV3Raw(raw) {
|
|
|
446
491
|
approvalSigning: {
|
|
447
492
|
required: raw.approvalSigning?.required === true,
|
|
448
493
|
},
|
|
494
|
+
approval: {
|
|
495
|
+
...DEFAULT_APPROVAL_CONFIG,
|
|
496
|
+
...(raw.approval ?? {}),
|
|
497
|
+
autoReplayScopes: {
|
|
498
|
+
...DEFAULT_APPROVAL_CONFIG.autoReplayScopes,
|
|
499
|
+
...(raw.approval?.autoReplayScopes ?? {}),
|
|
500
|
+
},
|
|
501
|
+
},
|
|
449
502
|
egress: {
|
|
450
503
|
...DEFAULT_EGRESS_V3,
|
|
451
504
|
...(raw.egress ?? {}),
|
|
@@ -460,6 +513,19 @@ function normalizeV3Raw(raw) {
|
|
|
460
513
|
},
|
|
461
514
|
});
|
|
462
515
|
}
|
|
516
|
+
function normalizeV5Raw(raw) {
|
|
517
|
+
const base = normalizeV3Raw({ ...raw, version: 4 });
|
|
518
|
+
return {
|
|
519
|
+
...base,
|
|
520
|
+
version: 5,
|
|
521
|
+
capability: {
|
|
522
|
+
grantsEnabled: raw.capability?.grantsEnabled !== false,
|
|
523
|
+
boundaryDriver: raw.capability?.boundaryDriver ?? 'host-integration',
|
|
524
|
+
attestationRelPath: raw.capability?.attestationRelPath ?? '.belay/attestation.json',
|
|
525
|
+
...(raw.capability ?? {}),
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
|
+
}
|
|
463
529
|
export function migrateConfig(loaded) {
|
|
464
530
|
if (typeof loaded !== 'object' || loaded === null) {
|
|
465
531
|
return { ...DEFAULT_CONFIG_V4 };
|
|
@@ -468,6 +534,9 @@ export function migrateConfig(loaded) {
|
|
|
468
534
|
if (raw.version === 4) {
|
|
469
535
|
return normalizeV3Raw(raw);
|
|
470
536
|
}
|
|
537
|
+
if (raw.version === 5) {
|
|
538
|
+
return normalizeV5Raw(raw);
|
|
539
|
+
}
|
|
471
540
|
if (raw.version === 3 || (raw.version === undefined && hasV3Sections(raw))) {
|
|
472
541
|
return normalizeV3Raw(raw);
|
|
473
542
|
}
|
|
@@ -546,8 +615,9 @@ export function normalizeConfig(config) {
|
|
|
546
615
|
return normalizeConfigV2(config);
|
|
547
616
|
}
|
|
548
617
|
const v4 = config;
|
|
549
|
-
|
|
550
|
-
|
|
618
|
+
const version = v4.version === 5 ? 5 : 4;
|
|
619
|
+
const normalized = {
|
|
620
|
+
version,
|
|
551
621
|
...(v4.installScope === 'global' || v4.installScope === 'project'
|
|
552
622
|
? { installScope: v4.installScope }
|
|
553
623
|
: {}),
|
|
@@ -676,6 +746,17 @@ export function normalizeConfig(config) {
|
|
|
676
746
|
approvalSigning: {
|
|
677
747
|
required: v4.approvalSigning?.required === true,
|
|
678
748
|
},
|
|
749
|
+
approval: {
|
|
750
|
+
flow: v4.approval?.flow === 'two_step' ? 'two_step' : DEFAULT_APPROVAL_CONFIG.flow,
|
|
751
|
+
autoReplayScopes: {
|
|
752
|
+
shell: v4.approval?.autoReplayScopes?.shell !== false,
|
|
753
|
+
tool: v4.approval?.autoReplayScopes?.tool === true,
|
|
754
|
+
subagent: v4.approval?.autoReplayScopes?.subagent === true,
|
|
755
|
+
},
|
|
756
|
+
executionLeaseMs: typeof v4.approval?.executionLeaseMs === 'number' && v4.approval.executionLeaseMs > 0
|
|
757
|
+
? v4.approval.executionLeaseMs
|
|
758
|
+
: DEFAULT_APPROVAL_CONFIG.executionLeaseMs,
|
|
759
|
+
},
|
|
679
760
|
egress: {
|
|
680
761
|
enabled: v4.egress?.enabled === true,
|
|
681
762
|
listenHost: normalizeEgressListenHost(typeof v4.egress?.listenHost === 'string' && v4.egress.listenHost.trim()
|
|
@@ -702,6 +783,10 @@ export function normalizeConfig(config) {
|
|
|
702
783
|
},
|
|
703
784
|
judge: normalizeJudgeConfig(v4.judge ?? DEFAULT_JUDGE_LOCAL_OLLAMA),
|
|
704
785
|
};
|
|
786
|
+
if (version === 5 || v4.capability) {
|
|
787
|
+
normalized.capability = normalizeCapabilityConfig(v4.capability ?? DEFAULT_CAPABILITY_V5);
|
|
788
|
+
}
|
|
789
|
+
return normalized;
|
|
705
790
|
}
|
|
706
791
|
export function isFreshConfigInput(loaded) {
|
|
707
792
|
if (loaded === null || loaded === undefined) {
|
|
@@ -752,6 +837,14 @@ export function mergeConfig(existing, defaults = DEFAULT_CONFIG_V4) {
|
|
|
752
837
|
...defaults.approvalSigning,
|
|
753
838
|
...migrated.approvalSigning,
|
|
754
839
|
},
|
|
840
|
+
approval: {
|
|
841
|
+
...defaults.approval,
|
|
842
|
+
...migrated.approval,
|
|
843
|
+
autoReplayScopes: {
|
|
844
|
+
...defaults.approval.autoReplayScopes,
|
|
845
|
+
...migrated.approval.autoReplayScopes,
|
|
846
|
+
},
|
|
847
|
+
},
|
|
755
848
|
egress: {
|
|
756
849
|
...defaults.egress,
|
|
757
850
|
...migrated.egress,
|
|
@@ -765,6 +858,15 @@ export function mergeConfig(existing, defaults = DEFAULT_CONFIG_V4) {
|
|
|
765
858
|
...migrated.audit,
|
|
766
859
|
},
|
|
767
860
|
...(migrated.installScope ? { installScope: migrated.installScope } : {}),
|
|
861
|
+
...(migrated.version === 5 || migrated.capability
|
|
862
|
+
? {
|
|
863
|
+
version: migrated.version === 5 ? 5 : 4,
|
|
864
|
+
capability: normalizeCapabilityConfig({
|
|
865
|
+
...DEFAULT_CAPABILITY_V5,
|
|
866
|
+
...migrated.capability,
|
|
867
|
+
}),
|
|
868
|
+
}
|
|
869
|
+
: {}),
|
|
768
870
|
});
|
|
769
871
|
}
|
|
770
872
|
export function scrubOptionsFromConfig(config) {
|
|
@@ -29,6 +29,9 @@ export interface GateVerdict extends GatePermissionResponse {
|
|
|
29
29
|
wouldBlock: boolean;
|
|
30
30
|
mode: 'enforce' | 'audit';
|
|
31
31
|
axes?: ClassifyResult['axes'];
|
|
32
|
+
capabilityRequests?: ClassifyResult['capabilityRequests'];
|
|
33
|
+
authorizationDecision?: ClassifyResult['authorizationDecision'];
|
|
34
|
+
boundaryProfile?: string;
|
|
32
35
|
}
|
|
33
36
|
export declare function isGatedAction(value: unknown): value is GatedAction;
|
|
34
37
|
export declare function classifyResultToGateVerdict(params: {
|
|
@@ -26,6 +26,9 @@ export function classifyResultToGateVerdict(params) {
|
|
|
26
26
|
user_message,
|
|
27
27
|
agent_message,
|
|
28
28
|
axes: result.axes,
|
|
29
|
+
capabilityRequests: result.capabilityRequests,
|
|
30
|
+
authorizationDecision: result.authorizationDecision,
|
|
31
|
+
boundaryProfile: result.boundaryProfile,
|
|
29
32
|
};
|
|
30
33
|
}
|
|
31
34
|
export function unnormalizedGateVerdict(params) {
|