Skip to main content

Roll back by prior commit_sha

Objective

Roll a bundle back to a known-good commit_sha, and explain why rollback is a re-deploy of a prior version, not a forward edit.

Concept

A bad bundle in prod is the worst kind of change: it can silently over-grant (a false allow) or lock everyone out (a false deny). When that happens you do not want to open an editor and hand-patch production under pressure. You want to return prod to a version you already trust, immediately.

That is what rollback by commit_sha is. Because every version of the bundle is a commit, the last known-good state has a commit_sha. Rollback re-deploys that exact commit_sha to prod. Nothing is edited. The PDP goes back to running bytes that already passed their tests and already ran cleanly in production.

Why this is the safe primitive:

  • It is deterministic. A commit_sha names exact bytes. "Roll back to 9f8e7d6" has one meaning; "undo the last change" does not.
  • It skips the risky path. You are not writing new Rego during an incident. You are re-applying a version that was already built, tested, and promoted.
  • It is auditable. Writ keeps decision logs and records which signed version is live in each environment, so "prod was on abc123, then 9f8e7d6 from 14:32" is a recorded fact, and the decisions before and after can be replayed.

Operationally, a rollback runs the same deploy-action path as a forward deploy: same GitHub OIDC authentication, same trust policy, same EnforceAuth API. The only difference is the version it points at. A rollback workflow typically takes the target commit_sha as an input so an operator can name the known-good version to restore. As in lesson 2, the with: keys in the YAML below are teaching placeholders, not a documented deploy-action API; substitute the real input names from the version of the Action you adopt. What is grounded is the path itself: OIDC authentication, RFC 8693 token exchange, and no API keys, identical to a forward deploy.

name: rollback-authz-bundle
on:
workflow_dispatch:
inputs:
commit_sha:
description: Known-good commit to restore to prod
required: true

permissions:
contents: read
id-token: write

jobs:
rollback-prod:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.commit_sha }} # check out the known-good version
- name: Test the known-good bundle before restoring
run: |
curl -sSL -o opa https://openpolicyagent.org/downloads/latest/opa_linux_amd64_static
chmod +x opa && ./opa test policy -v
- name: Re-deploy prior bundle to prod
uses: EnforceAuth/deploy-action@v1
with:
# Placeholder input names (illustrative, not a documented API).
bundle: policy
environment: prod

Notice the rollback still runs opa test on the version it is about to restore, and still deploys through the same OIDC-authenticated Action. Rolling back is re-deploying a known-good commit_sha, verified the same way a forward deploy is.

Forward-fix versus rollback: roll back first to stop the bleeding, then fix forward on a branch, test, and promote the fix through the normal dev-to-staging-to-prod flow from lesson 2. Rollback buys you time; it is not the fix.

Hands-on lab

The lab bundle authorizes rollback explicitly once you complete the lesson 1 exercise. In ../lab/policy.rego, the rule you implement lets a release manager rollback in prod when the change carries a commit_sha, which models "restore this prior version" (the starter denies it until then). With the rules in place, run the suite:

git clone https://github.com/EnforceAuth/university-labs.git
cd university-labs
opa test courses/policy-lifecycle-build-promote-rollback -v

Run it from the cloned university-labs repo. The test test_release_manager_can_rollback_prod_by_prior_commit passes with a commit_sha of 9f8e7d6: that is a release manager restoring a known-good version. Now confirm the guard: the rollback rule requires input.change.commit_sha != "". Temporarily set that test's commit_sha to "", re-run, and watch the case stop being allowed. The policy refuses a rollback that does not name a version, which is the point. A rollback with no target is not a rollback. Restore the value and confirm PASS: 7/7.

Check for understanding

  1. Why is "roll back to commit_sha 9f8e7d6" safer than "edit prod to undo the last change"?
  2. What does a rollback re-deploy, and how does its authentication path compare to a forward deploy?
  3. After a rollback stabilizes prod, what is the correct way to ship the actual fix?