@guilz-dev/belay 0.1.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/LICENSE +21 -0
- package/README.md +268 -0
- package/agent-belay-logo.png +0 -0
- package/dist/adapters/claude/adapter.d.ts +7 -0
- package/dist/adapters/claude/adapter.js +114 -0
- package/dist/adapters/claude/hooks.d.ts +13 -0
- package/dist/adapters/claude/hooks.js +49 -0
- package/dist/adapters/claude/runtime-entry.d.ts +4 -0
- package/dist/adapters/claude/runtime-entry.js +260 -0
- package/dist/adapters/codex/adapter.d.ts +7 -0
- package/dist/adapters/codex/adapter.js +73 -0
- package/dist/adapters/codex/hooks.d.ts +21 -0
- package/dist/adapters/codex/hooks.js +78 -0
- package/dist/adapters/codex/runtime-entry.d.ts +4 -0
- package/dist/adapters/codex/runtime-entry.js +237 -0
- package/dist/adapters/cursor/adapter.d.ts +7 -0
- package/dist/adapters/cursor/adapter.js +29 -0
- package/dist/adapters/cursor/hooks.d.ts +2 -0
- package/dist/adapters/cursor/hooks.js +26 -0
- package/dist/adapters/cursor/runtime-entry.d.ts +4 -0
- package/dist/adapters/cursor/runtime-entry.js +143 -0
- package/dist/adapters/layouts/claude.d.ts +2 -0
- package/dist/adapters/layouts/claude.js +40 -0
- package/dist/adapters/layouts/codex.d.ts +2 -0
- package/dist/adapters/layouts/codex.js +43 -0
- package/dist/adapters/layouts/cursor.d.ts +2 -0
- package/dist/adapters/layouts/cursor.js +40 -0
- package/dist/adapters/layouts/index.d.ts +7 -0
- package/dist/adapters/layouts/index.js +23 -0
- package/dist/adapters/layouts/protected-paths.d.ts +3 -0
- package/dist/adapters/layouts/protected-paths.js +15 -0
- package/dist/adapters/layouts/scope.d.ts +19 -0
- package/dist/adapters/layouts/scope.js +86 -0
- package/dist/adapters/layouts/types.d.ts +14 -0
- package/dist/adapters/layouts/types.js +1 -0
- package/dist/adapters/registry.d.ts +4 -0
- package/dist/adapters/registry.js +14 -0
- package/dist/adapters/shared/gate-runtime.d.ts +51 -0
- package/dist/adapters/shared/gate-runtime.js +518 -0
- package/dist/adapters/shared/repo-root.d.ts +2 -0
- package/dist/adapters/shared/repo-root.js +17 -0
- package/dist/adapters/types.d.ts +19 -0
- package/dist/adapters/types.js +1 -0
- package/dist/branding.d.ts +3 -0
- package/dist/branding.js +3 -0
- package/dist/bundle/claude-runtime.mjs +5323 -0
- package/dist/bundle/codex-runtime.mjs +5310 -0
- package/dist/bundle/cursor-runtime.mjs +5208 -0
- package/dist/cleanup-orphans.d.ts +7 -0
- package/dist/cleanup-orphans.js +59 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +631 -0
- package/dist/commands/approve.d.ts +14 -0
- package/dist/commands/approve.js +65 -0
- package/dist/commands/audit.d.ts +59 -0
- package/dist/commands/audit.js +132 -0
- package/dist/commands/classify-for-report.d.ts +9 -0
- package/dist/commands/classify-for-report.js +85 -0
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.js +366 -0
- package/dist/commands/dogfood.d.ts +5 -0
- package/dist/commands/dogfood.js +71 -0
- package/dist/commands/explain.d.ts +3 -0
- package/dist/commands/explain.js +133 -0
- package/dist/commands/health-snapshot.d.ts +2 -0
- package/dist/commands/health-snapshot.js +166 -0
- package/dist/commands/init-wizard.d.ts +16 -0
- package/dist/commands/init-wizard.js +50 -0
- package/dist/commands/metrics.d.ts +7 -0
- package/dist/commands/metrics.js +89 -0
- package/dist/commands/recover.d.ts +3 -0
- package/dist/commands/recover.js +105 -0
- package/dist/commands/report.d.ts +3 -0
- package/dist/commands/report.js +65 -0
- package/dist/commands/revoke.d.ts +5 -0
- package/dist/commands/revoke.js +22 -0
- package/dist/commands/simulate.d.ts +14 -0
- package/dist/commands/simulate.js +55 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.js +107 -0
- package/dist/config-io.d.ts +23 -0
- package/dist/config-io.js +180 -0
- package/dist/conformance/guarantee-table.d.ts +14 -0
- package/dist/conformance/guarantee-table.js +95 -0
- package/dist/conformance/types.d.ts +6 -0
- package/dist/conformance/types.js +1 -0
- package/dist/core/approval-service.d.ts +26 -0
- package/dist/core/approval-service.js +41 -0
- package/dist/core/approval-token.d.ts +11 -0
- package/dist/core/approval-token.js +61 -0
- package/dist/core/approval.d.ts +19 -0
- package/dist/core/approval.js +58 -0
- package/dist/core/audit-analysis.d.ts +10 -0
- package/dist/core/audit-analysis.js +147 -0
- package/dist/core/audit-metrics.d.ts +51 -0
- package/dist/core/audit-metrics.js +155 -0
- package/dist/core/audit-query.d.ts +11 -0
- package/dist/core/audit-query.js +142 -0
- package/dist/core/audit-summary.d.ts +33 -0
- package/dist/core/audit-summary.js +111 -0
- package/dist/core/audit-types.d.ts +65 -0
- package/dist/core/audit-types.js +2 -0
- package/dist/core/capability/allowlist.d.ts +10 -0
- package/dist/core/capability/allowlist.js +53 -0
- package/dist/core/capability/broker.d.ts +17 -0
- package/dist/core/capability/broker.js +29 -0
- package/dist/core/capability/index.d.ts +5 -0
- package/dist/core/capability/index.js +4 -0
- package/dist/core/capability/paths.d.ts +1 -0
- package/dist/core/capability/paths.js +20 -0
- package/dist/core/capability/reasons.d.ts +2 -0
- package/dist/core/capability/reasons.js +4 -0
- package/dist/core/capability/types.d.ts +10 -0
- package/dist/core/capability/types.js +1 -0
- package/dist/core/capability-approval.d.ts +28 -0
- package/dist/core/capability-approval.js +43 -0
- package/dist/core/classify-subagent.d.ts +2 -0
- package/dist/core/classify-subagent.js +69 -0
- package/dist/core/classify-tool.d.ts +3 -0
- package/dist/core/classify-tool.js +311 -0
- package/dist/core/config-layers.d.ts +23 -0
- package/dist/core/config-layers.js +59 -0
- package/dist/core/config.d.ts +219 -0
- package/dist/core/config.js +720 -0
- package/dist/core/control-plane-isolation.d.ts +10 -0
- package/dist/core/control-plane-isolation.js +83 -0
- package/dist/core/custom-command-match.d.ts +2 -0
- package/dist/core/custom-command-match.js +8 -0
- package/dist/core/egress/allowlist.d.ts +7 -0
- package/dist/core/egress/allowlist.js +33 -0
- package/dist/core/egress/env.d.ts +3 -0
- package/dist/core/egress/env.js +17 -0
- package/dist/core/egress/fingerprint.d.ts +3 -0
- package/dist/core/egress/fingerprint.js +35 -0
- package/dist/core/egress/policy.d.ts +8 -0
- package/dist/core/egress/policy.js +47 -0
- package/dist/core/egress/proxy-server.d.ts +21 -0
- package/dist/core/egress/proxy-server.js +263 -0
- package/dist/core/egress/types.d.ts +25 -0
- package/dist/core/egress/types.js +1 -0
- package/dist/core/egress-approval.d.ts +48 -0
- package/dist/core/egress-approval.js +129 -0
- package/dist/core/fingerprint.d.ts +6 -0
- package/dist/core/fingerprint.js +24 -0
- package/dist/core/gate-contract.d.ts +48 -0
- package/dist/core/gate-contract.js +50 -0
- package/dist/core/gate-engine.d.ts +20 -0
- package/dist/core/gate-engine.js +172 -0
- package/dist/core/glob.d.ts +1 -0
- package/dist/core/glob.js +39 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.js +15 -0
- package/dist/core/integrity.d.ts +15 -0
- package/dist/core/integrity.js +68 -0
- package/dist/core/judge-api-key.d.ts +4 -0
- package/dist/core/judge-api-key.js +11 -0
- package/dist/core/judge-config.d.ts +29 -0
- package/dist/core/judge-config.js +85 -0
- package/dist/core/judge-doctor.d.ts +7 -0
- package/dist/core/judge-doctor.js +124 -0
- package/dist/core/judgment.d.ts +6 -0
- package/dist/core/judgment.js +38 -0
- package/dist/core/notify.d.ts +13 -0
- package/dist/core/notify.js +44 -0
- package/dist/core/path-utils.d.ts +12 -0
- package/dist/core/path-utils.js +107 -0
- package/dist/core/reclassify.d.ts +15 -0
- package/dist/core/reclassify.js +82 -0
- package/dist/core/recover-advice.d.ts +30 -0
- package/dist/core/recover-advice.js +177 -0
- package/dist/core/recover-git-probe.d.ts +8 -0
- package/dist/core/recover-git-probe.js +50 -0
- package/dist/core/recover-select.d.ts +10 -0
- package/dist/core/recover-select.js +60 -0
- package/dist/core/scrub.d.ts +3 -0
- package/dist/core/scrub.js +87 -0
- package/dist/core/shell-substitution.d.ts +6 -0
- package/dist/core/shell-substitution.js +130 -0
- package/dist/core/shell-tokenizer.d.ts +5 -0
- package/dist/core/shell-tokenizer.js +129 -0
- package/dist/core/shell-unparseable.d.ts +4 -0
- package/dist/core/shell-unparseable.js +96 -0
- package/dist/core/transactional/diff-evaluator.d.ts +2 -0
- package/dist/core/transactional/diff-evaluator.js +84 -0
- package/dist/core/transactional/eligibility.d.ts +4 -0
- package/dist/core/transactional/eligibility.js +44 -0
- package/dist/core/transactional/git-worktree.d.ts +13 -0
- package/dist/core/transactional/git-worktree.js +189 -0
- package/dist/core/transactional/index.d.ts +5 -0
- package/dist/core/transactional/index.js +4 -0
- package/dist/core/transactional/reasons.d.ts +4 -0
- package/dist/core/transactional/reasons.js +8 -0
- package/dist/core/transactional/runner.d.ts +2 -0
- package/dist/core/transactional/runner.js +113 -0
- package/dist/core/transactional/types.d.ts +46 -0
- package/dist/core/transactional/types.js +1 -0
- package/dist/core/types.d.ts +90 -0
- package/dist/core/types.js +1 -0
- package/dist/core/v2/adapter.d.ts +14 -0
- package/dist/core/v2/adapter.js +118 -0
- package/dist/core/v2/containment.d.ts +19 -0
- package/dist/core/v2/containment.js +91 -0
- package/dist/core/v2/egress-classify.d.ts +7 -0
- package/dist/core/v2/egress-classify.js +216 -0
- package/dist/core/v2/fingerprint.d.ts +1 -0
- package/dist/core/v2/fingerprint.js +4 -0
- package/dist/core/v2/index.d.ts +12 -0
- package/dist/core/v2/index.js +10 -0
- package/dist/core/v2/judge-audit.d.ts +2 -0
- package/dist/core/v2/judge-audit.js +15 -0
- package/dist/core/v2/judge-factory.d.ts +25 -0
- package/dist/core/v2/judge-factory.js +75 -0
- package/dist/core/v2/judge-outbound.d.ts +12 -0
- package/dist/core/v2/judge-outbound.js +73 -0
- package/dist/core/v2/judge.d.ts +47 -0
- package/dist/core/v2/judge.js +264 -0
- package/dist/core/v2/launcher-resolve.d.ts +12 -0
- package/dist/core/v2/launcher-resolve.js +190 -0
- package/dist/core/v2/overrides.d.ts +7 -0
- package/dist/core/v2/overrides.js +37 -0
- package/dist/core/v2/parser.d.ts +21 -0
- package/dist/core/v2/parser.js +213 -0
- package/dist/core/v2/types.d.ts +67 -0
- package/dist/core/v2/types.js +1 -0
- package/dist/core/v2/verdict.d.ts +2 -0
- package/dist/core/v2/verdict.js +699 -0
- package/dist/corpus/evaluate.d.ts +24 -0
- package/dist/corpus/evaluate.js +69 -0
- package/dist/defaults.d.ts +18 -0
- package/dist/defaults.js +155 -0
- package/dist/egress-daemon.d.ts +1 -0
- package/dist/egress-daemon.js +52 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +15 -0
- package/dist/installer/bootstrap.d.ts +5 -0
- package/dist/installer/bootstrap.js +61 -0
- package/dist/installer/runtime-artifacts.d.ts +3 -0
- package/dist/installer/runtime-artifacts.js +23 -0
- package/dist/installer/scope-config.d.ts +8 -0
- package/dist/installer/scope-config.js +25 -0
- package/dist/installer.d.ts +22 -0
- package/dist/installer.js +169 -0
- package/dist/node-resolution.d.ts +8 -0
- package/dist/node-resolution.js +237 -0
- package/dist/operational-insights.d.ts +19 -0
- package/dist/operational-insights.js +24 -0
- package/dist/presets.d.ts +4 -0
- package/dist/presets.js +95 -0
- package/dist/services/egress-service.d.ts +57 -0
- package/dist/services/egress-service.js +334 -0
- package/dist/services/sandbox-service.d.ts +38 -0
- package/dist/services/sandbox-service.js +95 -0
- package/dist/templates.d.ts +7 -0
- package/dist/templates.js +56 -0
- package/dist/types.d.ts +230 -0
- package/dist/types.js +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +65 -0
- package/skills/belay/SKILL.md +52 -0
- package/skills/belay/belay-approve.md +7 -0
- package/skills/belay/belay-explain.md +11 -0
- package/skills/belay/belay-recover.md +13 -0
- package/skills/belay/belay-report.md +7 -0
- package/skills/belay/belay-status.md +9 -0
- package/skills/belay/belay-why.md +11 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { canonicalStringify, toolFingerprint } from './fingerprint.js';
|
|
3
|
+
import { matchesSensitivePath } from './glob.js';
|
|
4
|
+
import { pathWithinRoot, relativeWithinRepo } from './path-utils.js';
|
|
5
|
+
import { scrubValue } from './scrub.js';
|
|
6
|
+
import { classifyShell } from './v2/adapter.js';
|
|
7
|
+
const DEFAULT_SENSITIVE_PATHS = ['.env', '.env.*', '**/credentials/**'];
|
|
8
|
+
const FILE_WRITE_TOOL_NAMES = new Set(['write']);
|
|
9
|
+
const FILE_EDIT_TOOL_NAMES = new Set([
|
|
10
|
+
'edit',
|
|
11
|
+
'multiedit',
|
|
12
|
+
'multi_edit',
|
|
13
|
+
'patch',
|
|
14
|
+
'strreplace',
|
|
15
|
+
'str_replace',
|
|
16
|
+
]);
|
|
17
|
+
const FILE_DELETE_TOOL_NAMES = new Set(['delete']);
|
|
18
|
+
const APPLY_PATCH_TOOL_NAMES = new Set(['apply_patch', 'applypatch']);
|
|
19
|
+
function scrubPayload(value, options) {
|
|
20
|
+
return scrubValue(value, options.scrubOptions);
|
|
21
|
+
}
|
|
22
|
+
function extractFilePath(payload) {
|
|
23
|
+
const toolInput = payload.tool_input;
|
|
24
|
+
if (!toolInput || typeof toolInput !== 'object') {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const input = toolInput;
|
|
28
|
+
for (const key of ['path', 'file_path', 'target_file', 'filePath']) {
|
|
29
|
+
if (typeof input[key] === 'string') {
|
|
30
|
+
return input[key];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
function extractShellCommand(payload) {
|
|
36
|
+
const toolInput = payload.tool_input;
|
|
37
|
+
if (!toolInput || typeof toolInput !== 'object') {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const input = toolInput;
|
|
41
|
+
if (typeof input.command === 'string') {
|
|
42
|
+
return input.command;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
function extractPatch(payload) {
|
|
47
|
+
const toolInput = payload.tool_input;
|
|
48
|
+
if (!toolInput || typeof toolInput !== 'object') {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const input = toolInput;
|
|
52
|
+
for (const key of ['patch', 'input', 'text']) {
|
|
53
|
+
if (typeof input[key] === 'string' && input[key].trim()) {
|
|
54
|
+
return input[key];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
function applyPatchTargets(patch) {
|
|
60
|
+
const targets = [];
|
|
61
|
+
for (const line of patch.split('\n')) {
|
|
62
|
+
const match = line.match(/^\*\*\* (Add|Delete|Update) File: (.+)$/);
|
|
63
|
+
if (match?.[1] && match[2]) {
|
|
64
|
+
targets.push({ path: match[2], delete: match[1] === 'Delete' });
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const moveMatch = line.match(/^\*\*\* Move to: (.+)$/);
|
|
68
|
+
if (moveMatch?.[1]) {
|
|
69
|
+
targets.push({ path: moveMatch[1], delete: false });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return targets;
|
|
73
|
+
}
|
|
74
|
+
function normalizedToolName(toolName) {
|
|
75
|
+
return toolName.trim().toLowerCase();
|
|
76
|
+
}
|
|
77
|
+
export async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
78
|
+
const toolName = String(payload.tool_name ?? '');
|
|
79
|
+
const toolKind = normalizedToolName(toolName);
|
|
80
|
+
const sensitivePaths = [...DEFAULT_SENSITIVE_PATHS, ...(options.sensitivePaths ?? [])];
|
|
81
|
+
const protectedRoots = [
|
|
82
|
+
...(options.protectedArtifactRoots ?? []),
|
|
83
|
+
...(options.controlPlaneDir ? [options.controlPlaneDir] : []),
|
|
84
|
+
];
|
|
85
|
+
if (toolKind === 'shell') {
|
|
86
|
+
const command = extractShellCommand(payload);
|
|
87
|
+
if (!command) {
|
|
88
|
+
if (options.unknownLocalEffect === 'deny') {
|
|
89
|
+
return {
|
|
90
|
+
verdict: 'deny_pending_approval',
|
|
91
|
+
reason: 'tool_shell_missing_command',
|
|
92
|
+
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
93
|
+
fingerprint: toolFingerprint(toolName, scrubPayload(payload.tool_input ?? {}, options), repoRoot),
|
|
94
|
+
assessment: {
|
|
95
|
+
reversibility: 'irreversible',
|
|
96
|
+
external: false,
|
|
97
|
+
blastRadius: 'tool shell',
|
|
98
|
+
confidence: 0.85,
|
|
99
|
+
signals: ['missing_command'],
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
verdict: 'allow_flagged',
|
|
105
|
+
reason: 'tool_shell_missing_command',
|
|
106
|
+
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
107
|
+
fingerprint: toolFingerprint(toolName, scrubPayload(payload.tool_input ?? {}, options), repoRoot),
|
|
108
|
+
assessment: {
|
|
109
|
+
reversibility: 'recoverable_with_cost',
|
|
110
|
+
external: false,
|
|
111
|
+
blastRadius: 'tool shell',
|
|
112
|
+
confidence: 0.5,
|
|
113
|
+
signals: ['missing_command'],
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const shellResult = await classifyShell(command, cwd, repoRoot, config, options);
|
|
118
|
+
return {
|
|
119
|
+
...shellResult,
|
|
120
|
+
summary: command,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (FILE_WRITE_TOOL_NAMES.has(toolKind) ||
|
|
124
|
+
FILE_EDIT_TOOL_NAMES.has(toolKind) ||
|
|
125
|
+
FILE_DELETE_TOOL_NAMES.has(toolKind)) {
|
|
126
|
+
const filePath = extractFilePath(payload);
|
|
127
|
+
if (!filePath) {
|
|
128
|
+
if (options.unknownLocalEffect === 'deny') {
|
|
129
|
+
return {
|
|
130
|
+
verdict: 'deny_pending_approval',
|
|
131
|
+
reason: 'file_mutation_missing_path',
|
|
132
|
+
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
133
|
+
fingerprint: toolFingerprint(toolName, scrubPayload(payload.tool_input ?? {}, options), repoRoot),
|
|
134
|
+
assessment: {
|
|
135
|
+
reversibility: 'irreversible',
|
|
136
|
+
external: false,
|
|
137
|
+
blastRadius: 'file mutation',
|
|
138
|
+
confidence: 0.85,
|
|
139
|
+
signals: ['missing_path'],
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
verdict: 'allow_flagged',
|
|
145
|
+
reason: 'file_mutation_missing_path',
|
|
146
|
+
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
147
|
+
fingerprint: toolFingerprint(toolName, scrubPayload(payload.tool_input ?? {}, options), repoRoot),
|
|
148
|
+
assessment: {
|
|
149
|
+
reversibility: 'recoverable_with_cost',
|
|
150
|
+
external: false,
|
|
151
|
+
blastRadius: 'file mutation',
|
|
152
|
+
confidence: 0.55,
|
|
153
|
+
signals: ['missing_path'],
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const signals = [];
|
|
158
|
+
const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath);
|
|
159
|
+
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
160
|
+
if (hitsProtectedRoot) {
|
|
161
|
+
signals.push('control_plane_path');
|
|
162
|
+
return {
|
|
163
|
+
verdict: 'deny_pending_approval',
|
|
164
|
+
reason: 'control_plane_mutation',
|
|
165
|
+
summary: filePath,
|
|
166
|
+
fingerprint: toolFingerprint(toolName, { path: filePath }, repoRoot),
|
|
167
|
+
assessment: {
|
|
168
|
+
reversibility: 'irreversible',
|
|
169
|
+
external: false,
|
|
170
|
+
blastRadius: 'agent-belay control plane',
|
|
171
|
+
confidence: 0.97,
|
|
172
|
+
signals,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const relativePath = relativeWithinRepo(repoRoot, resolvedPath);
|
|
177
|
+
if (relativePath === null) {
|
|
178
|
+
signals.push('outside_repo_path');
|
|
179
|
+
return {
|
|
180
|
+
verdict: 'deny_pending_approval',
|
|
181
|
+
reason: 'outside_repo_file_mutation',
|
|
182
|
+
summary: filePath,
|
|
183
|
+
fingerprint: toolFingerprint(toolName, { path: filePath }, repoRoot),
|
|
184
|
+
assessment: {
|
|
185
|
+
reversibility: 'irreversible',
|
|
186
|
+
external: true,
|
|
187
|
+
blastRadius: 'outside the repository',
|
|
188
|
+
confidence: 0.9,
|
|
189
|
+
signals,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (matchesSensitivePath(relativePath, sensitivePaths)) {
|
|
194
|
+
signals.push('sensitive_path');
|
|
195
|
+
return {
|
|
196
|
+
verdict: 'deny_pending_approval',
|
|
197
|
+
reason: 'sensitive_file_mutation',
|
|
198
|
+
summary: filePath,
|
|
199
|
+
fingerprint: toolFingerprint(toolName, { path: filePath }, repoRoot),
|
|
200
|
+
assessment: {
|
|
201
|
+
reversibility: 'irreversible',
|
|
202
|
+
external: false,
|
|
203
|
+
blastRadius: 'sensitive repository file',
|
|
204
|
+
confidence: 0.88,
|
|
205
|
+
signals,
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
if (FILE_DELETE_TOOL_NAMES.has(toolKind)) {
|
|
210
|
+
signals.push('file_delete');
|
|
211
|
+
return {
|
|
212
|
+
verdict: 'allow_flagged',
|
|
213
|
+
reason: 'file_delete',
|
|
214
|
+
summary: filePath,
|
|
215
|
+
fingerprint: toolFingerprint(toolName, { path: filePath }, repoRoot),
|
|
216
|
+
assessment: {
|
|
217
|
+
reversibility: 'recoverable_with_cost',
|
|
218
|
+
external: false,
|
|
219
|
+
blastRadius: 'this repository',
|
|
220
|
+
confidence: 0.7,
|
|
221
|
+
signals,
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
signals.push('file_mutation');
|
|
226
|
+
return {
|
|
227
|
+
verdict: 'allow_flagged',
|
|
228
|
+
reason: 'file_mutation',
|
|
229
|
+
summary: filePath,
|
|
230
|
+
fingerprint: toolFingerprint(toolName, { path: filePath }, repoRoot),
|
|
231
|
+
assessment: {
|
|
232
|
+
reversibility: 'recoverable_with_cost',
|
|
233
|
+
external: false,
|
|
234
|
+
blastRadius: 'this repository',
|
|
235
|
+
confidence: 0.68,
|
|
236
|
+
signals,
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
if (APPLY_PATCH_TOOL_NAMES.has(toolKind)) {
|
|
241
|
+
const patch = extractPatch(payload);
|
|
242
|
+
const targets = patch ? applyPatchTargets(patch) : [];
|
|
243
|
+
if (targets.length === 0) {
|
|
244
|
+
if (options.unknownLocalEffect === 'deny') {
|
|
245
|
+
return {
|
|
246
|
+
verdict: 'deny_pending_approval',
|
|
247
|
+
reason: 'apply_patch_missing_path',
|
|
248
|
+
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
249
|
+
fingerprint: toolFingerprint(toolName, scrubPayload(payload.tool_input ?? {}, options), repoRoot),
|
|
250
|
+
assessment: {
|
|
251
|
+
reversibility: 'irreversible',
|
|
252
|
+
external: false,
|
|
253
|
+
blastRadius: 'file mutation',
|
|
254
|
+
confidence: 0.85,
|
|
255
|
+
signals: ['missing_path'],
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
verdict: 'allow_flagged',
|
|
261
|
+
reason: 'apply_patch_missing_path',
|
|
262
|
+
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
263
|
+
fingerprint: toolFingerprint(toolName, scrubPayload(payload.tool_input ?? {}, options), repoRoot),
|
|
264
|
+
assessment: {
|
|
265
|
+
reversibility: 'recoverable_with_cost',
|
|
266
|
+
external: false,
|
|
267
|
+
blastRadius: 'file mutation',
|
|
268
|
+
confidence: 0.55,
|
|
269
|
+
signals: ['missing_path'],
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
let sawDelete = false;
|
|
274
|
+
for (const target of targets) {
|
|
275
|
+
const result = await classifyToolUse({
|
|
276
|
+
tool_name: target.delete ? 'Delete' : 'Write',
|
|
277
|
+
tool_input: { path: target.path },
|
|
278
|
+
}, repoRoot, cwd, config, options);
|
|
279
|
+
if (result.verdict === 'deny_pending_approval') {
|
|
280
|
+
return result;
|
|
281
|
+
}
|
|
282
|
+
sawDelete ||= target.delete;
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
verdict: 'allow_flagged',
|
|
286
|
+
reason: sawDelete ? 'file_delete' : 'file_mutation',
|
|
287
|
+
summary: targets.map((target) => target.path).join(', '),
|
|
288
|
+
fingerprint: toolFingerprint(toolName, scrubPayload(payload.tool_input ?? {}, options), repoRoot),
|
|
289
|
+
assessment: {
|
|
290
|
+
reversibility: 'recoverable_with_cost',
|
|
291
|
+
external: false,
|
|
292
|
+
blastRadius: 'this repository',
|
|
293
|
+
confidence: sawDelete ? 0.7 : 0.68,
|
|
294
|
+
signals: [sawDelete ? 'file_delete' : 'file_mutation', 'apply_patch'],
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
verdict: 'allow',
|
|
300
|
+
reason: 'unclassified_tool',
|
|
301
|
+
summary: canonicalStringify(scrubPayload(payload.tool_input ?? {}, options)),
|
|
302
|
+
fingerprint: toolFingerprint(toolName, scrubPayload(payload.tool_input ?? {}, options), repoRoot),
|
|
303
|
+
assessment: {
|
|
304
|
+
reversibility: 'reversible',
|
|
305
|
+
external: false,
|
|
306
|
+
blastRadius: 'tool scope',
|
|
307
|
+
confidence: 0.5,
|
|
308
|
+
signals: ['unclassified_tool'],
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ConfigPresetName } from '../presets.js';
|
|
2
|
+
import type { BelayConfigV3 } from './config.js';
|
|
3
|
+
export type ConfigLayerSource = 'builtin' | 'team' | 'repo' | 'protected';
|
|
4
|
+
export interface ConfigProvenanceEntry {
|
|
5
|
+
path: string;
|
|
6
|
+
source: ConfigLayerSource;
|
|
7
|
+
}
|
|
8
|
+
export interface LayeredConfigResult {
|
|
9
|
+
config: BelayConfigV3;
|
|
10
|
+
provenance: ConfigProvenanceEntry[];
|
|
11
|
+
}
|
|
12
|
+
export interface TeamConfigFile {
|
|
13
|
+
preset?: ConfigPresetName;
|
|
14
|
+
config?: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
export declare function teamConfigPath(homedir?: () => string): string;
|
|
17
|
+
export declare function resolveLayeredConfig(params: {
|
|
18
|
+
repoConfig: unknown;
|
|
19
|
+
adapterDefaults: BelayConfigV3;
|
|
20
|
+
teamConfig?: TeamConfigFile | Record<string, unknown> | null;
|
|
21
|
+
teamConfigPath?: string;
|
|
22
|
+
repoConfigPath?: string;
|
|
23
|
+
}): LayeredConfigResult;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { applyConfigPreset } from '../presets.js';
|
|
3
|
+
import { DEFAULT_CONFIG_V3, mergeConfig } from './config.js';
|
|
4
|
+
export function teamConfigPath(homedir = () => process.env.HOME ?? process.env.USERPROFILE ?? '') {
|
|
5
|
+
const xdg = process.env.XDG_CONFIG_HOME?.trim();
|
|
6
|
+
const base = xdg || path.join(homedir(), '.config');
|
|
7
|
+
return path.join(base, 'agent-belay', 'team.config.json');
|
|
8
|
+
}
|
|
9
|
+
function applyProtectedLayer(config, builtin) {
|
|
10
|
+
const controlPlane = { ...config.controlPlane };
|
|
11
|
+
if (builtin.controlPlane.enabled && controlPlane.enabled === false) {
|
|
12
|
+
controlPlane.enabled = true;
|
|
13
|
+
}
|
|
14
|
+
if (builtin.controlPlane.integrity === 'hash-pinned' && controlPlane.integrity === 'none') {
|
|
15
|
+
controlPlane.integrity = 'hash-pinned';
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
...config,
|
|
19
|
+
controlPlane,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function asV3Layer(raw) {
|
|
23
|
+
if (!raw || typeof raw !== 'object') {
|
|
24
|
+
return { version: 3 };
|
|
25
|
+
}
|
|
26
|
+
return { version: 3, ...raw };
|
|
27
|
+
}
|
|
28
|
+
function mergeConfigLayer(base, layer) {
|
|
29
|
+
const merged = mergeConfig(layer, base);
|
|
30
|
+
if (!layer.policy) {
|
|
31
|
+
return { ...merged, policy: base.policy };
|
|
32
|
+
}
|
|
33
|
+
return merged;
|
|
34
|
+
}
|
|
35
|
+
export function resolveLayeredConfig(params) {
|
|
36
|
+
const provenance = [{ path: '(builtin)', source: 'builtin' }];
|
|
37
|
+
let config = mergeConfig({}, params.adapterDefaults);
|
|
38
|
+
if (params.teamConfig) {
|
|
39
|
+
const teamFile = params.teamConfig;
|
|
40
|
+
const teamRaw = teamFile.preset
|
|
41
|
+
? applyConfigPreset(teamFile.preset, teamFile.config ?? {})
|
|
42
|
+
: (teamFile.config ?? params.teamConfig);
|
|
43
|
+
config = mergeConfigLayer(config, asV3Layer(teamRaw));
|
|
44
|
+
provenance.push({
|
|
45
|
+
path: params.teamConfigPath ?? teamConfigPath(),
|
|
46
|
+
source: 'team',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
config = mergeConfigLayer(config, asV3Layer(params.repoConfig));
|
|
50
|
+
if (params.repoConfigPath) {
|
|
51
|
+
provenance.push({ path: params.repoConfigPath, source: 'repo' });
|
|
52
|
+
}
|
|
53
|
+
const protectedConfig = applyProtectedLayer(config, DEFAULT_CONFIG_V3);
|
|
54
|
+
if (JSON.stringify(protectedConfig) !== JSON.stringify(config)) {
|
|
55
|
+
provenance.push({ path: '(protected-layer)', source: 'protected' });
|
|
56
|
+
config = protectedConfig;
|
|
57
|
+
}
|
|
58
|
+
return { config, provenance };
|
|
59
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type { ClassifierOptions, ControlPlaneIntegrity, ScrubOptions, UnknownLocalEffectPolicy, UnparseableShellPolicy } from './types.js';
|
|
2
|
+
export type BelayMode = 'enforce' | 'audit';
|
|
3
|
+
export type { UnknownLocalEffectPolicy };
|
|
4
|
+
export interface BelayConfigV1 {
|
|
5
|
+
version: 1;
|
|
6
|
+
mode: BelayMode;
|
|
7
|
+
approvalTtlMinutes: number;
|
|
8
|
+
tokenPrefix: string;
|
|
9
|
+
gates: {
|
|
10
|
+
shell: boolean;
|
|
11
|
+
subagent: boolean;
|
|
12
|
+
};
|
|
13
|
+
audit: {
|
|
14
|
+
logPath: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export interface BelayConfigV2 {
|
|
18
|
+
version: 2;
|
|
19
|
+
mode: BelayMode;
|
|
20
|
+
approvalTtlMinutes: number;
|
|
21
|
+
tokenPrefix: string;
|
|
22
|
+
gates: {
|
|
23
|
+
shell: boolean;
|
|
24
|
+
subagent: boolean;
|
|
25
|
+
fileMutation: boolean;
|
|
26
|
+
toolShell: boolean;
|
|
27
|
+
};
|
|
28
|
+
classifier: {
|
|
29
|
+
strictChains: boolean;
|
|
30
|
+
customExternalCommands: string[];
|
|
31
|
+
customAllowCommands: string[];
|
|
32
|
+
sensitivePaths: string[];
|
|
33
|
+
};
|
|
34
|
+
audit: {
|
|
35
|
+
logPath: string;
|
|
36
|
+
includeAssessment: boolean;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export interface BelayConfidenceThresholds {
|
|
40
|
+
allow: number;
|
|
41
|
+
flag: number;
|
|
42
|
+
}
|
|
43
|
+
export interface BelayModelAssistConfig {
|
|
44
|
+
enabled: boolean;
|
|
45
|
+
model?: string;
|
|
46
|
+
timeoutMs?: number;
|
|
47
|
+
}
|
|
48
|
+
export interface BelayTransactionalConfig {
|
|
49
|
+
enabled: boolean;
|
|
50
|
+
minConfidence: number;
|
|
51
|
+
maxConfidence: number;
|
|
52
|
+
timeoutMs: number;
|
|
53
|
+
maxDeletionCount: number;
|
|
54
|
+
gates: {
|
|
55
|
+
shell: boolean;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export interface BelayPolicyConfig {
|
|
59
|
+
unknownLocalEffect: UnknownLocalEffectPolicy;
|
|
60
|
+
unparseableShell: UnparseableShellPolicy;
|
|
61
|
+
confidenceThresholds: BelayConfidenceThresholds;
|
|
62
|
+
modelAssist: BelayModelAssistConfig;
|
|
63
|
+
transactional: BelayTransactionalConfig;
|
|
64
|
+
codexUnmappedTool?: 'allow' | 'deny';
|
|
65
|
+
/** R-V2: silent-pass rate below this triggers fence-drift warning (default 0.5). */
|
|
66
|
+
fenceWarnThreshold: number;
|
|
67
|
+
}
|
|
68
|
+
export interface BelayOverridesConfig {
|
|
69
|
+
allow: string[];
|
|
70
|
+
external: string[];
|
|
71
|
+
}
|
|
72
|
+
export interface BelayRedactionConfig {
|
|
73
|
+
maskApprovalIds: boolean;
|
|
74
|
+
maskBearerTokens: boolean;
|
|
75
|
+
maskAuthHeaders: boolean;
|
|
76
|
+
maskKeyValueSecrets: boolean;
|
|
77
|
+
maskHighEntropyStrings: boolean;
|
|
78
|
+
}
|
|
79
|
+
export type JudgeProvider = 'ollama' | 'openai-compatible';
|
|
80
|
+
export interface BelayJudgeConfig {
|
|
81
|
+
provider: JudgeProvider;
|
|
82
|
+
model: string;
|
|
83
|
+
timeoutMs: number;
|
|
84
|
+
endpoint: string | null;
|
|
85
|
+
keepAlive: string | null;
|
|
86
|
+
}
|
|
87
|
+
export declare const DEFAULT_JUDGE_LOCAL_OLLAMA: BelayJudgeConfig;
|
|
88
|
+
export declare const DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE: BelayJudgeConfig;
|
|
89
|
+
/** @deprecated Use DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE */
|
|
90
|
+
export declare const DEFAULT_JUDGE_CURSOR_COMPOSER: BelayJudgeConfig;
|
|
91
|
+
export type ControlPlaneIsolationMode = 'none' | 'read-only-mount' | 'separate-user';
|
|
92
|
+
export interface BelayControlPlaneIsolationConfig {
|
|
93
|
+
mode: ControlPlaneIsolationMode;
|
|
94
|
+
expectedOwnerUid?: number;
|
|
95
|
+
verifyAgentWritable: boolean;
|
|
96
|
+
}
|
|
97
|
+
export interface BelayControlPlaneConfig {
|
|
98
|
+
enabled: boolean;
|
|
99
|
+
configDir: string | null;
|
|
100
|
+
integrity: ControlPlaneIntegrity;
|
|
101
|
+
isolation: BelayControlPlaneIsolationConfig;
|
|
102
|
+
}
|
|
103
|
+
export type SandboxRuntime = 'none' | 'cursor-sandbox' | 'container' | 'seatbelt' | 'landlock';
|
|
104
|
+
export interface BelaySandboxConfig {
|
|
105
|
+
enabled: boolean;
|
|
106
|
+
runtime: SandboxRuntime;
|
|
107
|
+
denyNetworkByDefault: boolean;
|
|
108
|
+
}
|
|
109
|
+
export interface BelayClassifierConfig {
|
|
110
|
+
strictChains: boolean;
|
|
111
|
+
sensitivePaths: string[];
|
|
112
|
+
}
|
|
113
|
+
export interface BelayNotificationsConfig {
|
|
114
|
+
webhookUrl?: string;
|
|
115
|
+
commandHook?: string;
|
|
116
|
+
}
|
|
117
|
+
export interface BelayApprovalSigningConfig {
|
|
118
|
+
/** When true, out-of-band approvals must present a signed token. */
|
|
119
|
+
required: boolean;
|
|
120
|
+
}
|
|
121
|
+
export interface BelayEgressConfig {
|
|
122
|
+
enabled: boolean;
|
|
123
|
+
listenHost: string;
|
|
124
|
+
listenPort: number;
|
|
125
|
+
/** When true with egress enabled, L3 external command lists become hints only. */
|
|
126
|
+
demoteL3External: boolean;
|
|
127
|
+
}
|
|
128
|
+
export interface BelayConfigV4 {
|
|
129
|
+
version: 4;
|
|
130
|
+
adapter?: 'cursor' | 'claude' | 'codex';
|
|
131
|
+
/** Where hooks/runtime/skill artifacts are installed. Defaults to project. */
|
|
132
|
+
installScope?: 'project' | 'global';
|
|
133
|
+
mode: BelayMode;
|
|
134
|
+
approvalTtlMinutes: number;
|
|
135
|
+
tokenPrefix: string;
|
|
136
|
+
gates: BelayConfigV2['gates'];
|
|
137
|
+
classifier: BelayClassifierConfig;
|
|
138
|
+
policy: BelayPolicyConfig;
|
|
139
|
+
overrides: BelayOverridesConfig;
|
|
140
|
+
redaction: BelayRedactionConfig;
|
|
141
|
+
controlPlane: BelayControlPlaneConfig;
|
|
142
|
+
notifications: BelayNotificationsConfig;
|
|
143
|
+
approvalSigning: BelayApprovalSigningConfig;
|
|
144
|
+
egress: BelayEgressConfig;
|
|
145
|
+
sandbox: BelaySandboxConfig;
|
|
146
|
+
audit: BelayConfigV2['audit'];
|
|
147
|
+
judge: BelayJudgeConfig;
|
|
148
|
+
}
|
|
149
|
+
/** @deprecated Use BelayConfigV4 */
|
|
150
|
+
export type BelayConfigV3 = BelayConfigV4;
|
|
151
|
+
export type BelayConfig = BelayConfigV4;
|
|
152
|
+
/** @deprecated Use DEFAULT_SILENT_PASS_THRESHOLD from audit-summary.js */
|
|
153
|
+
export declare const DEFAULT_FENCE_WARN_THRESHOLD = 0.5;
|
|
154
|
+
export declare const DEFAULT_CONFIDENCE_THRESHOLDS: BelayConfidenceThresholds;
|
|
155
|
+
export declare const DEFAULT_MODEL_ASSIST: BelayModelAssistConfig;
|
|
156
|
+
export declare const DEFAULT_TRANSACTIONAL_V3: BelayTransactionalConfig;
|
|
157
|
+
export declare const LEGACY_POLICY_V3: BelayPolicyConfig;
|
|
158
|
+
/** Fresh v0.4+ install defaults (fail-closed). */
|
|
159
|
+
export declare const DEFAULT_POLICY_V3: BelayPolicyConfig;
|
|
160
|
+
export declare const DEFAULT_OVERRIDES_V3: BelayOverridesConfig;
|
|
161
|
+
export declare const DEFAULT_REDACTION_V3: BelayRedactionConfig;
|
|
162
|
+
export declare const DEFAULT_CONTROL_PLANE_ISOLATION_V3: BelayControlPlaneIsolationConfig;
|
|
163
|
+
export declare const LEGACY_CONTROL_PLANE_V3: BelayControlPlaneConfig;
|
|
164
|
+
export declare const DEFAULT_CONTROL_PLANE_V3: BelayControlPlaneConfig;
|
|
165
|
+
export declare const DEFAULT_SANDBOX_V3: BelaySandboxConfig;
|
|
166
|
+
export declare const DEFAULT_NOTIFICATIONS_V3: BelayNotificationsConfig;
|
|
167
|
+
export declare const DEFAULT_APPROVAL_SIGNING_V3: BelayApprovalSigningConfig;
|
|
168
|
+
export declare const DEFAULT_EGRESS_V3: BelayEgressConfig;
|
|
169
|
+
export declare function normalizeEgressListenHost(host: string): string;
|
|
170
|
+
export declare const DEFAULT_CONFIG_V2: BelayConfigV2;
|
|
171
|
+
export declare const DEFAULT_CONFIG_V4: BelayConfigV4;
|
|
172
|
+
/** @deprecated Use DEFAULT_CONFIG_V4 */
|
|
173
|
+
export declare const DEFAULT_CONFIG_V3: BelayConfigV4;
|
|
174
|
+
export declare function mapLegacyClassifierToOverrides(classifier: {
|
|
175
|
+
customAllowCommands?: string[];
|
|
176
|
+
customExternalCommands?: string[];
|
|
177
|
+
}): BelayOverridesConfig;
|
|
178
|
+
export declare function migrateV2ToV3(v2: BelayConfigV2, rawOverrides?: Partial<BelayOverridesConfig>): BelayConfigV4;
|
|
179
|
+
export declare function isConfigV1(value: unknown): value is BelayConfigV1;
|
|
180
|
+
export declare function isConfigV2(value: unknown): value is BelayConfigV2;
|
|
181
|
+
export declare function isConfigV3(value: unknown): value is BelayConfigV4;
|
|
182
|
+
export declare function isConfigV4(value: unknown): value is BelayConfigV4;
|
|
183
|
+
export declare function normalizeJudgeProvider(provider: string | undefined): 'ollama' | 'openai-compatible';
|
|
184
|
+
export declare function normalizeJudgeConfig(judge: BelayJudgeConfig): BelayJudgeConfig;
|
|
185
|
+
export declare function migrateV3ToV4(v3: BelayConfigV4, raw?: RawConfigInput): BelayConfigV4;
|
|
186
|
+
type RawConfigInput = Partial<{
|
|
187
|
+
version: number;
|
|
188
|
+
judge: Partial<BelayJudgeConfig>;
|
|
189
|
+
mode: BelayMode;
|
|
190
|
+
approvalTtlMinutes: number;
|
|
191
|
+
tokenPrefix: string;
|
|
192
|
+
gates: Partial<BelayConfigV2['gates']>;
|
|
193
|
+
classifier: Partial<BelayConfigV2['classifier']> & Partial<BelayClassifierConfig>;
|
|
194
|
+
policy: Partial<BelayPolicyConfig>;
|
|
195
|
+
overrides: Partial<BelayOverridesConfig>;
|
|
196
|
+
redaction: Partial<BelayRedactionConfig>;
|
|
197
|
+
controlPlane: Partial<BelayControlPlaneConfig>;
|
|
198
|
+
notifications: Partial<BelayNotificationsConfig>;
|
|
199
|
+
approvalSigning: Partial<BelayApprovalSigningConfig>;
|
|
200
|
+
egress: Partial<BelayEgressConfig>;
|
|
201
|
+
sandbox: Partial<BelaySandboxConfig>;
|
|
202
|
+
audit: Partial<BelayConfigV2['audit']>;
|
|
203
|
+
installScope: 'project' | 'global';
|
|
204
|
+
}>;
|
|
205
|
+
export declare function migrateConfig(loaded: unknown): BelayConfigV4;
|
|
206
|
+
export declare function normalizeConfigV2(config: BelayConfigV2): BelayConfigV2;
|
|
207
|
+
export declare function normalizeConfig(config: BelayConfigV4): BelayConfigV4;
|
|
208
|
+
export declare function normalizeConfig(config: BelayConfigV2): BelayConfigV2;
|
|
209
|
+
export declare function isFreshConfigInput(loaded: unknown): boolean;
|
|
210
|
+
export declare function mergeConfig(existing: unknown, defaults?: BelayConfigV4): BelayConfigV4;
|
|
211
|
+
export declare function scrubOptionsFromConfig(config: BelayConfigV4): ScrubOptions;
|
|
212
|
+
export declare function classifierOptionsFromConfig(config: BelayConfigV4): ClassifierOptions;
|
|
213
|
+
export declare function defaultControlPlaneDir(env?: NodeJS.ProcessEnv, homedir?: () => string): string;
|
|
214
|
+
export declare function resolveControlPlaneDir(config: BelayConfigV4): string;
|
|
215
|
+
/** Control-plane directory regardless of enabled flag (for orphan migration). */
|
|
216
|
+
export declare function configuredControlPlaneDir(config: BelayConfigV4): string;
|
|
217
|
+
export declare function belayStateDir(config: BelayConfigV4, repoLocalStateDir: string): string;
|
|
218
|
+
export declare function pendingApprovalsFile(config: BelayConfigV4, repoLocalStateDir: string): string;
|
|
219
|
+
export declare function approvedApprovalsFile(config: BelayConfigV4, repoLocalStateDir: string): string;
|