Skip to content

Add approval binding and replay-protection tests #6

@SSBrouhard

Description

@SSBrouhard

Goal

Finish residual approval binding and replay-protection hardening after the v0.2.1 fixes.

Status update

This issue is partially resolved on main as of v0.2.1. Already landed; do not redo:

  • Single-process concurrent approval replay is closed via the adapter _state_lock over propose, approve, execute, and reset.
  • Single-use enforcement marks approvals used after successful execution; replay returns vmga_approval_already_used.
  • Integrity binding uses proposal_hash plus binding_hash over proposal fields and expiry; mismatches deny.
  • HMAC approval tokens bind to proposal_id:proposal_hash:approver_id:time_window with a five-minute window and one grace window.
  • Concurrent approval is serialized and covered by regression tests.

This issue now tracks only the residual gaps below.

Residual 1: Multi-process and cross-restart approval consumption

The adapter state lock is in-process only. Multiple broker processes against one state database, or a crash between execution and used-state persistence, can still create ambiguous approval-consumption semantics.

Recommended governance default: prefer at-most-once for kinetic actions. A lost draft/send attempt fails safer than a replayed mailbox side effect, but this choice must be explicit and documented.

Acceptance:

  • Decide and document execution semantics: at-most-once consume-before-execute vs at-least-once consume-after-execute.
  • If at-most-once is chosen, make approval consumption transactional in SQLiteStateStore, for example an atomic UPDATE ... WHERE used=0 operation; treat rowcount == 0 as already consumed.
  • Test two processes or two independent SQLiteStateStore instances racing execution against one DB file; exactly one path may consume the approval.
  • Test simulated crash/failure between consume and execute or execute and persist according to the chosen semantics.
  • Runbook states the chosen semantics and residual deployment tradeoff.

Residual 2: Binding-mutation and fuzz coverage

Current tests cover hash mismatch and binding mismatch paths, but field-level persisted approval tampering should be broader.

Acceptance:

  • Mutating individual persisted ApprovalRecord fields after approval, such as recipients, content, action, approver_id, parameters, and expires_at, denies with vmga_approval_binding_mismatch or the correct stricter error.
  • Stripping or blanking binding_hash in strict mode denies with vmga_approval_binding_missing.
  • Approval token valid for window N replayed after the grace window denies.
  • Approver outside approver_allowlist denies with vmga_approver_unauthorized.
  • Tests distinguish approval-record integrity from evidence-ledger tamper-evidence.

Out of scope

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:evidenceAudit ledger, attestations, and proof artifactsarea:policyPolicy schema, decisions, and enforcement behaviorrelease:v0.3.0Work targeted for v0.3.0 production alpha

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions