@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
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { matchesSensitivePath } from '../glob.js';
|
|
4
|
+
import { canonicalPath, pathWithinRoot, resolveWorkspaceRootMatch } from '../path-utils.js';
|
|
5
|
+
import { BOUNDARY_GRANT_ISSUER_CONTAINER, isPathWithinBoundaryMount, materializeContainerBoundaryGrant, } from './boundary-grant-materialize.js';
|
|
6
|
+
import { boundaryVerifiedAllowEnabled } from './boundary-profile.js';
|
|
7
|
+
import { isGrantScopeTooBroad } from './grant.js';
|
|
8
|
+
import { broadGrantTargetsRequest, grantMatchesRequest } from './grant-match.js';
|
|
9
|
+
import { CAPABILITY_REQUEST_VERSION, } from './request.js';
|
|
10
|
+
function enrichAuthWithMaterializedGrants(request, config, auth) {
|
|
11
|
+
if (!auth?.attestation || !boundaryVerifiedAllowEnabled(auth.attestation)) {
|
|
12
|
+
return auth;
|
|
13
|
+
}
|
|
14
|
+
const materialized = materializeContainerBoundaryGrant(request, {
|
|
15
|
+
attestation: auth.attestation,
|
|
16
|
+
mountRoot: request.context.cwd,
|
|
17
|
+
egressProxyActive: auth.egressProxyActive === true,
|
|
18
|
+
existingGrants: auth.grants,
|
|
19
|
+
sensitivePaths: auth.sensitivePaths ?? config.classifier.sensitivePaths,
|
|
20
|
+
});
|
|
21
|
+
if (!materialized) {
|
|
22
|
+
return auth;
|
|
23
|
+
}
|
|
24
|
+
return { ...auth, grants: [...(auth.grants ?? []), materialized] };
|
|
25
|
+
}
|
|
26
|
+
function buildAuthorizationContext(config, trustedWorkspaceRoots, auth) {
|
|
27
|
+
return {
|
|
28
|
+
config,
|
|
29
|
+
grants: auth?.grants,
|
|
30
|
+
attestation: auth?.attestation ?? null,
|
|
31
|
+
trustedWorkspaceRoots,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function buildSubagentCapabilityRequest(analysis) {
|
|
35
|
+
return {
|
|
36
|
+
version: CAPABILITY_REQUEST_VERSION,
|
|
37
|
+
principal: {
|
|
38
|
+
adapter: analysis.adapter,
|
|
39
|
+
repoRoot: analysis.repoRoot,
|
|
40
|
+
sessionHash: hashSession(`${analysis.repoRoot}:${analysis.cwd}`),
|
|
41
|
+
},
|
|
42
|
+
action: 'process.exec',
|
|
43
|
+
resource: { kind: 'executable', command: analysis.subagentType },
|
|
44
|
+
context: {
|
|
45
|
+
cwd: analysis.cwd,
|
|
46
|
+
inputFingerprint: analysis.inputFingerprint,
|
|
47
|
+
hookKind: 'subagent',
|
|
48
|
+
analysisBasis: [`subagent:${analysis.subagentType}`],
|
|
49
|
+
},
|
|
50
|
+
evidence: {
|
|
51
|
+
level: 'possible',
|
|
52
|
+
signals: [...analysis.signals],
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function evaluateSubagentPolicy(analysis, config, auth) {
|
|
57
|
+
const request = buildSubagentCapabilityRequest(analysis);
|
|
58
|
+
const enriched = enrichAuthWithMaterializedGrants(request, config, auth);
|
|
59
|
+
const decision = getDefaultPolicyEngine().evaluate(request, buildAuthorizationContext(config, undefined, enriched));
|
|
60
|
+
return { request, decision };
|
|
61
|
+
}
|
|
62
|
+
function hashSession(value) {
|
|
63
|
+
return createHash('sha256').update(value).digest('hex').slice(0, 16);
|
|
64
|
+
}
|
|
65
|
+
function resolveCapabilityPath(targetPath, cwd) {
|
|
66
|
+
const joined = path.isAbsolute(targetPath) ? targetPath : path.join(cwd, targetPath);
|
|
67
|
+
return canonicalPath(joined);
|
|
68
|
+
}
|
|
69
|
+
function evidenceLevelForOpacity(opacity) {
|
|
70
|
+
if (opacity === 'transparent' || opacity === 'recursive') {
|
|
71
|
+
return 'certain';
|
|
72
|
+
}
|
|
73
|
+
if (opacity === 'opaque') {
|
|
74
|
+
return 'possible';
|
|
75
|
+
}
|
|
76
|
+
return 'indeterminate';
|
|
77
|
+
}
|
|
78
|
+
function isGitRefWrite(analysis) {
|
|
79
|
+
if (analysis.segmentHead !== 'git') {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
return analysis.signals.includes('git.push');
|
|
83
|
+
}
|
|
84
|
+
function actionForShellAnalysis(analysis) {
|
|
85
|
+
if (isGitRefWrite(analysis)) {
|
|
86
|
+
return 'git.ref.write';
|
|
87
|
+
}
|
|
88
|
+
if (analysis.effect === 'remote_mutation' ||
|
|
89
|
+
analysis.egressClass === 'ambiguous' ||
|
|
90
|
+
analysis.egressClass === 'read' ||
|
|
91
|
+
analysis.egressClass === 'destructive') {
|
|
92
|
+
return 'network.connect';
|
|
93
|
+
}
|
|
94
|
+
if (analysis.opacity === 'unparseable' || analysis.effect === 'unknown') {
|
|
95
|
+
return 'indeterminate';
|
|
96
|
+
}
|
|
97
|
+
if (analysis.effect === 'read_only') {
|
|
98
|
+
return 'fs.read';
|
|
99
|
+
}
|
|
100
|
+
if (analysis.location === 'external') {
|
|
101
|
+
return 'network.connect';
|
|
102
|
+
}
|
|
103
|
+
if (analysis.effect === 'local_mutation') {
|
|
104
|
+
return 'fs.write';
|
|
105
|
+
}
|
|
106
|
+
return 'indeterminate';
|
|
107
|
+
}
|
|
108
|
+
function resourcePathForShellAnalysis(analysis) {
|
|
109
|
+
const targets = analysis.resolvedPathTargets && analysis.resolvedPathTargets.length > 0
|
|
110
|
+
? analysis.resolvedPathTargets
|
|
111
|
+
: analysis.pathArgs;
|
|
112
|
+
if (targets.length === 0) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
const repoRoot = canonicalPath(analysis.repoRoot);
|
|
116
|
+
const resolved = targets.map((target) => analysis.resolvedPathTargets?.length
|
|
117
|
+
? canonicalPath(target)
|
|
118
|
+
: resolveCapabilityPath(target, analysis.cwd));
|
|
119
|
+
if (analysis.effect === 'local_mutation') {
|
|
120
|
+
const outside = resolved.find((candidate) => !pathWithinRoot(repoRoot, candidate));
|
|
121
|
+
return outside ?? resolved[resolved.length - 1];
|
|
122
|
+
}
|
|
123
|
+
return resolved[0];
|
|
124
|
+
}
|
|
125
|
+
function resourceForShellAnalysis(analysis) {
|
|
126
|
+
if (isGitRefWrite(analysis)) {
|
|
127
|
+
return { kind: 'git-ref', ref: 'push' };
|
|
128
|
+
}
|
|
129
|
+
if (analysis.egressClass === 'ambiguous' ||
|
|
130
|
+
analysis.egressClass === 'read' ||
|
|
131
|
+
analysis.egressClass === 'destructive' ||
|
|
132
|
+
analysis.location === 'external') {
|
|
133
|
+
return { kind: 'network', host: '*', protocol: 'unknown' };
|
|
134
|
+
}
|
|
135
|
+
const resourcePath = resourcePathForShellAnalysis(analysis);
|
|
136
|
+
if (resourcePath) {
|
|
137
|
+
return { kind: 'path', path: resourcePath };
|
|
138
|
+
}
|
|
139
|
+
return { kind: 'executable', command: analysis.segmentHead };
|
|
140
|
+
}
|
|
141
|
+
export function buildShellCapabilityRequest(analysis) {
|
|
142
|
+
return {
|
|
143
|
+
version: CAPABILITY_REQUEST_VERSION,
|
|
144
|
+
principal: {
|
|
145
|
+
adapter: analysis.adapter,
|
|
146
|
+
repoRoot: analysis.repoRoot,
|
|
147
|
+
sessionHash: hashSession(`${analysis.repoRoot}:${analysis.cwd}`),
|
|
148
|
+
},
|
|
149
|
+
action: actionForShellAnalysis(analysis),
|
|
150
|
+
resource: resourceForShellAnalysis(analysis),
|
|
151
|
+
context: {
|
|
152
|
+
cwd: analysis.cwd,
|
|
153
|
+
inputFingerprint: analysis.inputFingerprint,
|
|
154
|
+
hookKind: analysis.hookKind,
|
|
155
|
+
analysisBasis: [
|
|
156
|
+
`segment:${analysis.segmentHead}`,
|
|
157
|
+
`effect:${analysis.effect}`,
|
|
158
|
+
`location:${analysis.location}`,
|
|
159
|
+
`opacity:${analysis.opacity}`,
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
evidence: {
|
|
163
|
+
level: evidenceLevelForOpacity(analysis.opacity),
|
|
164
|
+
signals: [...analysis.signals],
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function actionForFileMutation(analysis) {
|
|
169
|
+
if (analysis.locationLabel === 'control_plane') {
|
|
170
|
+
return 'control_plane.write';
|
|
171
|
+
}
|
|
172
|
+
if (analysis.locationLabel === 'sensitive_path') {
|
|
173
|
+
return 'fs.write';
|
|
174
|
+
}
|
|
175
|
+
if (analysis.isDelete) {
|
|
176
|
+
return 'fs.write';
|
|
177
|
+
}
|
|
178
|
+
return 'fs.write';
|
|
179
|
+
}
|
|
180
|
+
export function buildFileMutationCapabilityRequest(analysis) {
|
|
181
|
+
return {
|
|
182
|
+
version: CAPABILITY_REQUEST_VERSION,
|
|
183
|
+
principal: {
|
|
184
|
+
adapter: analysis.adapter,
|
|
185
|
+
repoRoot: analysis.repoRoot,
|
|
186
|
+
sessionHash: hashSession(`${analysis.repoRoot}:${analysis.cwd}`),
|
|
187
|
+
},
|
|
188
|
+
action: actionForFileMutation(analysis),
|
|
189
|
+
resource: { kind: 'path', path: analysis.resolvedPath },
|
|
190
|
+
context: {
|
|
191
|
+
cwd: analysis.cwd,
|
|
192
|
+
inputFingerprint: analysis.inputFingerprint,
|
|
193
|
+
hookKind: analysis.hookKind,
|
|
194
|
+
analysisBasis: [
|
|
195
|
+
`tool:${analysis.toolKind}`,
|
|
196
|
+
`location:${analysis.locationLabel}`,
|
|
197
|
+
analysis.isDelete ? 'delete' : 'write',
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
evidence: {
|
|
201
|
+
level: analysis.locationLabel === 'repo_local' ? 'certain' : 'possible',
|
|
202
|
+
signals: [...analysis.signals],
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function findFreshGrant(request, grants) {
|
|
207
|
+
if (!grants?.length) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
const now = Date.now();
|
|
211
|
+
for (const grant of grants) {
|
|
212
|
+
const expires = Date.parse(grant.expiresAt);
|
|
213
|
+
if (Number.isFinite(expires) && expires > now && grantMatchesRequest(grant, request)) {
|
|
214
|
+
return grant;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
function hasFreshGrant(request, grants) {
|
|
220
|
+
return findFreshGrant(request, grants) !== null;
|
|
221
|
+
}
|
|
222
|
+
function grantDecisionSignals(request, grant) {
|
|
223
|
+
const signals = [...request.evidence.signals, 'capability_grant'];
|
|
224
|
+
if (grant.issuer === BOUNDARY_GRANT_ISSUER_CONTAINER) {
|
|
225
|
+
signals.push('boundary_materialized_grant');
|
|
226
|
+
}
|
|
227
|
+
return signals;
|
|
228
|
+
}
|
|
229
|
+
function shellLocationFromRequest(request) {
|
|
230
|
+
const entry = request.context.analysisBasis.find((basis) => basis.startsWith('location:'));
|
|
231
|
+
return entry?.slice('location:'.length) ?? null;
|
|
232
|
+
}
|
|
233
|
+
function isRepoLocalShellLocation(request) {
|
|
234
|
+
return shellLocationFromRequest(request) === 'repo_local';
|
|
235
|
+
}
|
|
236
|
+
function isRepoLocalRoutineWrite(request, sensitivePaths) {
|
|
237
|
+
if (!isRepoLocalShellLocation(request)) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
if (request.action !== 'fs.write' && request.action !== 'fs.read') {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
if (request.resource.kind !== 'path') {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
const resolved = resolveCapabilityPath(request.resource.path, request.context.cwd);
|
|
247
|
+
const repoRoot = canonicalPath(request.principal.repoRoot);
|
|
248
|
+
if (!pathWithinRoot(repoRoot, resolved)) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
const relative = resolved.slice(repoRoot.length).replace(/^[/\\]/, '');
|
|
252
|
+
return !matchesSensitivePath(relative, sensitivePaths);
|
|
253
|
+
}
|
|
254
|
+
function isTrustedWorkspaceWrite(request, trustedWorkspaceRoots) {
|
|
255
|
+
if (!trustedWorkspaceRoots?.length || request.resource.kind !== 'path') {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
const match = resolveWorkspaceRootMatch(request.principal.repoRoot, trustedWorkspaceRoots, request.resource.path);
|
|
259
|
+
return match?.kind === 'trusted';
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* boundary.verified widens only when builtin already allows, or a boundary-materialized
|
|
263
|
+
* grant is present for an approved high-risk action (network via egress chokepoint).
|
|
264
|
+
*/
|
|
265
|
+
function verifiedBoundaryAllows(request, context) {
|
|
266
|
+
if (!boundaryVerifiedAllowEnabled(context.attestation)) {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
if (request.evidence.level !== 'certain') {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
const builtin = builtInRule(request, context);
|
|
273
|
+
if (builtin?.outcome === 'allow') {
|
|
274
|
+
return isPathWithinBoundaryMount(request);
|
|
275
|
+
}
|
|
276
|
+
if (builtin?.outcome === 'deny') {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
return hasFreshGrant(request, context.grants?.filter((grant) => grant.issuer === BOUNDARY_GRANT_ISSUER_CONTAINER));
|
|
280
|
+
}
|
|
281
|
+
function builtInRule(request, context) {
|
|
282
|
+
const trustedWorkspaceRoots = context.trustedWorkspaceRoots;
|
|
283
|
+
const sensitivePaths = context.config.classifier.sensitivePaths;
|
|
284
|
+
if (request.action === 'control_plane.write') {
|
|
285
|
+
return {
|
|
286
|
+
outcome: 'require_approval',
|
|
287
|
+
reason: 'control_plane_mutation',
|
|
288
|
+
signals: [...request.evidence.signals, 'control_plane_path'],
|
|
289
|
+
matchedRule: 'builtin.control_plane',
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
if (request.action === 'process.exec' && request.context.hookKind === 'subagent') {
|
|
293
|
+
return {
|
|
294
|
+
outcome: 'allow',
|
|
295
|
+
reason: 'subagent_review',
|
|
296
|
+
signals: [...request.evidence.signals],
|
|
297
|
+
matchedRule: 'builtin.subagent',
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
if (request.action === 'secret.read' || request.action === 'git.ref.write') {
|
|
301
|
+
return {
|
|
302
|
+
outcome: 'require_approval',
|
|
303
|
+
reason: 'high_stakes_path',
|
|
304
|
+
signals: [...request.evidence.signals, 'secret_path'],
|
|
305
|
+
matchedRule: 'builtin.secret',
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
if (request.action === 'network.connect') {
|
|
309
|
+
return {
|
|
310
|
+
outcome: 'require_approval',
|
|
311
|
+
reason: 'external_effect',
|
|
312
|
+
signals: [...request.evidence.signals, 'network_connect'],
|
|
313
|
+
matchedRule: 'builtin.network',
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
if (request.action === 'indeterminate' || request.evidence.level === 'indeterminate') {
|
|
317
|
+
return {
|
|
318
|
+
outcome: 'require_approval',
|
|
319
|
+
reason: 'indeterminate_effect',
|
|
320
|
+
signals: [...request.evidence.signals, 'indeterminate'],
|
|
321
|
+
matchedRule: 'builtin.indeterminate',
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (request.resource.kind === 'path' && sensitivePaths?.length) {
|
|
325
|
+
const repoRoot = canonicalPath(request.principal.repoRoot);
|
|
326
|
+
const resolved = resolveCapabilityPath(request.resource.path, request.context.cwd);
|
|
327
|
+
if (pathWithinRoot(repoRoot, resolved)) {
|
|
328
|
+
const relative = resolved.slice(repoRoot.length).replace(/^[/\\]/, '');
|
|
329
|
+
if (matchesSensitivePath(relative, sensitivePaths)) {
|
|
330
|
+
return {
|
|
331
|
+
outcome: 'require_approval',
|
|
332
|
+
reason: 'high_stakes_path',
|
|
333
|
+
signals: [...request.evidence.signals, 'sensitive_path'],
|
|
334
|
+
matchedRule: 'builtin.sensitive_path',
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (request.resource.kind === 'path') {
|
|
340
|
+
const repoRoot = canonicalPath(request.principal.repoRoot);
|
|
341
|
+
const resolved = resolveCapabilityPath(request.resource.path, request.context.cwd);
|
|
342
|
+
const insideRepo = pathWithinRoot(repoRoot, resolved);
|
|
343
|
+
if (!insideRepo && !isTrustedWorkspaceWrite(request, trustedWorkspaceRoots)) {
|
|
344
|
+
return {
|
|
345
|
+
outcome: 'require_approval',
|
|
346
|
+
reason: 'outside_repo_mutation',
|
|
347
|
+
signals: [...request.evidence.signals, 'outside_repo_path'],
|
|
348
|
+
matchedRule: 'builtin.outside_repo',
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (request.action === 'fs.read' || request.action === 'fs.write') {
|
|
353
|
+
if (request.action === 'fs.read' &&
|
|
354
|
+
request.resource.kind === 'executable' &&
|
|
355
|
+
isRepoLocalShellLocation(request)) {
|
|
356
|
+
return {
|
|
357
|
+
outcome: 'allow',
|
|
358
|
+
reason: 'read_only',
|
|
359
|
+
signals: [...request.evidence.signals],
|
|
360
|
+
matchedRule: 'builtin.repo_local',
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
if (isRepoLocalRoutineWrite(request, sensitivePaths)) {
|
|
364
|
+
return {
|
|
365
|
+
outcome: 'allow',
|
|
366
|
+
reason: request.action === 'fs.read' ? 'read_only' : 'repo_local_mutation',
|
|
367
|
+
signals: [...request.evidence.signals],
|
|
368
|
+
matchedRule: 'builtin.repo_local',
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
if (isTrustedWorkspaceWrite(request, trustedWorkspaceRoots)) {
|
|
372
|
+
return {
|
|
373
|
+
outcome: 'allow',
|
|
374
|
+
reason: 'trusted_workspace_root',
|
|
375
|
+
signals: [...request.evidence.signals, 'trusted_workspace_root'],
|
|
376
|
+
matchedRule: 'builtin.trusted_workspace',
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (request.evidence.signals.includes('unparseable_shell')) {
|
|
381
|
+
const deny = context.config.policy.unparseableShell === 'deny';
|
|
382
|
+
return {
|
|
383
|
+
outcome: deny ? 'require_approval' : 'allow',
|
|
384
|
+
reason: 'unparseable_shell',
|
|
385
|
+
signals: [...request.evidence.signals],
|
|
386
|
+
matchedRule: deny ? 'builtin.unparseable' : 'builtin.unparseable_allow_flagged',
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
if (request.evidence.signals.includes('opaque_execution')) {
|
|
390
|
+
return {
|
|
391
|
+
outcome: 'require_approval',
|
|
392
|
+
reason: 'opaque_execution',
|
|
393
|
+
signals: [...request.evidence.signals],
|
|
394
|
+
matchedRule: 'builtin.opaque',
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
export function createTypeScriptPolicyEngine() {
|
|
400
|
+
return {
|
|
401
|
+
evaluate(request, context) {
|
|
402
|
+
if (request.evidence.signals.includes('forged_grant')) {
|
|
403
|
+
return {
|
|
404
|
+
outcome: 'deny',
|
|
405
|
+
reason: 'grant_forgery',
|
|
406
|
+
signals: [...request.evidence.signals, 'grant_forgery'],
|
|
407
|
+
matchedRule: 'forbid.grant_forgery',
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
const grants = context.grants;
|
|
411
|
+
if (grants?.some((grant) => isGrantScopeTooBroad(grant) && broadGrantTargetsRequest(grant, request))) {
|
|
412
|
+
return {
|
|
413
|
+
outcome: 'deny',
|
|
414
|
+
reason: 'grant_scope_too_broad',
|
|
415
|
+
signals: [...request.evidence.signals, 'grant_scope_too_broad'],
|
|
416
|
+
matchedRule: 'forbid.broad_grant',
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
const matchedGrant = findFreshGrant(request, grants);
|
|
420
|
+
if (matchedGrant) {
|
|
421
|
+
return {
|
|
422
|
+
outcome: 'allow',
|
|
423
|
+
reason: 'capability_grant',
|
|
424
|
+
signals: grantDecisionSignals(request, matchedGrant),
|
|
425
|
+
matchedRule: 'grant.exact',
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
if (verifiedBoundaryAllows(request, context)) {
|
|
429
|
+
return {
|
|
430
|
+
outcome: 'allow',
|
|
431
|
+
reason: 'verified_boundary',
|
|
432
|
+
signals: [...request.evidence.signals, 'verified_boundary'],
|
|
433
|
+
matchedRule: 'boundary.verified',
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
const builtin = builtInRule(request, context);
|
|
437
|
+
if (builtin) {
|
|
438
|
+
return builtin;
|
|
439
|
+
}
|
|
440
|
+
return {
|
|
441
|
+
outcome: 'require_approval',
|
|
442
|
+
reason: 'policy_default',
|
|
443
|
+
signals: [...request.evidence.signals, 'default_deny'],
|
|
444
|
+
matchedRule: 'default.require_approval',
|
|
445
|
+
};
|
|
446
|
+
},
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
let defaultPolicyEngine = null;
|
|
450
|
+
export function getDefaultPolicyEngine() {
|
|
451
|
+
if (!defaultPolicyEngine) {
|
|
452
|
+
defaultPolicyEngine = createTypeScriptPolicyEngine();
|
|
453
|
+
}
|
|
454
|
+
return defaultPolicyEngine;
|
|
455
|
+
}
|
|
456
|
+
export function policyDecisionRequiresAsk(decision) {
|
|
457
|
+
return decision.outcome === 'require_approval' || decision.outcome === 'deny';
|
|
458
|
+
}
|
|
459
|
+
export function evaluateShellPolicy(analysis, config, auth) {
|
|
460
|
+
const request = buildShellCapabilityRequest(analysis);
|
|
461
|
+
const enriched = enrichAuthWithMaterializedGrants(request, config, {
|
|
462
|
+
...auth,
|
|
463
|
+
sensitivePaths: auth?.sensitivePaths ?? analysis.sensitivePaths,
|
|
464
|
+
});
|
|
465
|
+
const decision = getDefaultPolicyEngine().evaluate(request, buildAuthorizationContext(config, analysis.trustedWorkspaceRoots, enriched));
|
|
466
|
+
return { request, decision };
|
|
467
|
+
}
|
|
468
|
+
export function evaluateFileMutationPolicy(analysis, config, auth) {
|
|
469
|
+
const request = buildFileMutationCapabilityRequest(analysis);
|
|
470
|
+
const enriched = enrichAuthWithMaterializedGrants(request, config, {
|
|
471
|
+
...auth,
|
|
472
|
+
sensitivePaths: auth?.sensitivePaths ?? analysis.sensitivePaths,
|
|
473
|
+
});
|
|
474
|
+
const decision = getDefaultPolicyEngine().evaluate(request, buildAuthorizationContext(config, analysis.trustedWorkspaceRoots, enriched));
|
|
475
|
+
return { request, decision };
|
|
476
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BelayConfigV4 } from '../config.js';
|
|
2
|
+
import type { BoundaryAttestation } from './attestation.js';
|
|
3
|
+
import type { CapabilityGrantV1 } from './grant.js';
|
|
4
|
+
import type { CapabilityRequestV1 } from './request.js';
|
|
5
|
+
export type PolicyOutcome = 'allow' | 'require_approval' | 'deny';
|
|
6
|
+
export interface PolicyDecision {
|
|
7
|
+
outcome: PolicyOutcome;
|
|
8
|
+
reason: string;
|
|
9
|
+
signals: string[];
|
|
10
|
+
matchedRule?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AuthorizationContext {
|
|
13
|
+
config: BelayConfigV4;
|
|
14
|
+
grants?: CapabilityGrantV1[];
|
|
15
|
+
attestation?: BoundaryAttestation | null;
|
|
16
|
+
trustedWorkspaceRoots?: string[];
|
|
17
|
+
}
|
|
18
|
+
export interface PolicyEngine {
|
|
19
|
+
evaluate(request: CapabilityRequestV1, context: AuthorizationContext): PolicyDecision;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export declare const CAPABILITY_REQUEST_VERSION: 1;
|
|
2
|
+
export type CapabilityAction = 'fs.read' | 'fs.write' | 'process.exec' | 'network.connect' | 'secret.read' | 'git.ref.write' | 'control_plane.write' | 'indeterminate';
|
|
3
|
+
export type CapabilityEvidenceLevel = 'certain' | 'possible' | 'indeterminate';
|
|
4
|
+
export type CapabilityHookKind = 'shell' | 'tool' | 'subagent';
|
|
5
|
+
export interface CapabilityPrincipal {
|
|
6
|
+
adapter?: string;
|
|
7
|
+
repoRoot: string;
|
|
8
|
+
sessionHash?: string;
|
|
9
|
+
}
|
|
10
|
+
export type CapabilityResource = {
|
|
11
|
+
kind: 'path';
|
|
12
|
+
path: string;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'network';
|
|
15
|
+
host: string;
|
|
16
|
+
port?: number;
|
|
17
|
+
protocol?: string;
|
|
18
|
+
} | {
|
|
19
|
+
kind: 'executable';
|
|
20
|
+
command: string;
|
|
21
|
+
} | {
|
|
22
|
+
kind: 'git-ref';
|
|
23
|
+
ref: string;
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'unknown';
|
|
26
|
+
};
|
|
27
|
+
export interface CapabilityRequestContext {
|
|
28
|
+
cwd: string;
|
|
29
|
+
inputFingerprint: string;
|
|
30
|
+
hookKind: CapabilityHookKind;
|
|
31
|
+
analysisBasis: string[];
|
|
32
|
+
boundaryProfile?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface CapabilityEvidence {
|
|
35
|
+
level: CapabilityEvidenceLevel;
|
|
36
|
+
signals: string[];
|
|
37
|
+
}
|
|
38
|
+
export interface CapabilityRequestV1 {
|
|
39
|
+
version: typeof CAPABILITY_REQUEST_VERSION;
|
|
40
|
+
principal: CapabilityPrincipal;
|
|
41
|
+
action: CapabilityAction;
|
|
42
|
+
resource: CapabilityResource;
|
|
43
|
+
context: CapabilityRequestContext;
|
|
44
|
+
evidence: CapabilityEvidence;
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const CAPABILITY_REQUEST_VERSION = 1;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { evaluateSegmentShellPolicy, type SegmentShellPolicyInput, } from '../verdict/shell-policy.js';
|
|
2
|
+
export { BOUNDARY_PROFILE_L3_POLICY, checkGatedActionLimits } from './limits.js';
|
|
3
|
+
export { type CapabilityAuthorizationMetadata, policyReasonToLegacyReason, singleCapabilityMetadata, } from './policy-bridge.js';
|
|
4
|
+
export { buildFileMutationCapabilityRequest, buildShellCapabilityRequest, buildSubagentCapabilityRequest, evaluateFileMutationPolicy, evaluateShellPolicy, evaluateSubagentPolicy, type FileMutationCapabilityAnalysis, policyDecisionRequiresAsk, type ShellCapabilityAnalysis, type SubagentCapabilityAnalysis, } from './policy-engine.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { evaluateSegmentShellPolicy, } from '../verdict/shell-policy.js';
|
|
2
|
+
export { BOUNDARY_PROFILE_L3_POLICY, checkGatedActionLimits } from './limits.js';
|
|
3
|
+
export { policyReasonToLegacyReason, singleCapabilityMetadata, } from './policy-bridge.js';
|
|
4
|
+
export { buildFileMutationCapabilityRequest, buildShellCapabilityRequest, buildSubagentCapabilityRequest, evaluateFileMutationPolicy, evaluateShellPolicy, evaluateSubagentPolicy, policyDecisionRequiresAsk, } from './policy-engine.js';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { BelayConfigV3 } from '../config.js';
|
|
2
|
+
import type { TrustedWorkspaceRootEntry, TrustedWorkspaceRootsFile } from './types.js';
|
|
3
|
+
export declare function trustedWorkspaceRootsPath(config: BelayConfigV3, repoLocalStateDir: string): string;
|
|
4
|
+
export declare function loadTrustedWorkspaceRoots(filePath: string): Promise<TrustedWorkspaceRootsFile>;
|
|
5
|
+
export declare function loadTrustedWorkspaceRootsSync(filePath: string): TrustedWorkspaceRootsFile;
|
|
6
|
+
export declare function saveTrustedWorkspaceRoots(filePath: string, state: TrustedWorkspaceRootsFile): Promise<void>;
|
|
7
|
+
export declare function normalizeTrustedWorkspaceRootPath(targetPath: string): string;
|
|
8
|
+
export interface TrustedWorkspaceRootValidationParams {
|
|
9
|
+
candidatePath: string;
|
|
10
|
+
repoRoot: string;
|
|
11
|
+
controlPlaneDir?: string | null;
|
|
12
|
+
protectedRoots?: string[];
|
|
13
|
+
requireExistingDirectory?: boolean;
|
|
14
|
+
requireNonGit?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface TrustedWorkspaceRootValidationResult {
|
|
17
|
+
ok: boolean;
|
|
18
|
+
normalizedPath: string;
|
|
19
|
+
reason?: 'not_directory' | 'broad_root' | 'high_stakes' | 'inside_repo' | 'inside_git_repo' | 'control_plane_overlap' | 'protected_root_overlap';
|
|
20
|
+
}
|
|
21
|
+
export declare function isBroadTrustedWorkspaceRoot(targetPath: string): boolean;
|
|
22
|
+
export declare function isHighStakesTrustedWorkspaceRoot(targetPath: string): boolean;
|
|
23
|
+
export declare function validateTrustedWorkspaceRootCandidate(params: TrustedWorkspaceRootValidationParams): TrustedWorkspaceRootValidationResult;
|
|
24
|
+
export declare function isPathWithinTrustedWorkspaceRoots(absolutePath: string, roots: TrustedWorkspaceRootsFile): boolean;
|
|
25
|
+
export declare function addTrustedWorkspaceRoot(roots: TrustedWorkspaceRootsFile, entry: TrustedWorkspaceRootEntry): TrustedWorkspaceRootsFile;
|