ops-warden/docs/security-case-execution-proposal.md

137 lines
7.9 KiB
Markdown
Raw Normal View History

# SecurityCase execution contract proposal — 2026-10-10
Status: proposed owner review; not an accepted runtime protocol or authority.
Owner: ops-warden. Related: WARDEN-WP-0044-T03, NK-WP-0048, MASON-WP-0010.
`warden case plan` now gives a valid descriptive run, but the type's
`entry_point`, `auth`, verification `check` and rollback `action` fields are
prose. No `warden case run` or `rollback` implementation exists. A case becoming
`materialized` cannot turn those descriptions into executable commands.
The proposal preserves caller authority and routes by owner. It introduces no
new credential, policy grant, shell command inferred from prose, or authority
for Warden to configure a consumer. Architectural contract acceptance belongs to
net-kingdom and adapter interfaces to their owners. Founder review is needed
only if the acknowledged type's authorization/session boundary changes; the
current absence of a machine contract is not an excuse to fabricate one.
## Proposed machine seam
Keep human descriptions. Add a separately validated `execution` reference to
steps and checks, resolving to owner-provided closed adapters. An adapter has:
- immutable reference (owner repo, interface id, version, source digest);
- closed parameter schema (no secret-sensitivity fields; no free shell text);
- declared actor mode and catalog lane, which must agree with the case plan;
- explicit side-effect class and target identifier deriving from case parameters;
- idempotency/reconciliation contract and metadata-only receipt schema;
- supported rollback reference or explicit owner-only undo.
Warden does not invent an argv contract for ExternalSecrets, group membership,
KeyCape registration or Forgejo configuration. Owner adapters may internally
call their reviewed tools. Warden invokes only the fixed entry point provided by
that adapter, with validated separate argv fields, and refuses unknown adapters
or templates. `entry_point` prose never goes to `shell=True` or `sh -c`.
An owner may initially supply a receipt-only adapter: the run sheet records that
step as pending until the owner performs it and provides independent evidence.
This gives useful resumable orchestration before every live adapter exists,
without implying native completion or transferring ownership.
## Run sheet and receipts
The run sheet pins exact case bytes (`case-ref`), accepted type bytes/version,
owner adapter digests, catalog revision, acceptance reference and ordered step
identities. Changed pins require a newly reviewed sheet; never inherit previous
success into a different exact revision without explicit reconciliation.
Each attempt yields an immutable metadata receipt containing these pins, step
id, owner, target, attempt id, result enum and evidence-reference fingerprints.
Allowed results: pending-owner, not-started, running, verified-success,
verified-no-change, failed-before-change, failed-after-change, uncertain.
Neither subprocess output nor arbitrary owner payload is copied into receipts.
Adapter error strings are not evidence and must not be logged verbatim.
Stop on failure or uncertainty. A thrown exception or lost process receipt is
uncertain, not failed-before-change. Uncertain/failed-after-change blocks retry
until the owner reconciles target state. `verified-success` and
`verified-no-change` are not repeated. Retry after failed-before-change requires
the same pins and adapter's explicit retry-safe classification; a replay-safe
CAS0 receipt is reconciled, not retried into secret generation. State persistence
must write running before dispatch and result afterwards; interruption between
those writes leaves uncertain on resume. Outbox failures remain visible and do
not get rewritten as verified audit delivery.
Owner receipt ingestion must authenticate provenance or be explicitly manual
attended evidence, never a bare trusted JSON argument. Source/local receipts are
attributive preparation until their owner contract defines independent native
verification. Overall native completion requires every applicable step and
verification plus confirmed session revocation; pending-owner is never success.
## Sessions, values and rollback
Reuse `proxy_attended_login_exec` containment/output suppression/revocation
rather than add a second login helper. A key-cape login lane and the OpenBao
broker issuer role are distinct grants; the executor must represent both and
never silently share/inherit a token. Grouping is permitted only within the
same declared identity/lane and preserves follow-through order. An agent
principal cannot dispatch generated-in-custody mint-secret. The broker continues
to rederive the exact case-ref independently.
Rollback traverses successful step receipts in reverse order and only invokes
an owner's reviewed undo for target changes that receipt proves were created
by this case. Existing shared groups, membership and policies cannot be deleted
by interpreting a type rollback sentence literally. 'No change' yields no undo;
failed/uncertain states require reconciliation first. Do not restore a prior
secret value by extracting it into Warden; custody rollback is owner-native.
## Owner acceptance requests to prepare
1. net-kingdom: accept the closed machine seam separately from descriptive type
fields, document materialized = structural acceptance, and avoid gating that
state on mint-secret which is itself a follow-through step. Pin the revised
schema/type and keep type acceptance provenance explicit.
2. railiance-platform: provide a generate adapter over existing `credential.py`
exact `--grant`, `--client-id`, `--case-file`, `--case-ref` and receipt result
codes; clarify reconcile semantics for already-present CAS0 and grant/session
revocation evidence. No new credential is required by this proposal.
3. key-cape/net-kingdom: provide registration/group/env adapters and verify/undo
contracts in the existing attended boundary; do not hand Warden a user-engine
runtime token or a new broad Kubernetes credential.
4. railiance-apps/Forgejo: provide consumer OIDC + groups enforcement adapter or
receipt-only step, exact auth binding for CCR-2026-0042, and source/native
group-denial verification. This stays consumer ownership.
5. ops-mason: give a hash-pinned materialization receipt and list of objects
created vs pre-existing, sufficient for collision checks and scoped rollback.
No coordination messages have been sent by preparation of this proposal.
## Implementation and verification after owner seam acceptance
Implement `case_run.py` with injected typed adapters and receipt storage, then
CLI run-sheet/receipt import/resume/rollback commands. Keep case_plan read-only.
Add type machine-seam validation without turning valid descriptive planning
into an unreviewed source-breaking schema migration.
Required tests: rejected changed pins; unaccepted/unmaterialized cases; unsupported
adapter/argv refusal; agent mint refusal; pending owner keeps native gate open;
verified success never replayed; lost receipt resumes as uncertain; crash after
running persistence prevents duplicate side effect; failed-before-change retries
only with declared retry-safe adapter; failed-after-change needs owner reconcile;
malicious/secret output excluded; inability to revoke remains unverified;
rollback visits created successful objects only, preserves shared memberships,
and stops on uncertain undo. Inject runners; no live login or target required.
WARDEN-WP-0044-T03 remains open. This packet resolves the precise source contract
deficit; it is not case materialization, a native run, or a type decision.
## Local reducer prototype
`src/warden/case_receipt_state.py` is proposed local source preparation, not an
accepted wire format. Its pure immutable transitions can be tested without any
owner adapter or shell dispatch. Persist the returned running intent before an
external side effect; on a lost result, recover marks uncertainty and blocks
replay. No receipt provenance, durable storage, CLI dispatch or live action is
implemented. `tests/test_case_receipt_state.py` covers the failure boundaries.