Manage policy versions and roll back
Every policy save creates a new row in policy_versions containing a full snapshot of the policy at that moment (decision S7 — full-fidelity v1, no diff-only optimization). Rollback is a fresh save with the snapshot’s fields, producing version+1 rather than rewriting an existing row. This means the version timeline is monotonic and every audit row’s policy_version always resolves.
When to roll back
Section titled “When to roll back”Two common cases:
- You shipped a wrong policy. The latest version denies more than you meant. The right move is roll back to the last known-good version, then edit forward from there once you understand the fix.
- A planned change needs reversion. A policy you put live for a maintenance window expired wrong (e.g.,
valid_untiltypo) and is still firing. Rolling back to the pre-change version restores the intended state.
Step 1 — List versions
Section titled “Step 1 — List versions”ironflow policy versions list <policy_id>Output:
VERSION NAME EFFECT CHANGE CREATED1 deny-prod-invoke-non-oncall deny initial — oncall-only prod invoke 2026-04-12T10:14:02Z2 deny-prod-invoke-non-oncall deny widen to staging 2026-04-19T14:30:11Z3 deny-prod-invoke-non-oncall deny narrow back to prod 2026-04-22T09:11:48Z4 deny-prod-invoke-non-oncall deny allow incident-responder role too 2026-05-07T08:00:00ZAudit rows from before 2026-05-07 cite policy_version: 3; rows from after cite version 4.
Step 2 — Show a version verbatim
Section titled “Step 2 — Show a version verbatim”Before rolling back, confirm the target version is the one you want by listing all versions and checking the row with the matching version number:
ironflow policy versions list <policy_id>This is also useful for replaying old audit decisions — see debug-deny.md.
Step 3 — Roll back
Section titled “Step 3 — Roll back”ironflow policy rollback <policy_id> 3What this does:
- Reads version 3’s snapshot from
policy_versions. - Runs the three save preflights (saver, per-admin, role-only) against the snapshot.
- Saves the snapshot as a new version (append-only history).
- Bumps the tenant epoch in NATS KV; in-memory caches across the cluster invalidate on next lookup.
The previous versions stay in history. If you need to re-roll-back, ironflow policy rollback <policy_id> 5 is just another rollback — there’s nothing special about “the last rollback.”
Step 4 — Verify
Section titled “Step 4 — Verify”Same as a normal save:
# Confirm the rollback row is now latestironflow policy get <policy_id>Edge cases
Section titled “Edge cases”- Rollback target was created before a schema migration. A version 1 saved before
valid_from/valid_untilwere added will rollback as a snapshot with those fields null (the column defaults). This is the intended behavior — a policy that didn’t have a window before still doesn’t. If you want to add a window post-rollback, save a forward edit (version 6) on top. - Audit-row replay across rollback. An audit row from version 4 cites
policy_version: 4. After rolling back to version 3 (saved as version 5), that audit row still resolves to version 4 inpolicy_versions. The version is part of the audit, not part of the live policy. - Bulk rollback (multiple policies). No native multi-policy rollback in v1. Script the loop:
…but think first. A bulk rollback is rarely the right move during an incident — usually one policy is the cause.
Terminal window for id in $(ironflow policy list --json | jq -r '.[].id'); doironflow policy rollback "$id" "$(ironflow policy versions list "$id" --json | jq -r '.[-2].version_num // empty')"done
What rollback is not
Section titled “What rollback is not”- Not undo for audit rows. Rolling back a policy does not delete or modify any
policy_decisionsrow. Audit history is immutable. - Not a chain repair tool. If the audit chain shows corruption, that’s a tampered chain and a security incident — rollback won’t fix it. Open an incident; do not attempt to overwrite audit rows.
- Not an export. If you want to ship a known-good version to another tenant, use the template bundle path — see the dashboard “Templates” workflow (UI-8).
Next steps
Section titled “Next steps”- Debugging a deny that fired against an old version: debug-deny.md
- Break-glass when rollback itself is denied: emergency-bypass.md
- Architectural rationale for full-fidelity snapshots: ADR 0016, decision S7