Capstone: Build a Secure Reusable Enterprise CI/CD Platform: Core Concepts and Mental Model
Integrate event identity, reusable automation, runner trust, artifact provenance, deployment authorization, observability, recovery and governance into one independently verifiable delivery model.
Learning objectives
- Integrate event, workflow, runner, identity, artifact, deployment and governance state into one causal model.
- Define an evidence ledger that prevents “green workflow” from masking missing proof.
- Explain runner and reusable-workflow trust boundaries.
- Separate artifact identity, provenance, deployment authorization and target health.
- Establish the post-course production operating model.
1. The capstone problem: green is not the same as trustworthy
A mature CI/CD system cannot be summarized by “the workflow passed.” A production delivery crosses several independently owned states: an event chooses a source revision; a workflow revision evaluates conditions and permissions; jobs are queued and assigned to runners; build steps produce bytes; GitHub stores artifacts and attestations; an environment authorizes deployment; an identity obtains temporary authority; an external target changes; and logs, run metadata and policy records become evidence. A green check at one layer does not prove the others are correct.
This final chapter connects the course into one operating model. The objective is not to produce the largest YAML file. The objective is to make every important transition independently verifiable, least-privileged, reproducible and recoverable. Central reusable automation should remove accidental variation while preserving explicit repository contracts and safe escape hatches.
2. Mental model: one delivery, many proof boundaries
Start with the repository event and exact source SHA. The caller workflow does not immediately deploy. It first enters a trusted reusable CI contract. Jobs run on an explicitly selected hosted or ephemeral runner, tests and packaging create evidence, and an immutable artifact identity is recorded. Only then may a protected deployment job obtain the minimum authority needed for its target. Observability and recovery preserve what happened, while organization policy constrains which dependencies, runners and permissions were allowed in the first place.
flowchart TD A[Repository event + exact source SHA] --> B[Caller workflow revision] B --> C[Versioned reusable CI contract] C --> D[Hosted / ephemeral runner jobs] D --> E[Test + build evidence] E --> F[Artifact ID + file digest + provenance] F --> G[Protected environment decision] G --> H[OIDC / bounded deployment identity] H --> I[External target or faithful simulation] I --> J[Health verification + deployment record] J --> K[Logs + run/attempt + recovery evidence] K --> L[Policy / audit / upgrade feedback]
Every arrow changes a different state. The caller-to-reusable-workflow edge changes configuration control, not source identity. Runner assignment changes execution location, not GitHub permissions by itself. Artifact upload creates GitHub-owned evidence, not deployment authorization. Environment approval authorizes a job to proceed, not the health of the target. OIDC creates short-lived identity material, not a successful rollout. Health verification observes the target after mutation.
3. The capstone state ledger
| Layer | State to record | Independent proof |
|---|---|---|
| Event / source | event name, ref, head SHA, base/head for PRs | event payload fields, git revision, run URL |
| Workflow / dependencies | caller file revision, reusable workflow SHA, action SHAs | repository files + full immutable refs |
| Job graph | needs edges, matrix cells, conditions, concurrency | run job graph, conclusions, evaluated inputs |
| Runner | label, image/OS, architecture, tool versions, group if self-hosted | runner logs + explicit version commands |
| Token / trust | GITHUB_TOKEN permissions, secret names/scopes, OIDC audience/subject | workflow permissions + allowlisted claim inspection |
| Cache / artifact | cache key/hit, artifact ID, artifact-service digest, subject file SHA-256 | action outputs + local hash |
| Attestation | subject digest, workflow identity, repository, event | GitHub attestation + gh verification |
| Environment / deployment | environment name, approval/protection state, deployment record | environment/deployment UI or API |
| External target | target identity, promoted artifact digest, health result | target-native readback or faithful simulation |
| Recovery / governance | first run/attempt, rollback target, policy result, exception record | retained evidence + audit/policy record |
4. Read-only inspection comes before mutation
The safest first operation is inventory. Inspect the workflow source, dependency references, expected permissions, runner routing, environment names and last known artifact/deployment evidence before changing anything. A production incident is the worst time to discover that nobody recorded which reusable workflow revision produced the artifact.
git rev-parse HEAD
git status --short
grep -R "^[[:space:]]*uses:" -n .github/workflows .github/actions || true
grep -R "^[[:space:]]*permissions:" -n .github/workflows || true
gh run list --limit 10 --json databaseId,attempt,headSha,event,status,conclusion,workflowName,url
5. Trust is a graph, not a checkbox
A job inherits risk from everything it can execute or reach: repository code, reusable workflows, custom or Marketplace actions, shell interpreters, runner image, package registries, secrets, GITHUB_TOKEN permissions and external identity providers. GitHub currently recommends full-length commit SHA pinning as the only immutable action reference. The capstone therefore treats every executable dependency as part of the trusted computing base and records the reviewed release-to-SHA mapping.
For reusable workflows, centralization is valuable only when the caller contract remains explicit. The caller supplies typed inputs, grants a permissions ceiling and pins a known platform revision. The called workflow may reduce permissions further but must not be able to silently increase them. Current GitHub.com limits allow up to ten connected workflow levels and fifty unique reusable workflows in one call tree, which is another reason to keep the platform composable rather than deeply nested.
6. Runner trust is separate from workflow correctness
The primary capstone path uses ubuntu-24.04, a stable
GitHub-hosted label. GitHub-hosted jobs receive fresh instances,
which reduces persistence risk and makes the lab free in public
repositories. A self-hosted or ARC runner can be appropriate for
private networking, specialized hardware or scale, but it expands
the operational security boundary: image patching, network
reachability, filesystem residue, registration lifecycle and
runner-group access all become platform responsibilities.
Production invariant: untrusted pull-request code must not be routed to a privileged self-hosted/ARC runner or to a deployment identity merely because the workflow file is centrally governed.
7. Build evidence, artifact identity and provenance are different proofs
The capstone records both the content digest of the release file and the artifact service identity. The file SHA-256 proves the bytes a deployment should consume. The upload action also returns an artifact ID and artifact digest that identify GitHub’s stored artifact record. Do not substitute a cache key, artifact display name or log line for either identity.
For a public disposable repository, artifact attestations add
cryptographically signed provenance. Current GitHub guidance
requires contents: read,
id-token: write and
attestations: write for the attesting job. Verification
is essential: an attestation proves provenance claims about bytes;
it does not prove the bytes are vulnerability-free or safe to
deploy.
8. Authorization and deployment health are separate
A deployment job should reference an environment, bind concurrency
to the target and obtain deployment authority only after build
evidence is fixed. On current GitHub plans, environments and
protection rules are available for public repositories; required
reviewers on Free/Pro/Team are a public-repository capability. The
free capstone can therefore use a public disposable repository with
a protected capstone-production environment, while a
local-only learner can simulate the approval decision in an evidence
file.
When a real cloud is introduced, prefer OIDC over long-lived static secrets. Repositories created after July 15, 2026 use GitHub’s immutable default OIDC subject format containing owner and repository IDs. Trust policies must match the subject actually issued to the repository; copying an older name-only subject string is not a safe production shortcut.
9. The operating model after the course
- Change: pin reviewed platform/action revisions, test compatibility, then roll forward deliberately.
- Evidence: preserve run ID, attempt, source SHA, job conclusions, artifact identity, provenance and target health.
- Authority: keep write permissions, environment secrets and OIDC in the narrowest job that needs them.
- Recovery: promote known bytes or compensate known side effects; do not rebuild a rollback artifact from moving source.
- Governance: enforce allowed dependencies/runner access where plan permits, and document time-bounded exceptions.
- Economics: measure queue time, critical path, cache value and usage before buying larger runners or adding parallelism.
10. From model to implementation
Lesson 2 turns this state ledger into a two-repository disposable platform. The platform repository owns a reusable CI workflow and one organization-specific policy action. The application repository owns source code, the caller workflow and deployment intent. That separation demonstrates a realistic golden path without pretending every application must surrender all autonomy.
Knowledge check
Why is an environment approval not proof of a successful deployment?
Approval authorizes a job to proceed. Target mutation and health verification happen later and need their own evidence.
Which identity should a deployment compare before promoting an artifact?
The exact artifact/file digest tied to the expected source SHA and run, not only an artifact name.
Why can a reusable workflow not safely “fix” an overly broad caller permission model by assumption?
The caller establishes the permission ceiling and trust boundary. The reusable workflow should explicitly reduce permissions per internal job and document required permissions.
When should a self-hosted runner be considered part of the security boundary?
Always. Its filesystem, network reach, installed software, registration and accessible secrets can outlive or exceed an individual job.
What does an artifact attestation prove?
Signed provenance and integrity claims about the subject bytes and build identity; it is not a vulnerability or correctness guarantee.
Official references and version notes
- Workflow syntax for GitHub Actions — Current workflow/job/permissions/runner syntax and hosted-runner behavior.
- Reusing workflow configurations — Current reusable-workflow access, nesting and call-tree limits.
- Secure use reference — Least privilege, untrusted-input handling and full-SHA dependency guidance.
- Deployments and environments — Environment approvals, secrets, protection rules and deployment boundaries.
- OpenID Connect reference — OIDC claim semantics including immutable subject claims introduced in 2026.
- Artifact attestations — Provenance model and verification expectations.
- Using artifact attestations — Current permissions and actions/attest workflow pattern.
- GitHub-hosted runners reference — Current runner labels, images, hardware and billing boundaries.
- Runner groups — Runner-group trust boundary and access-control model.
- GitHub Actions billing and usage — Current public/private hosted-runner and usage accounting model.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.