@guilz-dev/belay 0.4.0 → 0.7.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 +27 -2
- package/dist/adapters/claude/runtime-entry.js +54 -25
- package/dist/adapters/layouts/scope.js +3 -2
- package/dist/adapters/shared/gate-runtime.d.ts +8 -2
- package/dist/adapters/shared/gate-runtime.js +579 -181
- package/dist/bundle/claude-runtime.mjs +13574 -6334
- package/dist/bundle/codex-runtime.mjs +13108 -5903
- package/dist/bundle/cursor-runtime.mjs +12676 -5476
- package/dist/cli.js +80 -2
- package/dist/commands/approve.js +34 -10
- package/dist/commands/classify-for-report.js +1 -1
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.js +134 -11
- package/dist/commands/doctor.js +87 -1
- package/dist/commands/explain.js +11 -1
- package/dist/commands/judge.js +3 -2
- package/dist/commands/recovery-checkpoints.d.ts +164 -0
- package/dist/commands/recovery-checkpoints.js +347 -0
- package/dist/commands/revoke.js +19 -7
- package/dist/commands/session.d.ts +20 -0
- package/dist/commands/session.js +51 -0
- package/dist/commands/status.js +7 -0
- package/dist/config-io.js +91 -23
- 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 +20 -9
- package/dist/conformance/types.d.ts +1 -0
- package/dist/core/approval-replay.d.ts +1 -1
- package/dist/core/approval-replay.js +4 -1
- package/dist/core/approval-service.d.ts +6 -1
- package/dist/core/approval-service.js +87 -24
- package/dist/core/approval.d.ts +4 -0
- package/dist/core/approval.js +19 -5
- package/dist/core/audit-types.d.ts +13 -0
- package/dist/core/capability/approval-state-mutation.d.ts +32 -0
- package/dist/core/capability/approval-state-mutation.js +165 -0
- package/dist/core/capability/approval-v3.d.ts +32 -0
- package/dist/core/capability/approval-v3.js +114 -0
- package/dist/core/capability/attestation.d.ts +16 -0
- package/dist/core/capability/attestation.js +62 -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 +19 -0
- package/dist/core/capability/boundary-driver-container.js +189 -0
- package/dist/core/capability/boundary-driver.d.ts +29 -0
- package/dist/core/capability/boundary-driver.js +44 -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 +14 -0
- package/dist/core/capability/boundary-grant-materialize.js +93 -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 +48 -0
- package/dist/core/capability/boundary-run.js +51 -0
- package/dist/core/capability/boundary-session.d.ts +61 -0
- package/dist/core/capability/boundary-session.js +138 -0
- package/dist/core/capability/boundary-workspace-mount.d.ts +5 -0
- package/dist/core/capability/boundary-workspace-mount.js +68 -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 +130 -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-consumption.d.ts +4 -0
- package/dist/core/capability/grant-consumption.js +11 -0
- package/dist/core/capability/grant-lease.d.ts +44 -0
- package/dist/core/capability/grant-lease.js +243 -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 +96 -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 +8 -0
- package/dist/core/capability/index.js +7 -0
- package/dist/core/capability/limits.d.ts +7 -0
- package/dist/core/capability/limits.js +55 -0
- 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 +77 -0
- package/dist/core/capability/policy-engine.js +663 -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 +48 -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/classify-subagent.d.ts +2 -1
- package/dist/core/classify-subagent.js +38 -2
- package/dist/core/classify-tool.js +126 -62
- package/dist/core/config.d.ts +34 -3
- package/dist/core/config.js +118 -3
- package/dist/core/effect-ir/audit.d.ts +9 -0
- package/dist/core/effect-ir/audit.js +86 -0
- package/dist/core/effect-ir/build.d.ts +31 -0
- package/dist/core/effect-ir/build.js +277 -0
- package/dist/core/effect-ir/index.d.ts +8 -0
- package/dist/core/effect-ir/index.js +7 -0
- package/dist/core/effect-ir/normalize.d.ts +4 -0
- package/dist/core/effect-ir/normalize.js +104 -0
- package/dist/core/effect-ir/package-exec-eval.d.ts +8 -0
- package/dist/core/effect-ir/package-exec-eval.js +152 -0
- package/dist/core/effect-ir/package-exec.d.ts +29 -0
- package/dist/core/effect-ir/package-exec.js +292 -0
- package/dist/core/effect-ir/policy.d.ts +13 -0
- package/dist/core/effect-ir/policy.js +77 -0
- package/dist/core/effect-ir/types.d.ts +55 -0
- package/dist/core/effect-ir/types.js +1 -0
- package/dist/core/egress/allowlist.d.ts +1 -0
- package/dist/core/egress/allowlist.js +8 -0
- package/dist/core/egress-approval.js +45 -51
- package/dist/core/gate-contract.d.ts +5 -0
- package/dist/core/gate-contract.js +5 -0
- package/dist/core/gate-engine.js +30 -8
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.js +2 -1
- package/dist/core/judge-cloud-consent.js +29 -15
- package/dist/core/judge-doctor.js +39 -14
- package/dist/core/judge-fallback-hints.d.ts +13 -0
- package/dist/core/judge-fallback-hints.js +108 -0
- package/dist/core/network-endpoint.d.ts +10 -0
- package/dist/core/network-endpoint.js +51 -0
- package/dist/core/path-utils.d.ts +1 -0
- package/dist/core/path-utils.js +5 -2
- package/dist/core/process-runner.d.ts +10 -0
- package/dist/core/process-runner.js +124 -0
- package/dist/core/recover-advice.js +2 -1
- package/dist/core/recovery/artifact-store.d.ts +29 -0
- package/dist/core/recovery/artifact-store.js +336 -0
- package/dist/core/recovery/capability.d.ts +3 -0
- package/dist/core/recovery/capability.js +22 -0
- package/dist/core/recovery/checkpoint.d.ts +25 -0
- package/dist/core/recovery/checkpoint.js +260 -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 +5 -0
- package/dist/core/recovery/index.js +4 -0
- package/dist/core/recovery/operator-guidance.d.ts +7 -0
- package/dist/core/recovery/operator-guidance.js +39 -0
- package/dist/core/recovery/reconcile.d.ts +3 -0
- package/dist/core/recovery/reconcile.js +48 -0
- package/dist/core/recovery/resource-identity.d.ts +4 -0
- package/dist/core/recovery/resource-identity.js +34 -0
- package/dist/core/recovery/restore.d.ts +13 -0
- package/dist/core/recovery/restore.js +114 -0
- package/dist/core/recovery/snapshot-node.d.ts +27 -0
- package/dist/core/recovery/snapshot-node.js +261 -0
- package/dist/core/recovery/types.d.ts +104 -0
- package/dist/core/recovery/types.js +1 -0
- package/dist/core/standing-allow.js +3 -0
- package/dist/core/transactional/apply-observed-changes.d.ts +13 -0
- package/dist/core/transactional/apply-observed-changes.js +275 -0
- package/dist/core/transactional/backend-selector.d.ts +8 -0
- package/dist/core/transactional/backend-selector.js +118 -0
- package/dist/core/transactional/backend.d.ts +55 -0
- package/dist/core/transactional/backend.js +1 -0
- package/dist/core/transactional/diff-evaluator.js +4 -1
- package/dist/core/transactional/eligibility.js +4 -0
- package/dist/core/transactional/file-checkpoint-backend.d.ts +3 -0
- package/dist/core/transactional/file-checkpoint-backend.js +278 -0
- package/dist/core/transactional/file-checkpoint-git.d.ts +11 -0
- package/dist/core/transactional/file-checkpoint-git.js +217 -0
- package/dist/core/transactional/file-checkpoint-staging.d.ts +13 -0
- package/dist/core/transactional/file-checkpoint-staging.js +54 -0
- package/dist/core/transactional/file-clone.d.ts +15 -0
- package/dist/core/transactional/file-clone.js +139 -0
- package/dist/core/transactional/file-tree-path.d.ts +7 -0
- package/dist/core/transactional/file-tree-path.js +50 -0
- package/dist/core/transactional/file-tree.d.ts +41 -0
- package/dist/core/transactional/file-tree.js +186 -0
- package/dist/core/transactional/git-worktree-backend.d.ts +2 -0
- package/dist/core/transactional/git-worktree-backend.js +50 -0
- package/dist/core/transactional/git-worktree.d.ts +14 -9
- package/dist/core/transactional/git-worktree.js +62 -87
- package/dist/core/transactional/index.d.ts +11 -0
- package/dist/core/transactional/index.js +10 -0
- package/dist/core/transactional/reasons.d.ts +1 -0
- package/dist/core/transactional/reasons.js +5 -0
- package/dist/core/transactional/runner.js +171 -23
- package/dist/core/transactional/snapshot-node.d.ts +26 -0
- package/dist/core/transactional/snapshot-node.js +87 -0
- package/dist/core/transactional/types.d.ts +21 -1
- package/dist/core/types.d.ts +30 -3
- package/dist/core/verdict/adapter.d.ts +3 -4
- package/dist/core/verdict/adapter.js +24 -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.js +1 -0
- package/dist/core/verdict/judge-baseline.d.ts +1 -1
- package/dist/core/verdict/judge-baseline.js +1 -0
- package/dist/core/verdict/judge-broker-service.js +12 -0
- package/dist/core/verdict/judge-catalog.js +1 -0
- package/dist/core/verdict/judge-cli-fingerprint.d.ts +1 -0
- package/dist/core/verdict/judge-cli-fingerprint.js +6 -0
- package/dist/core/verdict/judge-cli.js +5 -3
- package/dist/core/verdict/judge-provider-matrix.js +1 -1
- package/dist/core/verdict/judge-runtime-config.d.ts +2 -0
- package/dist/core/verdict/judge-runtime-config.js +10 -6
- package/dist/core/verdict/judge-session-broker.d.ts +1 -1
- package/dist/core/verdict/judge-session-broker.js +10 -5
- package/dist/core/verdict/judge-transport.d.ts +5 -1
- package/dist/core/verdict/judge-transport.js +24 -14
- package/dist/core/verdict/judge.d.ts +2 -15
- package/dist/core/verdict/judge.js +5 -68
- package/dist/core/verdict/launcher-resolve.d.ts +2 -0
- package/dist/core/verdict/launcher-resolve.js +14 -16
- 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 +26 -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 +18 -1
- package/dist/core/verdict/verdict.js +313 -178
- package/dist/corpus/evaluate.js +3 -7
- package/dist/corpus/gate-latency-budget.d.ts +39 -0
- package/dist/corpus/gate-latency-budget.js +33 -0
- package/dist/corpus/mutators.d.ts +1 -1
- package/dist/corpus/mutators.js +11 -0
- package/dist/corpus/runtime-match.js +1 -3
- package/dist/corpus/standing-allow-catalog.generated.js +29 -9
- package/dist/judge-broker-daemon.js +15 -1
- package/dist/services/sandbox-service.d.ts +4 -0
- package/dist/services/sandbox-service.js +28 -2
- package/dist/types.d.ts +13 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/belay/SKILL.md +8 -3
- package/skills/belay/belay-approve.md +10 -7
package/dist/core/config.js
CHANGED
|
@@ -3,6 +3,7 @@ import { warnDeprecatedJudgeModelAuto } from './judge-model-policy.js';
|
|
|
3
3
|
import { getJudgeProviderSpec, inferProviderIdFromConfig, isRemovedProviderId, normalizeLegacyProviderId, warnRemovedProviderId, } from './verdict/judge-catalog.js';
|
|
4
4
|
import { normalizeJudgeRuntimeConfig, } from './verdict/judge-runtime-config.js';
|
|
5
5
|
export const DEFAULT_JUDGE_LOCAL_OLLAMA = {
|
|
6
|
+
mode: 'shadow',
|
|
6
7
|
provider: 'ollama',
|
|
7
8
|
providerId: 'ollama',
|
|
8
9
|
model: 'gemma4:e2b',
|
|
@@ -11,6 +12,7 @@ export const DEFAULT_JUDGE_LOCAL_OLLAMA = {
|
|
|
11
12
|
keepAlive: '30m',
|
|
12
13
|
};
|
|
13
14
|
export const DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE = {
|
|
15
|
+
mode: 'shadow',
|
|
14
16
|
provider: 'openai-compatible',
|
|
15
17
|
providerId: 'codex',
|
|
16
18
|
model: 'gpt-5.3-codex-high',
|
|
@@ -20,6 +22,23 @@ export const DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE = {
|
|
|
20
22
|
};
|
|
21
23
|
/** @deprecated Use DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE */
|
|
22
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
|
+
}
|
|
23
42
|
/** Pre-v0.4 defaults preserved when migrating existing v1/v2/v3 configs. */
|
|
24
43
|
import { DEFAULT_SILENT_PASS_THRESHOLD } from './audit-summary.js';
|
|
25
44
|
/** @deprecated Use DEFAULT_SILENT_PASS_THRESHOLD from audit-summary.js */
|
|
@@ -32,6 +51,46 @@ export const DEFAULT_MODEL_ASSIST = {
|
|
|
32
51
|
enabled: false,
|
|
33
52
|
timeoutMs: 3000,
|
|
34
53
|
};
|
|
54
|
+
export const DEFAULT_FILE_CHECKPOINT = {
|
|
55
|
+
enabled: false,
|
|
56
|
+
allowNonGit: false,
|
|
57
|
+
maxFiles: 100_000,
|
|
58
|
+
maxSourceBytes: 2_147_483_648,
|
|
59
|
+
maxWorkspaceBytes: 4_294_967_296,
|
|
60
|
+
prepareTimeoutMs: 30_000,
|
|
61
|
+
copyConcurrency: 8,
|
|
62
|
+
};
|
|
63
|
+
function clampCopyConcurrency(value) {
|
|
64
|
+
return Math.min(32, Math.max(1, Math.floor(value)));
|
|
65
|
+
}
|
|
66
|
+
export function normalizeFileCheckpointConfig(raw) {
|
|
67
|
+
return {
|
|
68
|
+
enabled: raw?.enabled === true,
|
|
69
|
+
allowNonGit: raw?.allowNonGit === true,
|
|
70
|
+
maxFiles: typeof raw?.maxFiles === 'number' && raw.maxFiles > 0
|
|
71
|
+
? Math.floor(raw.maxFiles)
|
|
72
|
+
: DEFAULT_FILE_CHECKPOINT.maxFiles,
|
|
73
|
+
maxSourceBytes: typeof raw?.maxSourceBytes === 'number' && raw.maxSourceBytes > 0
|
|
74
|
+
? Math.floor(raw.maxSourceBytes)
|
|
75
|
+
: DEFAULT_FILE_CHECKPOINT.maxSourceBytes,
|
|
76
|
+
maxWorkspaceBytes: typeof raw?.maxWorkspaceBytes === 'number' && raw.maxWorkspaceBytes > 0
|
|
77
|
+
? Math.floor(raw.maxWorkspaceBytes)
|
|
78
|
+
: DEFAULT_FILE_CHECKPOINT.maxWorkspaceBytes,
|
|
79
|
+
prepareTimeoutMs: typeof raw?.prepareTimeoutMs === 'number' && raw.prepareTimeoutMs > 0
|
|
80
|
+
? Math.floor(raw.prepareTimeoutMs)
|
|
81
|
+
: DEFAULT_FILE_CHECKPOINT.prepareTimeoutMs,
|
|
82
|
+
copyConcurrency: typeof raw?.copyConcurrency === 'number' && raw.copyConcurrency > 0
|
|
83
|
+
? clampCopyConcurrency(raw.copyConcurrency)
|
|
84
|
+
: DEFAULT_FILE_CHECKPOINT.copyConcurrency,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export const DEFAULT_RECOVERY_CHECKPOINT = {
|
|
88
|
+
enabled: false,
|
|
89
|
+
appliedRetentionHours: 7 * 24,
|
|
90
|
+
restoredRetentionHours: 24,
|
|
91
|
+
maxCheckpoints: 20,
|
|
92
|
+
maxBytes: 1024 * 1024 * 1024,
|
|
93
|
+
};
|
|
35
94
|
export const DEFAULT_TRANSACTIONAL_V3 = {
|
|
36
95
|
enabled: false,
|
|
37
96
|
minConfidence: DEFAULT_CONFIDENCE_THRESHOLDS.flag,
|
|
@@ -41,6 +100,8 @@ export const DEFAULT_TRANSACTIONAL_V3 = {
|
|
|
41
100
|
gates: {
|
|
42
101
|
shell: true,
|
|
43
102
|
},
|
|
103
|
+
fileCheckpoint: { ...DEFAULT_FILE_CHECKPOINT },
|
|
104
|
+
checkpoint: { ...DEFAULT_RECOVERY_CHECKPOINT },
|
|
44
105
|
};
|
|
45
106
|
export const LEGACY_POLICY_V3 = {
|
|
46
107
|
unknownLocalEffect: 'allow_flagged',
|
|
@@ -222,7 +283,8 @@ export function isConfigV3(value) {
|
|
|
222
283
|
return version === 3 || version === 4;
|
|
223
284
|
}
|
|
224
285
|
export function isConfigV4(value) {
|
|
225
|
-
|
|
286
|
+
const version = typeof value === 'object' && value !== null ? value.version : null;
|
|
287
|
+
return version === 4 || version === 5;
|
|
226
288
|
}
|
|
227
289
|
export function normalizeJudgeProvider(provider) {
|
|
228
290
|
if (provider === 'anthropic') {
|
|
@@ -239,6 +301,7 @@ function defaultJudgeTemplateForProvider(provider) {
|
|
|
239
301
|
}
|
|
240
302
|
if (provider === 'anthropic') {
|
|
241
303
|
return {
|
|
304
|
+
mode: 'shadow',
|
|
242
305
|
provider: 'anthropic',
|
|
243
306
|
providerId: 'claude',
|
|
244
307
|
model: 'claude-sonnet-4-6',
|
|
@@ -283,6 +346,7 @@ export function normalizeJudgeConfig(judge) {
|
|
|
283
346
|
const timeoutMs = typeof judge.timeoutMs === 'number' && judge.timeoutMs > 0 ? judge.timeoutMs : base.timeoutMs;
|
|
284
347
|
const endpoint = typeof judge.endpoint === 'string' && judge.endpoint.trim() ? judge.endpoint.trim() : null;
|
|
285
348
|
return {
|
|
349
|
+
mode: judge.mode === 'off' ? 'off' : 'shadow',
|
|
286
350
|
provider,
|
|
287
351
|
providerId: rawProviderId,
|
|
288
352
|
model,
|
|
@@ -320,6 +384,7 @@ export function normalizeJudgeConfig(judge) {
|
|
|
320
384
|
endpoint = catalogSpec.defaultEndpoint;
|
|
321
385
|
}
|
|
322
386
|
const normalized = {
|
|
387
|
+
mode: judge.mode === 'off' ? 'off' : 'shadow',
|
|
323
388
|
provider,
|
|
324
389
|
providerId,
|
|
325
390
|
model,
|
|
@@ -490,6 +555,19 @@ function normalizeV3Raw(raw) {
|
|
|
490
555
|
},
|
|
491
556
|
});
|
|
492
557
|
}
|
|
558
|
+
function normalizeV5Raw(raw) {
|
|
559
|
+
const base = normalizeV3Raw({ ...raw, version: 4 });
|
|
560
|
+
return {
|
|
561
|
+
...base,
|
|
562
|
+
version: 5,
|
|
563
|
+
capability: {
|
|
564
|
+
grantsEnabled: raw.capability?.grantsEnabled !== false,
|
|
565
|
+
boundaryDriver: raw.capability?.boundaryDriver ?? 'host-integration',
|
|
566
|
+
attestationRelPath: raw.capability?.attestationRelPath ?? '.belay/attestation.json',
|
|
567
|
+
...(raw.capability ?? {}),
|
|
568
|
+
},
|
|
569
|
+
};
|
|
570
|
+
}
|
|
493
571
|
export function migrateConfig(loaded) {
|
|
494
572
|
if (typeof loaded !== 'object' || loaded === null) {
|
|
495
573
|
return { ...DEFAULT_CONFIG_V4 };
|
|
@@ -498,6 +576,9 @@ export function migrateConfig(loaded) {
|
|
|
498
576
|
if (raw.version === 4) {
|
|
499
577
|
return normalizeV3Raw(raw);
|
|
500
578
|
}
|
|
579
|
+
if (raw.version === 5) {
|
|
580
|
+
return normalizeV5Raw(raw);
|
|
581
|
+
}
|
|
501
582
|
if (raw.version === 3 || (raw.version === undefined && hasV3Sections(raw))) {
|
|
502
583
|
return normalizeV3Raw(raw);
|
|
503
584
|
}
|
|
@@ -576,8 +657,9 @@ export function normalizeConfig(config) {
|
|
|
576
657
|
return normalizeConfigV2(config);
|
|
577
658
|
}
|
|
578
659
|
const v4 = config;
|
|
579
|
-
|
|
580
|
-
|
|
660
|
+
const version = v4.version === 5 ? 5 : 4;
|
|
661
|
+
const normalized = {
|
|
662
|
+
version,
|
|
581
663
|
...(v4.installScope === 'global' || v4.installScope === 'project'
|
|
582
664
|
? { installScope: v4.installScope }
|
|
583
665
|
: {}),
|
|
@@ -656,6 +738,26 @@ export function normalizeConfig(config) {
|
|
|
656
738
|
gates: {
|
|
657
739
|
shell: v4.policy?.transactional?.gates?.shell !== false,
|
|
658
740
|
},
|
|
741
|
+
fileCheckpoint: normalizeFileCheckpointConfig(v4.policy?.transactional?.fileCheckpoint),
|
|
742
|
+
checkpoint: {
|
|
743
|
+
enabled: v4.policy?.transactional?.checkpoint?.enabled === true,
|
|
744
|
+
appliedRetentionHours: typeof v4.policy?.transactional?.checkpoint?.appliedRetentionHours === 'number' &&
|
|
745
|
+
v4.policy.transactional.checkpoint.appliedRetentionHours > 0
|
|
746
|
+
? v4.policy.transactional.checkpoint.appliedRetentionHours
|
|
747
|
+
: DEFAULT_RECOVERY_CHECKPOINT.appliedRetentionHours,
|
|
748
|
+
restoredRetentionHours: typeof v4.policy?.transactional?.checkpoint?.restoredRetentionHours === 'number' &&
|
|
749
|
+
v4.policy.transactional.checkpoint.restoredRetentionHours > 0
|
|
750
|
+
? v4.policy.transactional.checkpoint.restoredRetentionHours
|
|
751
|
+
: DEFAULT_RECOVERY_CHECKPOINT.restoredRetentionHours,
|
|
752
|
+
maxCheckpoints: typeof v4.policy?.transactional?.checkpoint?.maxCheckpoints === 'number' &&
|
|
753
|
+
v4.policy.transactional.checkpoint.maxCheckpoints > 0
|
|
754
|
+
? Math.floor(v4.policy.transactional.checkpoint.maxCheckpoints)
|
|
755
|
+
: DEFAULT_RECOVERY_CHECKPOINT.maxCheckpoints,
|
|
756
|
+
maxBytes: typeof v4.policy?.transactional?.checkpoint?.maxBytes === 'number' &&
|
|
757
|
+
v4.policy.transactional.checkpoint.maxBytes > 0
|
|
758
|
+
? Math.floor(v4.policy.transactional.checkpoint.maxBytes)
|
|
759
|
+
: DEFAULT_RECOVERY_CHECKPOINT.maxBytes,
|
|
760
|
+
},
|
|
659
761
|
};
|
|
660
762
|
})(),
|
|
661
763
|
},
|
|
@@ -743,6 +845,10 @@ export function normalizeConfig(config) {
|
|
|
743
845
|
},
|
|
744
846
|
judge: normalizeJudgeConfig(v4.judge ?? DEFAULT_JUDGE_LOCAL_OLLAMA),
|
|
745
847
|
};
|
|
848
|
+
if (version === 5 || v4.capability) {
|
|
849
|
+
normalized.capability = normalizeCapabilityConfig(v4.capability ?? DEFAULT_CAPABILITY_V5);
|
|
850
|
+
}
|
|
851
|
+
return normalized;
|
|
746
852
|
}
|
|
747
853
|
export function isFreshConfigInput(loaded) {
|
|
748
854
|
if (loaded === null || loaded === undefined) {
|
|
@@ -814,6 +920,15 @@ export function mergeConfig(existing, defaults = DEFAULT_CONFIG_V4) {
|
|
|
814
920
|
...migrated.audit,
|
|
815
921
|
},
|
|
816
922
|
...(migrated.installScope ? { installScope: migrated.installScope } : {}),
|
|
923
|
+
...(migrated.version === 5 || migrated.capability
|
|
924
|
+
? {
|
|
925
|
+
version: migrated.version === 5 ? 5 : 4,
|
|
926
|
+
capability: normalizeCapabilityConfig({
|
|
927
|
+
...DEFAULT_CAPABILITY_V5,
|
|
928
|
+
...migrated.capability,
|
|
929
|
+
}),
|
|
930
|
+
}
|
|
931
|
+
: {}),
|
|
817
932
|
});
|
|
818
933
|
}
|
|
819
934
|
export function scrubOptionsFromConfig(config) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PolicyDecision } from '../capability/policy-types.js';
|
|
2
|
+
import type { CapabilityRequestV1 } from '../capability/request.js';
|
|
3
|
+
import type { EffectPlan } from './types.js';
|
|
4
|
+
export declare function hashEffectPlan(plan: EffectPlan): string;
|
|
5
|
+
export declare function effectPlanAuditFields(plan: EffectPlan | undefined, policy?: {
|
|
6
|
+
capabilityRequests?: readonly CapabilityRequestV1[];
|
|
7
|
+
decisions?: readonly PolicyDecision[];
|
|
8
|
+
authorizationDecision?: PolicyDecision;
|
|
9
|
+
}): Record<string, unknown>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { canonicalStringify, hashValue } from '../fingerprint.js';
|
|
2
|
+
import { collectRequirements } from './build.js';
|
|
3
|
+
function auditableProvenance(provenance) {
|
|
4
|
+
return {
|
|
5
|
+
...(provenance.segment ? { segment: provenance.segment } : {}),
|
|
6
|
+
...(provenance.launcher ? { launcher: provenance.launcher } : {}),
|
|
7
|
+
...(provenance.phase ? { phase: provenance.phase } : {}),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function auditableResource(resource) {
|
|
11
|
+
if (resource.kind === 'executable') {
|
|
12
|
+
return {
|
|
13
|
+
kind: 'executable',
|
|
14
|
+
commandHash: hashValue(resource.command),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
return resource;
|
|
18
|
+
}
|
|
19
|
+
export function hashEffectPlan(plan) {
|
|
20
|
+
const requirements = collectRequirements(plan.root)
|
|
21
|
+
.map((requirement) => ({
|
|
22
|
+
tag: requirement.tag,
|
|
23
|
+
action: requirement.action,
|
|
24
|
+
resource: auditableResource(requirement.resource),
|
|
25
|
+
evidence: {
|
|
26
|
+
level: requirement.evidence.level,
|
|
27
|
+
signals: [...requirement.evidence.signals].sort(),
|
|
28
|
+
basis: [...requirement.evidence.basis].sort(),
|
|
29
|
+
},
|
|
30
|
+
provenance: requirement.provenance,
|
|
31
|
+
provenances: [...(requirement.provenances ?? [requirement.provenance])].sort((left, right) => canonicalStringify(left).localeCompare(canonicalStringify(right))),
|
|
32
|
+
}))
|
|
33
|
+
.sort((left, right) => canonicalStringify(left).localeCompare(canonicalStringify(right)));
|
|
34
|
+
return hashValue(`effect-plan:v1:${canonicalStringify({
|
|
35
|
+
version: plan.version,
|
|
36
|
+
inputFingerprint: plan.inputFingerprint,
|
|
37
|
+
opacity: plan.opacity,
|
|
38
|
+
disposition: plan.disposition,
|
|
39
|
+
completeness: plan.completeness,
|
|
40
|
+
signals: [...plan.signals].sort(),
|
|
41
|
+
requirements,
|
|
42
|
+
})}`);
|
|
43
|
+
}
|
|
44
|
+
export function effectPlanAuditFields(plan, policy) {
|
|
45
|
+
if (!plan) {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
const fields = {
|
|
49
|
+
effectPlanVersion: plan.version,
|
|
50
|
+
effectIRHash: hashEffectPlan(plan),
|
|
51
|
+
effectPlanSignals: [...plan.signals],
|
|
52
|
+
effectPlanOpacity: plan.opacity,
|
|
53
|
+
effectPlanDisposition: plan.disposition,
|
|
54
|
+
effectPlanCompleteness: plan.completeness,
|
|
55
|
+
effectPlanRequirements: collectRequirements(plan.root).map((requirement) => ({
|
|
56
|
+
tag: requirement.tag,
|
|
57
|
+
action: requirement.action,
|
|
58
|
+
resource: auditableResource(requirement.resource),
|
|
59
|
+
evidence: requirement.evidence,
|
|
60
|
+
provenance: auditableProvenance(requirement.provenance),
|
|
61
|
+
provenances: (requirement.provenances ?? [requirement.provenance]).map((provenance) => auditableProvenance(provenance)),
|
|
62
|
+
})),
|
|
63
|
+
};
|
|
64
|
+
if (policy?.authorizationDecision) {
|
|
65
|
+
fields.effectPlanPolicyOutcome = policy.authorizationDecision.outcome;
|
|
66
|
+
fields.effectPlanPolicyReason = policy.authorizationDecision.reason;
|
|
67
|
+
if (policy.authorizationDecision.matchedRule) {
|
|
68
|
+
fields.effectPlanPolicyMatchedRule = policy.authorizationDecision.matchedRule;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (policy?.capabilityRequests?.length) {
|
|
72
|
+
fields.effectPlanRequestActions = policy.capabilityRequests.map((request) => request.action);
|
|
73
|
+
fields.effectPlanRequestCount = policy.capabilityRequests.length;
|
|
74
|
+
if (policy.capabilityRequests.some((request) => request.evidence.signals.includes('package_cache_write'))) {
|
|
75
|
+
fields.effectPlanCacheWriteProjected = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (policy?.decisions?.length) {
|
|
79
|
+
fields.effectPlanRequestDecisions = policy.decisions.map((decision) => ({
|
|
80
|
+
outcome: decision.outcome,
|
|
81
|
+
reason: decision.reason,
|
|
82
|
+
matchedRule: decision.matchedRule,
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
return fields;
|
|
86
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CapabilityPrincipal, CapabilityRequestV1 } from '../capability/request.js';
|
|
2
|
+
import type { LauncherResolution } from '../verdict/launcher-resolve.js';
|
|
3
|
+
import type { EffectNode, EffectPlan, EffectRequirement, PackageExecLauncher } from './types.js';
|
|
4
|
+
export interface BuildEffectPlanParams {
|
|
5
|
+
tokens: string[];
|
|
6
|
+
cwd: string;
|
|
7
|
+
repoRoot: string;
|
|
8
|
+
inputFingerprint: string;
|
|
9
|
+
launcherResolution?: LauncherResolution | null;
|
|
10
|
+
innerRequirements?: readonly EffectRequirement[];
|
|
11
|
+
}
|
|
12
|
+
export interface BuildCapabilityEffectPlanParams {
|
|
13
|
+
actionKind: 'shell' | 'tool' | 'subagent';
|
|
14
|
+
summary: string;
|
|
15
|
+
inputFingerprint: string;
|
|
16
|
+
requests: readonly CapabilityRequestV1[];
|
|
17
|
+
effectFree: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function buildPackageExecEffectNode(params: BuildEffectPlanParams): EffectNode | null;
|
|
20
|
+
export declare function collectRequirements(node: EffectNode): EffectRequirement[];
|
|
21
|
+
export declare function buildEffectPlan(params: BuildEffectPlanParams): EffectPlan | null;
|
|
22
|
+
/** Build the canonical plan envelope for non-package-exec gated actions. */
|
|
23
|
+
export declare function buildCapabilityEffectPlan(params: BuildCapabilityEffectPlanParams): EffectPlan;
|
|
24
|
+
export declare function flattenRequirementsToCapabilityRequests(requirements: readonly EffectRequirement[], opts: {
|
|
25
|
+
principal: CapabilityPrincipal;
|
|
26
|
+
cwd: string;
|
|
27
|
+
repoRoot: string;
|
|
28
|
+
hookKind: 'shell';
|
|
29
|
+
inputFingerprint: string;
|
|
30
|
+
}): CapabilityRequestV1[];
|
|
31
|
+
export type { PackageExecLauncher };
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { mergeRequirements } from './normalize.js';
|
|
2
|
+
import { classifyPackageAcquisitionSpec, innerRecipeFromPeel, peelPackageExecArgv, resolveLocalBin, } from './package-exec.js';
|
|
3
|
+
export function buildPackageExecEffectNode(params) {
|
|
4
|
+
const peel = peelPackageExecArgv(params.tokens);
|
|
5
|
+
if (!peel) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
const children = [];
|
|
9
|
+
const invokeNode = {
|
|
10
|
+
kind: 'launcher',
|
|
11
|
+
launcher: peel.launcher,
|
|
12
|
+
phase: 'invoke',
|
|
13
|
+
opaque: peel.opaque,
|
|
14
|
+
reason: peel.reason,
|
|
15
|
+
children: [],
|
|
16
|
+
};
|
|
17
|
+
children.push(invokeNode);
|
|
18
|
+
if (peel.opaque) {
|
|
19
|
+
children.push(acquireRequirement(peel, 'indeterminate'));
|
|
20
|
+
return { kind: 'merge', children };
|
|
21
|
+
}
|
|
22
|
+
if (peel.reason === 'npx_wrapper_readonly') {
|
|
23
|
+
return { kind: 'merge', children };
|
|
24
|
+
}
|
|
25
|
+
const innerRecipe = innerRecipeFromPeel(peel);
|
|
26
|
+
const binHead = peel.innerTokens[0] ?? '';
|
|
27
|
+
const local = !peel.forceAcquire ? resolveLocalBin(binHead, params.cwd, params.repoRoot) : null;
|
|
28
|
+
if (local) {
|
|
29
|
+
children.push({
|
|
30
|
+
kind: 'launcher',
|
|
31
|
+
launcher: peel.launcher,
|
|
32
|
+
phase: 'resolve',
|
|
33
|
+
opaque: false,
|
|
34
|
+
reason: 'npx_local_bin_resolved',
|
|
35
|
+
children: [],
|
|
36
|
+
});
|
|
37
|
+
if (innerRecipe) {
|
|
38
|
+
children.push(delegateExecNode(peel, innerRecipe, binHead, local.path));
|
|
39
|
+
}
|
|
40
|
+
if (innerRecipe && params.innerRequirements !== undefined) {
|
|
41
|
+
if (params.innerRequirements.length > 0) {
|
|
42
|
+
children.push({
|
|
43
|
+
kind: 'exec',
|
|
44
|
+
commandRedacted: innerRecipe,
|
|
45
|
+
segmentHead: binHead,
|
|
46
|
+
requirements: [...params.innerRequirements],
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
children.push(acquireRequirement(peel, 'possible'));
|
|
53
|
+
if (innerRecipe) {
|
|
54
|
+
children.push(delegateExecNode(peel, innerRecipe, binHead));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { kind: 'merge', children };
|
|
58
|
+
}
|
|
59
|
+
function delegateExecNode(peel, innerRecipe, segmentHead, resolvedLocalPath) {
|
|
60
|
+
return {
|
|
61
|
+
kind: 'launcher',
|
|
62
|
+
launcher: peel.launcher,
|
|
63
|
+
phase: 'delegate',
|
|
64
|
+
opaque: false,
|
|
65
|
+
reason: 'package_exec_delegate',
|
|
66
|
+
children: [
|
|
67
|
+
{
|
|
68
|
+
kind: 'exec',
|
|
69
|
+
commandRedacted: innerRecipe,
|
|
70
|
+
segmentHead,
|
|
71
|
+
requirements: [
|
|
72
|
+
{
|
|
73
|
+
tag: 'process.exec',
|
|
74
|
+
action: 'process.exec',
|
|
75
|
+
resource: { kind: 'executable', command: resolvedLocalPath ?? segmentHead },
|
|
76
|
+
evidence: {
|
|
77
|
+
level: resolvedLocalPath ? 'certain' : peel.forceAcquire ? 'possible' : 'certain',
|
|
78
|
+
signals: [
|
|
79
|
+
'package_exec.delegate',
|
|
80
|
+
...(resolvedLocalPath ? ['package_exec.local_bin_resolved'] : []),
|
|
81
|
+
],
|
|
82
|
+
basis: [`launcher:${peel.launcher}`],
|
|
83
|
+
},
|
|
84
|
+
provenance: {
|
|
85
|
+
launcher: peel.launcher,
|
|
86
|
+
phase: 'delegate',
|
|
87
|
+
innerCommand: innerRecipe,
|
|
88
|
+
innerArgv: [...peel.innerTokens],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function cacheWriteRequirement(peel) {
|
|
97
|
+
return {
|
|
98
|
+
tag: 'fs.write',
|
|
99
|
+
action: 'fs.write',
|
|
100
|
+
resource: { kind: 'package-cache', manager: peel.launcher === 'pnpm' ? 'pnpm' : 'npm' },
|
|
101
|
+
evidence: {
|
|
102
|
+
level: 'possible',
|
|
103
|
+
signals: [...peel.signals, 'package_cache_write'],
|
|
104
|
+
basis: [`launcher:${peel.launcher}:cache_write`],
|
|
105
|
+
},
|
|
106
|
+
provenance: { launcher: peel.launcher, phase: 'cache_write' },
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function acquireRequirement(peel, level) {
|
|
110
|
+
const knownResources = packageAcquisitionResources(peel.acquisitionSpecs);
|
|
111
|
+
const networkRequirements = knownResources.map((resource) => acquireNetworkRequirement(peel, resource, 'possible'));
|
|
112
|
+
if (level === 'indeterminate') {
|
|
113
|
+
networkRequirements.push(acquireNetworkRequirement(peel, { kind: 'unknown' }, level));
|
|
114
|
+
}
|
|
115
|
+
else if (networkRequirements.length === 0 && peel.acquisitionSpecs.length === 0) {
|
|
116
|
+
networkRequirements.push(acquireNetworkRequirement(peel, { kind: 'network', host: 'registry.npmjs.org', protocol: 'registry' }, level));
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
kind: 'launcher',
|
|
120
|
+
launcher: peel.launcher,
|
|
121
|
+
phase: 'acquire',
|
|
122
|
+
opaque: level === 'indeterminate',
|
|
123
|
+
reason: peel.reason,
|
|
124
|
+
children: [
|
|
125
|
+
{
|
|
126
|
+
kind: 'exec',
|
|
127
|
+
commandRedacted: peel.innerTokens.join(' ') || peel.launcher,
|
|
128
|
+
segmentHead: peel.launcher,
|
|
129
|
+
requirements: [
|
|
130
|
+
...networkRequirements,
|
|
131
|
+
...(level === 'possible' || peel.acquisitionSpecs.length > 0
|
|
132
|
+
? [cacheWriteRequirement(peel)]
|
|
133
|
+
: []),
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function acquireNetworkRequirement(peel, resource, level) {
|
|
140
|
+
return {
|
|
141
|
+
tag: level === 'indeterminate' ? 'indeterminate' : 'network.acquire',
|
|
142
|
+
action: level === 'indeterminate' ? 'indeterminate' : 'network.connect',
|
|
143
|
+
resource,
|
|
144
|
+
evidence: {
|
|
145
|
+
level,
|
|
146
|
+
signals: [...peel.signals, 'package_acquire_possible'],
|
|
147
|
+
basis: [`launcher:${peel.launcher}:acquire`],
|
|
148
|
+
},
|
|
149
|
+
provenance: {
|
|
150
|
+
launcher: peel.launcher,
|
|
151
|
+
phase: 'acquire',
|
|
152
|
+
innerArgv: [...peel.acquisitionSpecs],
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function packageAcquisitionResources(specs) {
|
|
157
|
+
const resources = new Map();
|
|
158
|
+
for (const spec of specs) {
|
|
159
|
+
const source = classifyPackageAcquisitionSpec(spec);
|
|
160
|
+
if (source.kind === 'local') {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const resource = source.kind === 'registry'
|
|
164
|
+
? { kind: 'network', host: 'registry.npmjs.org', protocol: 'registry' }
|
|
165
|
+
: {
|
|
166
|
+
kind: 'network',
|
|
167
|
+
host: source.host,
|
|
168
|
+
...(source.port ? { port: source.port } : {}),
|
|
169
|
+
protocol: source.protocol,
|
|
170
|
+
};
|
|
171
|
+
resources.set(`${resource.host}:${resource.port ?? ''}:${resource.protocol ?? ''}`, resource);
|
|
172
|
+
}
|
|
173
|
+
return [...resources.values()];
|
|
174
|
+
}
|
|
175
|
+
export function collectRequirements(node) {
|
|
176
|
+
switch (node.kind) {
|
|
177
|
+
case 'exec':
|
|
178
|
+
return [...node.requirements];
|
|
179
|
+
case 'launcher':
|
|
180
|
+
return node.children.flatMap((child) => collectRequirements(child));
|
|
181
|
+
case 'merge':
|
|
182
|
+
return mergeRequirements(...node.children.map((child) => collectRequirements(child)));
|
|
183
|
+
default:
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
export function buildEffectPlan(params) {
|
|
188
|
+
const root = buildPackageExecEffectNode(params);
|
|
189
|
+
if (!root) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
const requirements = collectRequirements(root);
|
|
193
|
+
const signals = [
|
|
194
|
+
...new Set([
|
|
195
|
+
...(params.launcherResolution?.reason ? [params.launcherResolution.reason] : []),
|
|
196
|
+
...requirements.flatMap((r) => r.evidence.signals),
|
|
197
|
+
]),
|
|
198
|
+
];
|
|
199
|
+
const opacity = peelPackageExecArgv(params.tokens)?.opaque || params.launcherResolution?.opaque
|
|
200
|
+
? 'opaque'
|
|
201
|
+
: 'recursive';
|
|
202
|
+
return {
|
|
203
|
+
version: 1,
|
|
204
|
+
root,
|
|
205
|
+
inputFingerprint: params.inputFingerprint,
|
|
206
|
+
opacity,
|
|
207
|
+
disposition: requirements.length > 0 ? 'effects' : 'effect_free',
|
|
208
|
+
completeness: opacity === 'recursive' ? 'complete' : 'partial',
|
|
209
|
+
signals,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function effectTagForAction(action) {
|
|
213
|
+
return action === 'indeterminate' ? 'indeterminate' : action;
|
|
214
|
+
}
|
|
215
|
+
/** Build the canonical plan envelope for non-package-exec gated actions. */
|
|
216
|
+
export function buildCapabilityEffectPlan(params) {
|
|
217
|
+
const provenance = { segment: params.actionKind };
|
|
218
|
+
const requirements = params.requests.map((request) => ({
|
|
219
|
+
tag: effectTagForAction(request.action),
|
|
220
|
+
action: request.action,
|
|
221
|
+
resource: request.resource,
|
|
222
|
+
evidence: {
|
|
223
|
+
level: request.evidence.level,
|
|
224
|
+
signals: [...request.evidence.signals],
|
|
225
|
+
basis: [...request.context.analysisBasis],
|
|
226
|
+
},
|
|
227
|
+
provenance,
|
|
228
|
+
provenances: [provenance],
|
|
229
|
+
}));
|
|
230
|
+
if (!params.effectFree && requirements.length === 0) {
|
|
231
|
+
requirements.push({
|
|
232
|
+
tag: 'indeterminate',
|
|
233
|
+
action: 'indeterminate',
|
|
234
|
+
resource: { kind: 'unknown' },
|
|
235
|
+
evidence: {
|
|
236
|
+
level: 'indeterminate',
|
|
237
|
+
signals: ['effect_plan.incomplete'],
|
|
238
|
+
basis: [`gated_action:${params.actionKind}`],
|
|
239
|
+
},
|
|
240
|
+
provenance,
|
|
241
|
+
provenances: [provenance],
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
const partial = requirements.some((requirement) => requirement.evidence.level === 'indeterminate');
|
|
245
|
+
return {
|
|
246
|
+
version: 1,
|
|
247
|
+
root: {
|
|
248
|
+
kind: 'exec',
|
|
249
|
+
commandRedacted: params.summary,
|
|
250
|
+
segmentHead: params.actionKind,
|
|
251
|
+
requirements,
|
|
252
|
+
},
|
|
253
|
+
inputFingerprint: params.inputFingerprint,
|
|
254
|
+
opacity: partial ? 'opaque' : 'transparent',
|
|
255
|
+
disposition: params.effectFree ? 'effect_free' : 'effects',
|
|
256
|
+
completeness: partial ? 'partial' : 'complete',
|
|
257
|
+
signals: [...new Set(requirements.flatMap((requirement) => requirement.evidence.signals))],
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
export function flattenRequirementsToCapabilityRequests(requirements, opts) {
|
|
261
|
+
return requirements.map((req) => ({
|
|
262
|
+
version: 1,
|
|
263
|
+
principal: opts.principal,
|
|
264
|
+
action: req.action,
|
|
265
|
+
resource: req.resource,
|
|
266
|
+
context: {
|
|
267
|
+
hookKind: opts.hookKind,
|
|
268
|
+
cwd: opts.cwd,
|
|
269
|
+
inputFingerprint: opts.inputFingerprint,
|
|
270
|
+
analysisBasis: [...req.evidence.basis],
|
|
271
|
+
},
|
|
272
|
+
evidence: {
|
|
273
|
+
level: req.evidence.level,
|
|
274
|
+
signals: [...req.evidence.signals],
|
|
275
|
+
},
|
|
276
|
+
}));
|
|
277
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { effectPlanAuditFields, hashEffectPlan } from './audit.js';
|
|
2
|
+
export { buildCapabilityEffectPlan, buildEffectPlan, buildPackageExecEffectNode, collectRequirements, flattenRequirementsToCapabilityRequests, } from './build.js';
|
|
3
|
+
export { mergeEffectPlans, mergeRequirements, normalizeEffectTags } from './normalize.js';
|
|
4
|
+
export { innerRecipeFromPeel, isPackageExecLauncher, peelPackageExecArgv, resolveLocalBin, } from './package-exec.js';
|
|
5
|
+
export { evaluatePackageExecSegment } from './package-exec-eval.js';
|
|
6
|
+
export { capabilityRequestsFromEffectPlan, capabilityRequestsToEffectRequirements, effectPlanPolicyLegacyReason, effectPlanPolicyRequiresAsk, evaluateEffectPlanPolicy, } from './policy.js';
|
|
7
|
+
export type { EffectEvidence, EffectNode, EffectPlan, EffectProvenance, EffectRequirement, EffectTag, ExecEffectNode, LauncherEffectNode, LauncherPhase, MergeEffectNode, PackageExecLauncher, } from './types.js';
|
|
8
|
+
export { EFFECT_PLAN_VERSION } from './types.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { effectPlanAuditFields, hashEffectPlan } from './audit.js';
|
|
2
|
+
export { buildCapabilityEffectPlan, buildEffectPlan, buildPackageExecEffectNode, collectRequirements, flattenRequirementsToCapabilityRequests, } from './build.js';
|
|
3
|
+
export { mergeEffectPlans, mergeRequirements, normalizeEffectTags } from './normalize.js';
|
|
4
|
+
export { innerRecipeFromPeel, isPackageExecLauncher, peelPackageExecArgv, resolveLocalBin, } from './package-exec.js';
|
|
5
|
+
export { evaluatePackageExecSegment } from './package-exec-eval.js';
|
|
6
|
+
export { capabilityRequestsFromEffectPlan, capabilityRequestsToEffectRequirements, effectPlanPolicyLegacyReason, effectPlanPolicyRequiresAsk, evaluateEffectPlanPolicy, } from './policy.js';
|
|
7
|
+
export { EFFECT_PLAN_VERSION } from './types.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { EffectPlan, EffectRequirement, EffectTag } from './types.js';
|
|
2
|
+
export declare function normalizeEffectTags(tags: Iterable<EffectTag>): readonly EffectTag[];
|
|
3
|
+
export declare function mergeRequirements(...groups: readonly (readonly EffectRequirement[])[]): EffectRequirement[];
|
|
4
|
+
export declare function mergeEffectPlans(...plans: readonly (EffectPlan | null | undefined)[]): EffectPlan | undefined;
|