CI/CD automation¶
The automation architecture view shows how pull-request planning, scheduled observation, and protected apply must use different trust boundaries.
Automation should make drift visible more often than it changes state. Begin with a scheduled read-only job and introduce apply only after the policy, repository selection, credentials, and approval boundary are established.
Scheduled read-only audit¶
name: Repository governance audit
on:
workflow_dispatch:
schedule:
- cron: '17 6 * * 1'
permissions:
contents: read
jobs:
audit:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npx --yes @hector21/octoform@0.5.0 audit --config octoform.yml
env:
GITHUB_TOKEN: ${{ secrets.OCTOFORM_AUDIT_TOKEN }}
audit exits 1 when it reports findings, so the scheduled job fails on
drift and the failure is the notification. On the 0.3 line it exited 0
regardless; a job carried over from that line starts failing the first time it
finds something, which is the intended behaviour rather than a regression.
Credential selection¶
| Credential | Appropriate use | Boundary |
|---|---|---|
Workflow GITHUB_TOKEN |
Repositories visible to that workflow's repository token | Usually insufficient for an owner-wide inventory |
| Fine-grained PAT | Initial or narrowly scoped automation | Long-lived secret; restrict repositories and permissions |
| GitHub App installation token | Production owner-wide automation | Short-lived and installation-scoped; preferred |
Never print the token, enable shell tracing around it, or expose private repository names through a public workflow log.
Protected apply¶
Octoform 0.5 can hand a reviewed plan from one job to another. plan --out
writes a versioned artifact and apply --plan performs exactly the operations
it records, refusing with a named reason when the actor, an account's numeric
identity, the configuration digest, a source digest, or the expiry no longer
match. This is the shape to prefer: the job that mutates applies what was
reviewed, rather than re-deriving it and hoping the two agree.
The artifact is not cryptographically signed and does not try to be. It detects a plan that no longer matches the world it was made in, not an attacker who can rewrite files in the workspace — it carries the same trust as the configuration file beside it. A protected job must therefore still approve the workflow revision and the policy, not the plan file alone.
Running apply without --plan plans, displays, and mutates in the same
process, which remains correct for interactive use.
Use all of these controls:
- manual
workflow_dispatch, never an unreviewed pull-request workflow; - a protected environment with required reviewers;
- a GitHub App or narrowly scoped token stored only in that environment;
- a pinned Octoform patch;
- an explicit
--repoor reviewed--typeselector; - concurrency that prevents simultaneous governance runs;
- retained logs with secret masking and restricted access.
name: Apply repository governance
on:
workflow_dispatch:
inputs:
repository:
description: Exact repository name
required: true
type: string
permissions:
contents: read
concurrency:
group: octoform-apply
cancel-in-progress: false
jobs:
apply:
environment: governance-apply
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npx --yes @hector21/octoform@0.5.0 apply --yes --config octoform.yml --repo "$TARGET_REPOSITORY"
env:
GITHUB_TOKEN: ${{ secrets.OCTOFORM_APPLY_TOKEN }}
TARGET_REPOSITORY: ${{ inputs.repository }}
The example uses version tags for readability. A production supply-chain policy may additionally pin Actions to reviewed commit SHAs.
Patch shown in commands
The documentation line is 0.5. Executable examples pin 0.5.0, the
latest patch verified by this publication. Review the
changelog before adopting a later patch.
Failure and recovery¶
If apply exits non-zero, assume partial success is possible. Preserve the log, run a fresh read-only plan, and reconcile the remaining state. Do not blindly rerun a failed workflow before reviewing the new plan.