GitHub Actions Foundations, Automation Model, and CI/CD Concepts: Configuration, Design Patterns, and Trade-Offs
A workflow can be syntactically correct and still be the wrong design. This lesson treats GitHub Actions configuration as delivery architecture: decide which automation belongs in the repository, which checks should influence merges, where reusable actions help or hurt, how permissions and runner choices affect blast radius, and which evidence must remain stable when the platform or organization grows.
Learning objectives
- Distinguish general repository automation from continuous integration, continuous delivery, and continuous deployment responsibilities.
- Compare repository-native GitHub Actions orchestration with external systems without pretending one tool owns every delivery concern.
- Evaluate advisory versus required checks as governance choices tied to stable check identity and branch/ruleset policy.
- Choose between explicit shell/scripts and reusable actions using transparency, portability, dependency risk, maintenance, and auditability criteria.
- Use a decision table to select a Chapter 01 architecture while stating plan, trust, runner, cost, and rollback assumptions.
1. Design starts with the outcome, not the YAML feature
When a team asks “Should we use GitHub Actions for this?”, the useful question is: what state should change, who owns that state, what authority is required, and what evidence proves success? A repository labeler, a CI test suite, a package publisher, and a production rollout can all be implemented with workflows, but their risk profiles are radically different.
Start with the smallest trusted automation boundary. Read-only validation jobs can often run with no repository write scope. Release or deployment jobs need deliberate authority and stronger evidence. External infrastructure may remain owned by cloud, Kubernetes, registry, or deployment systems even when Actions orchestrates requests to them.
2. Automation versus CI/CD: do not make the terms meaningless
| Pattern | Primary purpose | Expected evidence | Typical authority |
|---|---|---|---|
| Repository automation | Repeat administrative/repository work consistently. | Run ID, API change, issue/PR/repository state. | Only the API scopes required for that mutation. |
| CI | Validate integration of an exact revision. | Build/test/lint results tied to immutable SHA and toolchain. | Usually read-only source plus evidence publication. |
| Continuous delivery | Produce and govern a deployable verified artifact. | Artifact/digest, provenance, gates, release candidate identity. | Artifact/package write only where needed. |
| Continuous deployment | Move approved verified change to a target automatically. | Deployment record, provider resource ID, post-deploy health, rollback state. | Narrow target-specific deployment identity. |
The same workflow can contain several of these responsibilities, but combining them increases coupling and permission scope. A useful production pattern is to keep untrusted/read-only validation separate from mutation and deployment work so a compromised build step does not automatically inherit deployment authority.
3. Repository-native orchestration versus external orchestration
GitHub Actions is attractive because the workflow lives beside the source and naturally receives repository events, checks, identities, and review history. That makes repository-centric CI easy to audit. External orchestrators can still be appropriate when delivery must coordinate many repositories, long-running infrastructure workflows, highly specialized compute, regulated approval systems, or targets whose lifecycle does not belong to GitHub.
| Question | Repository-native Actions is strong when… | External orchestration may be stronger when… |
|---|---|---|
| Trigger identity | GitHub event/SHA is the natural source of truth. | Events come from many systems and GitHub is only one input. |
| Reviewability | Workflow changes should follow normal pull-request review. | Central platform configuration must be managed independently of app repos. |
| Execution | Hosted/self-hosted runners fit the workload. | Specialized schedulers, persistent agents, or non-GitHub compute constraints dominate. |
| Authority | Repository/environment policy can express the boundary. | External separation-of-duties or provider-native controls are mandatory. |
| Evidence | Run/check/deployment records are sufficient anchors. | Enterprise audit requires another system to remain authoritative. |
Avoid false tool wars. GitHub Actions can orchestrate an external deployment without becoming the authoritative cloud control plane. Likewise, an external orchestrator can report a status back to GitHub without becoming the source-control system.
4. Advisory checks versus required checks
An advisory check gives feedback but does not block a merge. A required check participates in repository governance through branch protection or rulesets. Turning a check into a merge requirement changes business workflow, so it should be treated as a policy change rather than a cosmetic setting.
Required checks create two design obligations:
- Stable identity. Renaming a workflow/job/check can break or orphan a policy dependency. Treat names referenced by rules as interfaces.
- Reliable availability. A flaky external dependency or runner bottleneck can block every merge if the check is mandatory. Reliability and failure ownership therefore become governance concerns.
5. Shell/scripted steps versus reusable actions
A shell command written directly in a workflow can be highly transparent: reviewers can see exactly what executes. A reusable action can remove duplication, package platform-specific behavior, and centralize maintenance. Neither is automatically safer.
| Criterion | Direct script/command | Reusable action |
|---|---|---|
| Transparency | High for small commands; logic visible inline. | Requires reviewing the action source and pinned revision. |
| Reuse | Can become duplicated across workflows. | Strong interface for repeated behavior. |
| Dependency surface | Depends on shell/tools available on runner. | Adds action runtime/source dependency. |
| Portability | Shell/platform details may leak into workflow. | Well-designed action can normalize platforms. |
| Versioning | Versioned with workflow/repository. | Must pin/version the external interface deliberately. |
| Debugging | Simple failures often obvious in logs. | May require inspecting nested action implementation. |
Chapter 01 stays with shell steps because the logic is tiny and educational. Later chapters should introduce actions when reuse or setup behavior justifies the dependency. For third-party actions, production references should prefer a verified full commit SHA rather than a mutable branch or tag.
6. Keep GitHub state, runner state, and external state separate
flowchart LR A[GitHub repository + workflow + run records] --> B[Runner process + workspace + tools] B --> C[External registry / cloud / cluster / service] A -. policy .-> C C -. health evidence .-> A
The diagram is intentionally small. GitHub owns repository/workflow/run metadata. The runner owns transient process/filesystem/tool state while the job executes. An external provider owns the deployed service or infrastructure. A workflow can pass data across those boundaries, but the ownership does not disappear.
This separation is crucial during rollback. Cancelling a GitHub run cannot be assumed to undo an external database migration. Deleting a runner workspace cannot be assumed to remove a published package. A production design needs explicit compensation or provider-native rollback for side effects.
7. Least privilege is an architecture choice
Permissions should follow the job's responsibility. A build job that only validates code should not need package publication or deployment access. A release job can be separated so it receives narrow authority only after required build evidence exists. This reduces the amount of code that executes with mutation capability.
At workflow or job scope, explicit permissions narrows
the GITHUB_TOKEN. Current GitHub syntax sets
unspecified permissions to none once any permission is
specified. Organization/repository defaults and fork/Dependabot
rules still affect the final effective permission, so never infer
authority from YAML alone—inspect the event and policy context.
permissions: {}
jobs:
validate:
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
# validation only
The snippet illustrates the direction of travel; Chapter 06 teaches token scopes in depth. The key Chapter 01 lesson is that permission is not a convenience flag. It is part of the execution contract.
8. Runner choice combines compatibility, trust, reproducibility, and cost
Standard GitHub-hosted runners are convenient because GitHub provisions clean hosted compute for jobs. Public repositories can use standard hosted runners without usage charges under current billing rules; private repositories receive plan-dependent included minutes/storage before overage. Larger runners have different billing. Self-hosted runners shift compute operations and security responsibility to you.
Do not choose a runner only because “it is faster.” Ask:
- Does the OS/architecture match what the software must support?
- Can the workload safely execute on shared-cloud hosted infrastructure?
- Does it require private network access?
- Are preinstalled tool versions acceptable, or must toolchains be pinned?
- What is the queue/parallelism/cost impact?
- Would untrusted repository code be allowed to reach a privileged self-hosted environment?
Chapter 01 uses ubuntu-24.04 because it is a stable
explicit hosted label for a lightweight synthetic lab. It does not
imply Linux is universally the correct production runner.
9. Worked decision table
Suppose a small open-source project wants build feedback on every push, a release package on version tags, and later deployment to a cloud environment. Decide each responsibility separately:
| Need | Recommended Chapter 01 direction | Why | Evidence / rollback |
|---|---|---|---|
| Fast build feedback | Repository workflow, hosted runner, read-only permissions. | Source event/SHA is natural trigger; low privilege. | Run/check tied to SHA; rerun only after preserving failure. |
| Merge enforcement | Start advisory; make required only after reliability/ownership is defined. | A required check becomes a governance dependency. | Stable check name, ruleset/branch-policy record, exception path. |
| Release package | Separate mutation job/workflow from ordinary validation. | Publication requires additional authority and immutable artifact identity. | Package/release ID and digest; delete only exact test release if rollback is safe. |
| Cloud deployment | Keep provider authorization and target health distinct from build success. | Actions orchestrates; provider owns external state. | Deployment record + provider resource/health; provider-native rollback plan. |
10. Design lab: review before implementation
For your disposable gha-ch01-lab repository, write a
one-page design note with these fields:
- Automation objective: record and validate execution identity for a push/manual event.
- Trust: only your disposable repository content; no untrusted fork execution in this chapter.
-
Runner: GitHub-hosted
ubuntu-24.04. - Permission:
permissions: {}. - External side effects: none.
- Evidence: event, ref/SHA, run ID/attempt, job/step conclusion, runner metadata.
- Failure owner: workflow author for YAML/shell; GitHub status/runner evidence for platform failure.
- Rollback: revert/remove the lab workflow; do not delete evidence before review.
Now imagine the same workflow is proposed as a required merge check. Add three new fields: reliability expectation, owner/on-call or support path, and a bounded exception process. This exercise demonstrates how the same YAML can carry different organizational consequences.
11. Production pattern: evidence-first, authority-last
A scalable platform tends to move through this order: establish event/revision identity; run deterministic read-only validation; produce immutable evidence; evaluate policy; only then grant the narrow mutation/deployment authority required for the next state change. This ordering reduces blast radius and makes failures easier to attribute.
It also avoids a common anti-pattern: one giant workflow job that checks out source, runs arbitrary third-party code, holds package/cloud/admin credentials, publishes releases, mutates infrastructure, and performs cleanup. Such a job may be convenient at first but creates poor isolation, poor auditability, and dangerous rerun semantics.
Knowledge check
When does an advisory CI check become a governance dependency?
When repository policy such as a ruleset or branch protection requires it for merge. At that point stable identity, reliability, ownership, and exception handling matter.
Why separate validation from publication/deployment jobs?
Validation can remain low privilege while mutation/deployment jobs receive narrow authority only after evidence is available, reducing blast radius.
Is a reusable action automatically better than a shell step?
No. Reuse can improve maintainability, but it adds an executable dependency and interface that must be reviewed and versioned. Small transparent commands may be safer inline.
A workflow sends a successful deployment API request. Which system owns proof that the service is healthy?
The external target/provider. GitHub can record deployment intent/status, but actual service health must be verified from the target system.
Why pin ubuntu-24.04 in the lab instead of relying
on ubuntu-latest?
The -latest alias can migrate to a newer GA image.
An explicit OS label removes that migration variable, although
preinstalled tools on the image can still change.
Official references and version notes
- Understanding GitHub Actions — current component model for workflows, events, jobs, steps, actions, and runners.
- Workflow syntax for GitHub Actions — authoritative workflow keys, permissions, jobs, runner selection, and manual dispatch syntax.
- Variables reference — definitions of GITHUB_SHA, GITHUB_REF, GITHUB_RUN_ID, GITHUB_RUN_ATTEMPT, and related default variables.
- GitHub-hosted runners reference — current hosted-runner labels, VM behavior, hardware, and image caveats.
- Billing and usage — current availability, public-repository standard-runner usage, private-repository quotas, and usage boundaries.
- Secure use reference — security guidance for untrusted input, action dependencies, and least-privilege workflow design.
- Managing GitHub Actions settings for a repository — repository-level Actions policy and workflow permission controls.
Rechecked on 2026-09-09. Billing, runner specifications, permission defaults, and policy availability are plan- and platform-sensitive; use the current linked documentation rather than copying numeric quotas or defaults into long-lived production policy. The mandatory design exercise has no paid or enterprise prerequisite.
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.