Reviewed plan¶
The person who approves a change and the process that carries it out need not be the same. This example is written for that split.
# A configuration written to be planned by one party and applied by another.
#
# Nothing in the YAML enables that separation — the separation comes from how
# the two commands are run:
#
# # reviewer, read-only credentials
# octoform plan --config octoform.yml --repo example-service \
# --out plan.json --expires-in 30
#
# # applier, write credentials, after the plan has been reviewed
# octoform apply --plan plan.json
#
# The second command re-checks the artifact schema version, the expiry, the
# authenticated actor, each account's numeric identity, every configuration
# source file, and the resolved configuration itself. If any of them moved it
# refuses and names which one. That is why this example declares settings a
# reviewer would genuinely want to look at before they are applied.
#
# `example-org` is a placeholder — replace it before running anything.
version: 1
owners:
example-org:
defaults:
security:
secret_scanning: true
secret_scanning_push_protection: true
repos:
example-service:
merge:
delete_branch_on_merge: true
default_branch:
name: main
rulesets:
- name: protected-default
target_branches: ['~DEFAULT_BRANCH']
required_approvals: 1
required_checks: ['build']
block_force_push: true
The two commands¶
octoform plan --config octoform.yml --repo example-service --out plan.json --expires-in 30
octoform apply --plan plan.json
The first can run with read-only credentials. The second needs write access, and performs exactly the operations the file records — it does not re-plan and does not re-observe.
What the second command checks first¶
Before it touches anything it re-checks six things, and refuses naming which one failed if any of them moved:
| Check | A failure means |
|---|---|
| Artifact schema version | The file came from an incompatible release |
| Expiry | The observation behind the plan is too old to act on |
| Authenticated actor | A different identity is applying than planned |
| Account numeric identity | The account was renamed or replaced |
| Configuration source digests | A contributing file changed after review |
| Resolved configuration digest | The document now means something different |
A stale plan is never silently repaired and never quietly re-planned into something else. The remedy is always to plan again, review the new plan, and hand over the new artifact.
Treat the artifact like the configuration
It carries no credential, but it does name private repositories and their settings. It is not a build-log attachment.
Why the settings here are worth reviewing¶
A saved plan is only useful if someone actually reads it. This configuration declares a ruleset with required approvals, required checks, and force-push blocking on the default branch — the kind of change where a reviewer will want to see the exact current and desired values before anyone applies it.
The expiry is deliberately short. Thirty minutes is enough for a review and short enough that an unattended artifact stops being applicable.
In automation¶
This is the shape to prefer when a workflow applies changes. The approval that
apply's interactive prompt would have represented becomes the review of the
plan artifact, and --yes no longer stands in for a review that never
happened. See the automation guide.