Fail closed dry-run action execution

This commit is contained in:
rcourtman
2026-05-05 09:22:04 +01:00
parent 53a928ee2d
commit d91c2afedb
12 changed files with 323 additions and 7 deletions
@@ -137,7 +137,9 @@ implicit command execution or define a parallel execution handoff. When a
planned resource capability is actually executed from an agent-lifecycle
surface, that handoff must route through `POST /api/actions/{id}/execute` so
the API-owned action audit records `executing` before dispatch and the
terminal execution result afterward.
terminal execution result afterward. Dry-run-only plans remain planning evidence
only; lifecycle surfaces must not present them as executable, dispatch them
through agent-local command paths, or bypass the API fail-closed execution gate.
The node setup modal boundary must keep guided setup and manual credential
submission separate. For new PVE/PBS setup, Agent Install and Direct Connection
@@ -309,11 +309,13 @@ the canonical monitored-system blocked payload.
requires a later explicit execution contract.
Action execution is API-owned as the next explicit contract:
`POST /api/actions/{id}/execute` may only start execution for an approved
action or an approval-free allowed plan, must atomically persist the
action or an approval-free executable plan, must atomically persist the
`executing` lifecycle state before invoking a registered executor, and must
atomically persist the terminal `completed` or `failed` result afterward.
If no API executor is registered, the endpoint must fail closed without
mutating the approved audit record or appending execution lifecycle events.
Dry-run-only plans are not executable plans and must fail closed before any
`executing` mutation. If no API executor is registered, the endpoint must
fail closed without mutating the approved audit record or appending execution
lifecycle events.
Approval must never imply execution, and local UI, CLI, MCP, agent, or
storage/recovery adapters must not bypass this endpoint with a parallel
execution transport.
@@ -112,7 +112,10 @@ without executing the underlying capability. Any storage/recovery execution
handoff for the approved action must route through
`POST /api/actions/{id}/execute` so the API-owned action audit records
`executing` before dispatch and the terminal result afterward instead of
creating storage-local action transport.
creating storage-local action transport. Dry-run-only plans remain planning
evidence only; storage and recovery surfaces must not present them as
executable, dispatch them through provider-local restore/remediation paths, or
bypass the API fail-closed execution gate.
1. Add or change recovery-point persistence, rollups, or series derivation through `internal/recovery/`
2. Add or change recovery page UX through `frontend-modern/src/components/Recovery/` and keep canonical route/query/filter state ownership in `frontend-modern/src/features/recovery/useRecoverySurfaceState.ts`
@@ -478,7 +478,9 @@ the current audit record and append the lifecycle event atomically without
creating execution results or accepting stale second decisions.
Action execution now follows that same resource-owned state machine:
`BeginActionExecution` may transition only an approved action, or an
approval-free allowed plan, into `executing`; `CompleteActionExecution` may
approval-free allowed plan that is not `ApprovalDryRun`, into `executing`;
dry-run-only plans may remain audited planning evidence, but must fail closed
before any `executing` lifecycle mutation. `CompleteActionExecution` may
transition only an executing record into `completed` or `failed` with an
explicit `ExecutionResult`. `RecordActionExecutionStart` and
`RecordActionExecutionResult` must perform the audit update and lifecycle