@guilz-dev/belay 0.6.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 +20 -1
- package/dist/adapters/claude/runtime-entry.js +54 -25
- package/dist/adapters/shared/gate-runtime.d.ts +7 -0
- package/dist/adapters/shared/gate-runtime.js +420 -220
- package/dist/bundle/claude-runtime.mjs +13215 -8864
- package/dist/bundle/codex-runtime.mjs +10771 -6453
- package/dist/bundle/cursor-runtime.mjs +10797 -6484
- package/dist/cli.js +37 -1
- package/dist/commands/approve.js +34 -10
- package/dist/commands/doctor.js +51 -0
- 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/status.js +7 -0
- package/dist/config-io.js +49 -18
- package/dist/conformance/guarantee-table.js +6 -0
- 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 +86 -27
- package/dist/core/approval.d.ts +2 -0
- package/dist/core/approval.js +6 -3
- package/dist/core/audit-types.d.ts +13 -0
- package/dist/core/capability/approval-state-mutation.d.ts +19 -0
- package/dist/core/capability/approval-state-mutation.js +76 -3
- package/dist/core/capability/approval-v3.d.ts +18 -1
- package/dist/core/capability/approval-v3.js +63 -23
- package/dist/core/capability/attestation.d.ts +3 -0
- package/dist/core/capability/attestation.js +7 -0
- package/dist/core/capability/boundary-driver-container.d.ts +12 -0
- package/dist/core/capability/boundary-driver-container.js +101 -34
- package/dist/core/capability/boundary-driver.js +1 -0
- package/dist/core/capability/boundary-grant-materialize.d.ts +1 -0
- package/dist/core/capability/boundary-grant-materialize.js +15 -0
- package/dist/core/capability/boundary-run.d.ts +25 -0
- package/dist/core/capability/boundary-run.js +37 -9
- package/dist/core/capability/boundary-session.d.ts +4 -0
- package/dist/core/capability/boundary-session.js +9 -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/gate-policy-shadow.js +23 -1
- 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 +36 -1
- package/dist/core/capability/grant-lease.js +213 -16
- package/dist/core/capability/grant-match.js +3 -0
- package/dist/core/capability/index.d.ts +1 -1
- package/dist/core/capability/index.js +1 -1
- package/dist/core/capability/policy-engine.d.ts +7 -0
- package/dist/core/capability/policy-engine.js +202 -15
- package/dist/core/capability/request.d.ts +3 -0
- package/dist/core/config.d.ts +20 -0
- package/dist/core/config.js +62 -0
- 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 +2 -0
- package/dist/core/gate-contract.js +2 -0
- package/dist/core/gate-engine.js +26 -9
- 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/network-endpoint.d.ts +10 -0
- package/dist/core/network-endpoint.js +51 -0
- 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/checkpoint.d.ts +25 -0
- package/dist/core/recovery/checkpoint.js +260 -0
- package/dist/core/recovery/index.d.ts +3 -1
- package/dist/core/recovery/index.js +2 -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 +85 -1
- 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/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 +9 -11
- package/dist/core/transactional/git-worktree.js +24 -119
- package/dist/core/transactional/index.d.ts +11 -0
- package/dist/core/transactional/index.js +10 -0
- package/dist/core/transactional/reasons.js +1 -0
- package/dist/core/transactional/runner.js +157 -25
- 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 +17 -1
- package/dist/core/types.d.ts +10 -1
- package/dist/core/verdict/adapter.js +8 -0
- package/dist/core/verdict/launcher-resolve.js +2 -20
- package/dist/core/verdict/shell-policy.d.ts +1 -0
- package/dist/core/verdict/shell-policy.js +1 -1
- package/dist/core/verdict/types.d.ts +5 -0
- package/dist/core/verdict/verdict.js +37 -20
- package/dist/types.d.ts +11 -0
- 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/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ import { formatHarvestReport, harvestApplyProject, harvestListProject } from './
|
|
|
10
10
|
import { formatMetricsReport, metricsProject } from './commands/metrics.js';
|
|
11
11
|
import { formatQualityReport, qualityCheck } from './commands/quality.js';
|
|
12
12
|
import { formatRecoverReport, recoverProject } from './commands/recover.js';
|
|
13
|
+
import { formatRecoveryCheckpointResult, recoveryCheckpointCommand, } from './commands/recovery-checkpoints.js';
|
|
13
14
|
import { formatReport, reportProject } from './commands/report.js';
|
|
14
15
|
import { revokeApproval } from './commands/revoke.js';
|
|
15
16
|
import { formatSessionStatusReport, sessionStartProject, sessionStatusProject, } from './commands/session.js';
|
|
@@ -433,6 +434,23 @@ function parseArgs(argv) {
|
|
|
433
434
|
}
|
|
434
435
|
throw new Error('harvest requires subcommand: list or apply');
|
|
435
436
|
}
|
|
437
|
+
if (command === 'recover' && !options.recoverSubcommand) {
|
|
438
|
+
if (token === 'advice' ||
|
|
439
|
+
token === 'status' ||
|
|
440
|
+
token === 'list' ||
|
|
441
|
+
token === 'show' ||
|
|
442
|
+
token === 'apply') {
|
|
443
|
+
options.recoverSubcommand = token;
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
throw new Error('recover requires subcommand: advice, status, list, show, or apply');
|
|
447
|
+
}
|
|
448
|
+
if (command === 'recover' &&
|
|
449
|
+
(options.recoverSubcommand === 'show' || options.recoverSubcommand === 'apply') &&
|
|
450
|
+
!options.recoverCheckpointId) {
|
|
451
|
+
options.recoverCheckpointId = token;
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
436
454
|
if (command === 'judge' && !options.judgeSubcommand) {
|
|
437
455
|
if (token === 'status' ||
|
|
438
456
|
token === 'list' ||
|
|
@@ -527,8 +545,10 @@ Usage:
|
|
|
527
545
|
${c} metrics [--target <dir>] [--json]
|
|
528
546
|
${c} quality [--target <dir>] [--corpus <path>] [--json]
|
|
529
547
|
${c} report [--target <dir>] [--since <iso>] [--until <iso>] [--limit <n>] [--json]
|
|
530
|
-
${c} recover [--target <dir>] [--since <iso>] [--fingerprint <fp>] [--command "<text>"] [--limit <n>] [--json]
|
|
548
|
+
${c} recover [advice] [--target <dir>] [--since <iso>] [--fingerprint <fp>] [--command "<text>"] [--limit <n>] [--json]
|
|
531
549
|
(--limit picks the Nth recover candidate after priority ranking: local_mutation first, then recency; 1 = highest priority, default 1)
|
|
550
|
+
${c} recover <status|list> [--target <dir>] [--json]
|
|
551
|
+
${c} recover <show|apply> <checkpoint-id> [--target <dir>] [--json]
|
|
532
552
|
${c} audit <query|summarize|replay> [--target <dir>] [--json] [--since <iso>] [--until <iso>] [--verdict <v>] [--reason <r>] [--kind <k>] [--fingerprint <fp>] [--event <e>] [--location <v>] [--opacity <v>] [--effect <v>] [--confidence <v>] [--limit <n>] [--config <path>]
|
|
533
553
|
${c} simulate --config <path> [--target <dir>] [--json]
|
|
534
554
|
${c} status [--target <dir>] [--json]
|
|
@@ -825,6 +845,22 @@ async function main() {
|
|
|
825
845
|
throw new Error('harvest requires subcommand: list or apply');
|
|
826
846
|
}
|
|
827
847
|
if (command === 'recover') {
|
|
848
|
+
if (options.recoverSubcommand && options.recoverSubcommand !== 'advice') {
|
|
849
|
+
const result = await recoveryCheckpointCommand({
|
|
850
|
+
targetDir: options.targetDir,
|
|
851
|
+
subcommand: options.recoverSubcommand,
|
|
852
|
+
checkpointId: options.recoverCheckpointId,
|
|
853
|
+
});
|
|
854
|
+
if (options.json) {
|
|
855
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
856
|
+
}
|
|
857
|
+
else {
|
|
858
|
+
process.stdout.write(formatRecoveryCheckpointResult(result));
|
|
859
|
+
}
|
|
860
|
+
if (!result.ok)
|
|
861
|
+
process.exitCode = 2;
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
828
864
|
const report = await recoverProject({
|
|
829
865
|
targetDir: options.targetDir,
|
|
830
866
|
since: options.since,
|
package/dist/commands/approve.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { loadApprovalState, loadConfigFile } from '../config-io.js';
|
|
3
|
-
import { canAutoReplay, getExecutionLeaseMs
|
|
4
|
-
import {
|
|
3
|
+
import { canAutoReplay, getExecutionLeaseMs } from '../core/approval-replay.js';
|
|
4
|
+
import { claimApprovedForReplay, createGateApprovalStore, recordApproval, } from '../core/approval-service.js';
|
|
5
|
+
import { runBoundaryAgentCommand } from '../core/capability/boundary-session.js';
|
|
5
6
|
import { JUDGE_CLOUD_CONSENT_REASON } from '../core/capability/reasons.js';
|
|
6
7
|
import { recordCapabilityApproval } from '../core/capability-approval.js';
|
|
7
8
|
import { recordEgressApproval } from '../core/egress-approval.js';
|
|
9
|
+
import { RECOVERY_RESTORE_REASON } from '../core/recovery/checkpoint.js';
|
|
8
10
|
import { createEgressApprovalStore } from '../services/egress-service.js';
|
|
9
11
|
import { createCapabilityApprovalStore } from '../services/sandbox-service.js';
|
|
10
12
|
export async function approvePending(options) {
|
|
@@ -12,6 +14,19 @@ export async function approvePending(options) {
|
|
|
12
14
|
const config = await loadConfigFile(repoRoot);
|
|
13
15
|
const pending = await loadApprovalState(repoRoot, 'pending-approvals.json', config);
|
|
14
16
|
const match = pending.approvals.find((approval) => approval.approvalId === options.approvalId);
|
|
17
|
+
if (match?.reason === RECOVERY_RESTORE_REASON) {
|
|
18
|
+
if (options.scope && options.scope !== 'once') {
|
|
19
|
+
return { ok: false, message: 'Recovery restore approvals support one-shot scope only.' };
|
|
20
|
+
}
|
|
21
|
+
const result = await recordApproval({
|
|
22
|
+
approvalId: options.approvalId,
|
|
23
|
+
config,
|
|
24
|
+
token: options.token,
|
|
25
|
+
requireSignedToken: true,
|
|
26
|
+
store: createGateApprovalStore(repoRoot, config),
|
|
27
|
+
});
|
|
28
|
+
return { ok: result.ok, message: result.message };
|
|
29
|
+
}
|
|
15
30
|
if (match?.reason === JUDGE_CLOUD_CONSENT_REASON) {
|
|
16
31
|
const result = await recordCapabilityApproval({
|
|
17
32
|
approvalId: options.approvalId,
|
|
@@ -73,22 +88,31 @@ export async function approvePending(options) {
|
|
|
73
88
|
message: 'CLI replay is only supported for shell approvals. Retry the original tool or subagent action manually.',
|
|
74
89
|
};
|
|
75
90
|
}
|
|
76
|
-
const
|
|
77
|
-
|
|
91
|
+
const claimed = await claimApprovedForReplay({
|
|
92
|
+
approvalId: options.approvalId,
|
|
93
|
+
store: approvalStore,
|
|
94
|
+
});
|
|
95
|
+
if (!claimed) {
|
|
96
|
+
return { ok: false, message: 'Approval could not be claimed for replay.' };
|
|
97
|
+
}
|
|
98
|
+
const replayResult = await runBoundaryAgentCommand({
|
|
99
|
+
repoRoot,
|
|
100
|
+
config,
|
|
101
|
+
command: claimed.input ?? approval.input,
|
|
102
|
+
cwd: claimed.cwd ?? repoRoot,
|
|
103
|
+
timeoutMs: getExecutionLeaseMs(config),
|
|
104
|
+
runOptions: { mountReadOnly: false },
|
|
105
|
+
});
|
|
78
106
|
if (replayResult.exitCode === 0) {
|
|
79
|
-
await consumeApprovedAfterCliReplay({
|
|
80
|
-
approvalId: options.approvalId,
|
|
81
|
-
store: approvalStore,
|
|
82
|
-
});
|
|
83
107
|
return {
|
|
84
108
|
ok: true,
|
|
85
|
-
message: `Belay replay succeeded for ${options.approvalId}. Do not retry via hooks; the one-shot grant was consumed
|
|
109
|
+
message: `Belay replay succeeded for ${options.approvalId}. Do not retry via hooks; the one-shot grant was consumed.`,
|
|
86
110
|
};
|
|
87
111
|
}
|
|
88
112
|
const timeoutNote = replayResult.timedOut ? ' Replay timed out.' : '';
|
|
89
113
|
return {
|
|
90
114
|
ok: false,
|
|
91
|
-
message: `Belay replay failed for ${options.approvalId} (exit ${replayResult.exitCode}).${timeoutNote}
|
|
115
|
+
message: `Belay replay failed for ${options.approvalId} (exit ${replayResult.exitCode}).${timeoutNote} The one-shot approval was consumed before replay and was not re-armed.`,
|
|
92
116
|
};
|
|
93
117
|
}
|
|
94
118
|
return { ok: result.ok, message: result.message };
|
package/dist/commands/doctor.js
CHANGED
|
@@ -7,6 +7,7 @@ import { getAdapterLayout } from '../adapters/layouts/index.js';
|
|
|
7
7
|
import { resolveScopedPaths } from '../adapters/layouts/scope.js';
|
|
8
8
|
import { cleanupOrphanApprovalState } from '../cleanup-orphans.js';
|
|
9
9
|
import { approvedApprovalsPath, belayStateDir, detectAdapterName, loadLayeredConfig, pendingApprovalsPath, repoLocalStateDirFor, } from '../config-io.js';
|
|
10
|
+
import { approvalSigningKeyPath } from '../core/approval-token.js';
|
|
10
11
|
import { detectFenceDrift, summarizeAuditVisibility } from '../core/audit-summary.js';
|
|
11
12
|
import { inspectBoundaryAttestationFile } from '../core/capability/boundary-attestation-sign.js';
|
|
12
13
|
import { boundaryAttestationPath, boundarySessionStatus, } from '../core/capability/boundary-session.js';
|
|
@@ -14,6 +15,9 @@ import { defaultControlPlaneDir } from '../core/config.js';
|
|
|
14
15
|
import { verifyIntegrityManifest } from '../core/integrity.js';
|
|
15
16
|
import { diagnoseJudge, stopJudgeSessionBrokers } from '../core/judge-doctor.js';
|
|
16
17
|
import { resolveJudgeTransport } from '../core/judge-runtime-detection.js';
|
|
18
|
+
import { listRecoveryCheckpoints } from '../core/recovery/checkpoint.js';
|
|
19
|
+
import { recoveryApprovalSetupNotes, recoveryNotificationConfigured, recoveryNotificationSetupWarning, summarizeRecoveryCheckpointDiagnostics, } from '../core/recovery/operator-guidance.js';
|
|
20
|
+
import { probeFileCloneStrategy } from '../core/transactional/file-clone.js';
|
|
17
21
|
import { getManagedHookEntries } from '../defaults.js';
|
|
18
22
|
import { resolveNodeBinary } from '../node-resolution.js';
|
|
19
23
|
import { egressStatus } from '../services/egress-service.js';
|
|
@@ -290,6 +294,45 @@ export async function doctorProject(options = {}) {
|
|
|
290
294
|
warnings.push('Transactional execution is enabled but this directory is not a git repository. Transactional worktrees will be skipped until git is available.');
|
|
291
295
|
}
|
|
292
296
|
}
|
|
297
|
+
const fileCheckpoint = loadedConfig.policy.transactional.fileCheckpoint;
|
|
298
|
+
if (fileCheckpoint.enabled) {
|
|
299
|
+
const copyStrategy = await probeFileCloneStrategy();
|
|
300
|
+
notes.push(`File checkpoint: enabled (copyStrategy=${copyStrategy}, non-Git=${fileCheckpoint.allowNonGit}, maxFiles=${fileCheckpoint.maxFiles}, maxSourceBytes=${fileCheckpoint.maxSourceBytes}, maxWorkspaceBytes=${fileCheckpoint.maxWorkspaceBytes}, prepareTimeoutMs=${fileCheckpoint.prepareTimeoutMs}, copyConcurrency=${fileCheckpoint.copyConcurrency}).`);
|
|
301
|
+
if (!loadedConfig.policy.transactional.enabled) {
|
|
302
|
+
warnings.push('File checkpoint is enabled but transactional execution is disabled; dirty Git workspaces cannot use the backend.');
|
|
303
|
+
}
|
|
304
|
+
if (!loadedConfig.policy.transactional.checkpoint?.enabled) {
|
|
305
|
+
warnings.push('File checkpoint is enabled but durable Recovery checkpointing is disabled; backend selection will fail closed.');
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (loadedConfig.policy.transactional.checkpoint?.enabled) {
|
|
309
|
+
notes.push('Recovery checkpoint: enabled — repo-local pre-images are persisted before observed-safe transactional apply.');
|
|
310
|
+
notes.push(...recoveryApprovalSetupNotes());
|
|
311
|
+
if (!recoveryNotificationConfigured(loadedConfig)) {
|
|
312
|
+
warnings.push(recoveryNotificationSetupWarning());
|
|
313
|
+
}
|
|
314
|
+
const signingKeyPath = approvalSigningKeyPath(loadedConfig.controlPlane.enabled
|
|
315
|
+
? belayStateDir(loadedConfig, repoLocalDir)
|
|
316
|
+
: (loadedConfig.controlPlane.configDir ?? defaultControlPlaneDir()));
|
|
317
|
+
if (!existsSync(signingKeyPath)) {
|
|
318
|
+
notes.push(`Approval signing key not yet created at ${signingKeyPath}; it will be generated on the first signed recovery approval request.`);
|
|
319
|
+
}
|
|
320
|
+
if (!loadedConfig.policy.transactional.enabled) {
|
|
321
|
+
warnings.push('Recovery checkpoint is enabled but transactional execution is disabled; checkpoints will not be created until transactional execution is enabled.');
|
|
322
|
+
}
|
|
323
|
+
try {
|
|
324
|
+
const stateDir = belayStateDir(loadedConfig, repoLocalDir);
|
|
325
|
+
const checkpoints = await listRecoveryCheckpoints(stateDir, repoRoot);
|
|
326
|
+
if (checkpoints.length > 0) {
|
|
327
|
+
notes.push(`Recovery checkpoints in this repository: ${checkpoints.length}.`);
|
|
328
|
+
}
|
|
329
|
+
const advisories = summarizeRecoveryCheckpointDiagnostics(checkpoints);
|
|
330
|
+
warnings.push(...advisories);
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// Checkpoint inspection is advisory only.
|
|
334
|
+
}
|
|
335
|
+
}
|
|
293
336
|
if (loadedConfig.sandbox.enabled) {
|
|
294
337
|
const sandbox = await sandboxStatus({ targetDir: repoRoot });
|
|
295
338
|
notes.push(`Sandbox capability broker: enabled (runtime=${loadedConfig.sandbox.runtime}, fs-scope entries=${sandbox.fsScopeAllowlistCount}, full-isolation=${sandbox.l1FullActive}).`);
|
|
@@ -305,6 +348,10 @@ export async function doctorProject(options = {}) {
|
|
|
305
348
|
}
|
|
306
349
|
const boundaryDriver = loadedConfig.capability?.boundaryDriver ??
|
|
307
350
|
(loadedConfig.sandbox.runtime === 'container' ? 'container' : null);
|
|
351
|
+
if (loadedConfig.policy.transactional.fileCheckpoint.enabled &&
|
|
352
|
+
boundaryDriver !== 'container') {
|
|
353
|
+
warnings.push('File checkpoint requires an attested workspace-isolating boundary driver; configure the container boundary and run belay session start.');
|
|
354
|
+
}
|
|
308
355
|
if (loadedConfig.capability || boundaryDriver === 'container') {
|
|
309
356
|
const attestationPath = boundaryAttestationPath(repoRoot, loadedConfig);
|
|
310
357
|
const attestationFormat = await inspectBoundaryAttestationFile(attestationPath);
|
|
@@ -323,6 +370,10 @@ export async function doctorProject(options = {}) {
|
|
|
323
370
|
else if (!session.fresh) {
|
|
324
371
|
warnings.push('Boundary attestation is stale or expired. Run belay session start to refresh.');
|
|
325
372
|
}
|
|
373
|
+
else if (loadedConfig.policy.transactional.fileCheckpoint.enabled &&
|
|
374
|
+
session.attestation.isolatesWorkspaceMounts !== true) {
|
|
375
|
+
warnings.push('File checkpoint is enabled but the fresh boundary attestation does not prove workspace-mount isolation. Run belay session start with a compatible boundary.');
|
|
376
|
+
}
|
|
326
377
|
else if (session.attestation.probeSignals.includes('repo-mount-ro-default')) {
|
|
327
378
|
notes.push('Container boundary defaults to read-only directory mounts; predicted writes use read-write mounts for the working directory only.');
|
|
328
379
|
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
export type RecoveryCheckpointSubcommand = 'status' | 'list' | 'show' | 'apply';
|
|
2
|
+
export declare function recoveryCheckpointCommand(options: {
|
|
3
|
+
targetDir?: string;
|
|
4
|
+
subcommand: RecoveryCheckpointSubcommand;
|
|
5
|
+
checkpointId?: string;
|
|
6
|
+
}): Promise<{
|
|
7
|
+
ok: boolean;
|
|
8
|
+
subcommand: string;
|
|
9
|
+
repoRoot: string;
|
|
10
|
+
backend: string;
|
|
11
|
+
availableBackends: string[];
|
|
12
|
+
backendCounts: {
|
|
13
|
+
[k: string]: number;
|
|
14
|
+
};
|
|
15
|
+
fileCheckpoint: {
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
allowNonGit: boolean;
|
|
18
|
+
isolation: string | null;
|
|
19
|
+
copyStrategy: import("../core/transactional/file-clone.js").FileCloneStrategy | undefined;
|
|
20
|
+
probe: string;
|
|
21
|
+
};
|
|
22
|
+
enabled: boolean;
|
|
23
|
+
checkpointCount: number;
|
|
24
|
+
storageBytes: number;
|
|
25
|
+
recoverableCount: number;
|
|
26
|
+
needsManualRepairCount: number;
|
|
27
|
+
verifiedReceiptCount: number;
|
|
28
|
+
states: {
|
|
29
|
+
[k: string]: number;
|
|
30
|
+
};
|
|
31
|
+
advisories: string[];
|
|
32
|
+
limits: {
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
appliedRetentionHours: number;
|
|
35
|
+
restoredRetentionHours: number;
|
|
36
|
+
maxCheckpoints: number;
|
|
37
|
+
maxBytes: number;
|
|
38
|
+
};
|
|
39
|
+
checkpoints?: undefined;
|
|
40
|
+
manifest?: undefined;
|
|
41
|
+
state?: undefined;
|
|
42
|
+
manifestHash?: undefined;
|
|
43
|
+
receipt?: undefined;
|
|
44
|
+
verdict?: undefined;
|
|
45
|
+
checkpointId?: undefined;
|
|
46
|
+
approvalId?: undefined;
|
|
47
|
+
paths?: undefined;
|
|
48
|
+
auditRecorded?: undefined;
|
|
49
|
+
message?: undefined;
|
|
50
|
+
} | {
|
|
51
|
+
ok: boolean;
|
|
52
|
+
subcommand: string;
|
|
53
|
+
repoRoot: string;
|
|
54
|
+
checkpoints: import("../core/index.js").RecoveryCheckpointSummary[];
|
|
55
|
+
backend?: undefined;
|
|
56
|
+
availableBackends?: undefined;
|
|
57
|
+
backendCounts?: undefined;
|
|
58
|
+
fileCheckpoint?: undefined;
|
|
59
|
+
enabled?: undefined;
|
|
60
|
+
checkpointCount?: undefined;
|
|
61
|
+
storageBytes?: undefined;
|
|
62
|
+
recoverableCount?: undefined;
|
|
63
|
+
needsManualRepairCount?: undefined;
|
|
64
|
+
verifiedReceiptCount?: undefined;
|
|
65
|
+
states?: undefined;
|
|
66
|
+
advisories?: undefined;
|
|
67
|
+
limits?: undefined;
|
|
68
|
+
manifest?: undefined;
|
|
69
|
+
state?: undefined;
|
|
70
|
+
manifestHash?: undefined;
|
|
71
|
+
receipt?: undefined;
|
|
72
|
+
verdict?: undefined;
|
|
73
|
+
checkpointId?: undefined;
|
|
74
|
+
approvalId?: undefined;
|
|
75
|
+
paths?: undefined;
|
|
76
|
+
auditRecorded?: undefined;
|
|
77
|
+
message?: undefined;
|
|
78
|
+
} | {
|
|
79
|
+
ok: boolean;
|
|
80
|
+
subcommand: string;
|
|
81
|
+
manifest: import("../core/index.js").RecoveryCheckpointManifest;
|
|
82
|
+
state: import("../core/recovery/types.js").RecoveryCheckpointStateV1;
|
|
83
|
+
manifestHash: string;
|
|
84
|
+
receipt: import("../core/index.js").RecoveryReceiptV1 | undefined;
|
|
85
|
+
repoRoot?: undefined;
|
|
86
|
+
backend?: undefined;
|
|
87
|
+
availableBackends?: undefined;
|
|
88
|
+
backendCounts?: undefined;
|
|
89
|
+
fileCheckpoint?: undefined;
|
|
90
|
+
enabled?: undefined;
|
|
91
|
+
checkpointCount?: undefined;
|
|
92
|
+
storageBytes?: undefined;
|
|
93
|
+
recoverableCount?: undefined;
|
|
94
|
+
needsManualRepairCount?: undefined;
|
|
95
|
+
verifiedReceiptCount?: undefined;
|
|
96
|
+
states?: undefined;
|
|
97
|
+
advisories?: undefined;
|
|
98
|
+
limits?: undefined;
|
|
99
|
+
checkpoints?: undefined;
|
|
100
|
+
verdict?: undefined;
|
|
101
|
+
checkpointId?: undefined;
|
|
102
|
+
approvalId?: undefined;
|
|
103
|
+
paths?: undefined;
|
|
104
|
+
auditRecorded?: undefined;
|
|
105
|
+
message?: undefined;
|
|
106
|
+
} | {
|
|
107
|
+
ok: boolean;
|
|
108
|
+
subcommand: string;
|
|
109
|
+
verdict: string;
|
|
110
|
+
checkpointId: string;
|
|
111
|
+
approvalId: string;
|
|
112
|
+
manifestHash: string;
|
|
113
|
+
paths: string[];
|
|
114
|
+
auditRecorded: boolean;
|
|
115
|
+
message: string;
|
|
116
|
+
repoRoot?: undefined;
|
|
117
|
+
backend?: undefined;
|
|
118
|
+
availableBackends?: undefined;
|
|
119
|
+
backendCounts?: undefined;
|
|
120
|
+
fileCheckpoint?: undefined;
|
|
121
|
+
enabled?: undefined;
|
|
122
|
+
checkpointCount?: undefined;
|
|
123
|
+
storageBytes?: undefined;
|
|
124
|
+
recoverableCount?: undefined;
|
|
125
|
+
needsManualRepairCount?: undefined;
|
|
126
|
+
verifiedReceiptCount?: undefined;
|
|
127
|
+
states?: undefined;
|
|
128
|
+
advisories?: undefined;
|
|
129
|
+
limits?: undefined;
|
|
130
|
+
checkpoints?: undefined;
|
|
131
|
+
manifest?: undefined;
|
|
132
|
+
state?: undefined;
|
|
133
|
+
receipt?: undefined;
|
|
134
|
+
} | {
|
|
135
|
+
auditRecorded: boolean;
|
|
136
|
+
message: string;
|
|
137
|
+
manifestHash: string;
|
|
138
|
+
changeCount: number;
|
|
139
|
+
ok: boolean;
|
|
140
|
+
subcommand: string;
|
|
141
|
+
verdict: string;
|
|
142
|
+
checkpointId: string;
|
|
143
|
+
repoRoot?: undefined;
|
|
144
|
+
backend?: undefined;
|
|
145
|
+
availableBackends?: undefined;
|
|
146
|
+
backendCounts?: undefined;
|
|
147
|
+
fileCheckpoint?: undefined;
|
|
148
|
+
enabled?: undefined;
|
|
149
|
+
checkpointCount?: undefined;
|
|
150
|
+
storageBytes?: undefined;
|
|
151
|
+
recoverableCount?: undefined;
|
|
152
|
+
needsManualRepairCount?: undefined;
|
|
153
|
+
verifiedReceiptCount?: undefined;
|
|
154
|
+
states?: undefined;
|
|
155
|
+
advisories?: undefined;
|
|
156
|
+
limits?: undefined;
|
|
157
|
+
checkpoints?: undefined;
|
|
158
|
+
manifest?: undefined;
|
|
159
|
+
state?: undefined;
|
|
160
|
+
receipt?: undefined;
|
|
161
|
+
approvalId?: undefined;
|
|
162
|
+
paths?: undefined;
|
|
163
|
+
}>;
|
|
164
|
+
export declare function formatRecoveryCheckpointResult(result: Record<string, unknown>): string;
|