Agent Wranglers

Infrastructure as code Required

Review the plan and apply only from CI

Post the plan in every pull request. Apply only from CI after merge, from the plan file made for that commit. No person applies from a laptop.

How to do it

On each pull request, CI runs plan with a read-only role and posts the summary. After merge, one job runs plan -out, prints the plan and saves the file as a short-lived build artifact. The apply job waits for a person to approve that printed plan, for example through a protected environment. Then it applies that exact file. A saved plan refuses to apply when the state changed in between. Plan files can hold secrets, so encrypt them or keep them for 1 day at most. Write access belongs only to the CI role, as in separate roles for plan and apply. Protect the branch as in protect the main branch.

Example

# GitHub Actions: plan on pull requests, apply the saved plan after merge
on:
  pull_request:
  push:
    branches: [main]
permissions:
  id-token: write
  contents: read
jobs:
  plan:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<commit-sha>
      - run: tofu init -lockfile=readonly && tofu plan -no-color
  plan-release:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<commit-sha>
      - run: tofu init -lockfile=readonly && tofu plan -no-color -out=release.tfplan
      - uses: actions/upload-artifact@<commit-sha>
        with: { name: release-plan, path: release.tfplan, retention-days: 1 }
  apply:
    needs: plan-release
    environment: production   # a person approves the plan printed above
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<commit-sha>
      - uses: actions/download-artifact@<commit-sha>
        with: { name: release-plan }
      - run: tofu init -lockfile=readonly && tofu apply release.tfplan

How to check

The workflow file runs apply only on a saved plan file, in a job limited to the main branch and a protected environment. No human role has write rights on the state bucket.

For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers infrastructure playbook: https://agentwranglers.se/playbook/infrastructure/infrastructure-as-code/plan-in-review.