Chapter 01Lesson 01~90 minutes

GitHub Actions Foundations, Automation Model, and CI/CD Concepts: Core Concepts and Mental Model

GitHub Actions is easiest to understand when you stop thinking of it as “a YAML file that runs commands” and instead model it as an event-driven execution system. A repository event selects workflow configuration at a particular revision; GitHub creates a run and jobs; each job is assigned to a runner; ordered steps execute there; and only then do checks, artifacts, deployments, or external systems record outcomes. This lesson builds that causal model before adding more syntax.

FoundationsEvent-drivenRuns & attemptsRunner stateLeast privilege

Learning objectives

  • Explain the event → workflow revision → run → job → runner → step → evidence chain without collapsing distinct states into “the workflow ran.”
  • Distinguish a workflow, workflow run, run attempt, job, step, action, runner, check, artifact, environment, deployment, and external target.
  • Use read-only runtime evidence such as GITHUB_SHA, GITHUB_REF, GITHUB_RUN_ID, and GITHUB_RUN_ATTEMPT to identify what actually executed.
  • Explain why steps in one job can share a filesystem while separate GitHub-hosted jobs must be treated as separate machines.
  • Relate GitHub Actions automation to CI, continuous delivery, deployment authorization, least privilege, reproducibility, and auditability.

1. The problem: automation without an execution model becomes guesswork

A team can copy a working workflow from a blog and still be unable to answer basic operational questions: Which commit caused this run? Which version of the workflow was evaluated? Did a job wait for a runner or fail after assignment? Did a green build produce the expected artifact? Did an approved deployment actually make the external service healthy? Those are different questions because they are owned by different layers.

The first production skill is therefore not memorizing YAML. It is learning to follow evidence through the system. If a run is reproducible, another engineer should be able to identify the triggering event, exact source/workflow revision, permissions, runner context, step code, outputs, and any external side effects.

Chapter 01 rule: every green indicator proves only the state it actually represents. A successful step proves that step concluded successfully. It does not automatically prove another job ran, a release contains the intended files, or an external deployment is healthy.

2. The event-driven mental model

A workflow starts with intent. The intent may be a repository event such as a push, a manual dispatch, a schedule, an API dispatch, or another supported event. GitHub evaluates the workflow definition associated with the event/ref rules, creates a workflow run, evaluates jobs and conditions, queues eligible jobs, assigns runners, then executes steps on those runners.

Causal execution chain — state changes flow downward
flowchart TD
  A[Repository event or manual intent] --> B[Workflow definition at a revision]
  B --> C[Workflow run ID + attempt]
  C --> D[Job graph and conditions]
  D --> E[Queue and runner assignment]
  E --> F[Ordered steps: scripts or actions]
  F --> G[Outputs, checks, logs, artifacts]
  G --> H[Environment / deployment records]
  H --> I[External target health and governance evidence]

The arrows matter. For example, a workflow file can be valid YAML but never selected by the event filter. A job can be created but remain queued because no matching runner is available. A deployment job can finish after an API request even though the external service later fails health checks. Diagnosis becomes much faster when you ask, “At which arrow did the expected state stop advancing?”

3. Core nouns: define the objects before using them

Object Mental model Evidence you can inspect
Workflow A versioned YAML automation definition stored under .github/workflows. File path, repository revision, triggers, permissions, job definitions.
Event The activity or explicit request that may select a workflow. Event name, payload, ref, actor, source repository.
Run One workflow execution created for an event/dispatch. GITHUB_RUN_ID, run number, event, head SHA, status/conclusion.
Run attempt A rerun of the same run identity. GITHUB_RUN_ATTEMPT; first execution starts at 1.
Job A set of ordered steps scheduled onto one runner. Job name, dependencies, queue/start/end times, runner, conclusion.
Step An ordered unit inside a job; a shell command or an action invocation. Step name, command/action revision, log, exit status, outputs.
Action Reusable code invoked by a step. Repository/path, immutable revision or release reference, inputs, runtime.
Runner The compute environment that executes one job. OS label, image metadata, architecture, tool versions, runner name.
Artifact / cache GitHub-managed stored files; artifacts are evidence/results, caches are performance aids. Name, producing run/SHA, retention, digest/metadata where supported.
Environment / deployment GitHub records used to control or report deployment intent and status. Environment name, approval/protection state, deployment status.
External target The cloud, registry, server, cluster, or service changed by the workflow. Provider-side deployment/resource ID, digest, health check, logs.

This vocabulary prevents a common communication failure. Saying “Actions failed” is too broad. Saying “the run was created, the build job queued for three minutes, the hosted runner started, and step 4 exited 1 before any artifact was produced” is actionable.

4. Revision identity: the run is not just a branch name

Branches and tags are human-friendly references; commits are immutable identities. GitHub exposes event-dependent values such as GITHUB_SHA, GITHUB_REF, and GITHUB_REF_NAME. The exact meaning of GITHUB_SHA depends on the event type, so production workflows should record it rather than infer it from a branch label.

Also separate the event SHA from a later checked-out SHA. In this chapter's minimal workflow we deliberately do not run a checkout action. That proves an important boundary: the hosted runner does not automatically contain your repository source. In later chapters, if a workflow checks out another ref, the workspace commit can differ from the event's original SHA; both identities then need evidence.

printf 'event=%s\n' "$GITHUB_EVENT_NAME"
printf 'ref=%s\n' "$GITHUB_REF"
printf 'sha=%s\n' "$GITHUB_SHA"
printf 'run_id=%s\n' "$GITHUB_RUN_ID"
printf 'run_attempt=%s\n' "$GITHUB_RUN_ATTEMPT"
printf 'workflow=%s\n' "$GITHUB_WORKFLOW"
Do not dump the entire runtime environment or complete contexts into logs. Contexts can contain sensitive or security-relevant values. Print only the fields required for diagnosis or evidence.

5. Run ID, run number, and run attempt answer different questions

GITHUB_RUN_ID uniquely identifies a workflow run within a repository and remains the same when that run is rerun. GITHUB_RUN_ATTEMPT starts at 1 and increments for reruns. GITHUB_RUN_NUMBER is the sequence number for that workflow. Preserve the ID and attempt together when comparing logs because a rerun can execute changed external conditions even when the logical run ID is unchanged.

Run ID

Stable identity used to correlate UI, API, jobs, logs, and reruns.

Attempt

Which execution of that run produced this evidence.

Head/event SHA

Revision identity that the event associates with the run.

Conclusion

Completed result such as success, failure, cancelled, or skipped—not a deployment health guarantee.

6. Runner state: one job, one execution environment

For normal GitHub-hosted runners, a job begins on newly provisioned hosted compute. Steps within that job execute on the same runner and can share files through its workspace. A different job must be treated as a separate execution environment; do not expect files created by one hosted job to exist in another.

Current runner-image mappings change over time. At this lesson's verification date, ubuntu-latest maps to Ubuntu 24.04, windows-latest to Windows Server 2025, and macos-latest to macOS 26 Arm64 in the runner-images project. The lab pins ubuntu-24.04 so the OS family does not silently move when the -latest alias migrates.

printf 'runner_os=%s\n' "$RUNNER_OS"
printf 'runner_arch=%s\n' "$RUNNER_ARCH"
uname -a
python3 --version

Pinning the OS label does not freeze every preinstalled tool. Hosted images are still updated. If a build depends on a particular compiler, runtime, or package manager version, set that toolchain explicitly in later workflow design rather than relying on whatever happens to be preinstalled.

7. Permissions are evaluated configuration, not decoration

GitHub creates a GITHUB_TOKEN for jobs, but its usable permissions depend on repository/organization defaults, event trust, and explicit workflow/job configuration. If you declare any permissions, unspecified scopes become none. Chapter 01's observation-only workflows use permissions: {} because they do not need repository API access.

permissions: {}

This is a deliberately strong teaching default: start with no repository mutation capability, then add a narrow permission only when a later operation proves it needs one. A build step that only computes local files should not silently carry write authority to issues, contents, packages, or deployments.

8. Automation, CI, continuous delivery, and deployment are related—not synonyms

Practice Main question Typical Actions evidence What it does not prove
Repository automation Can repetitive repository work happen consistently? Run/job/step result, API mutation record. That software was built or releasable.
Continuous integration Does this exact change integrate and satisfy automated checks? Build/test/lint results tied to SHA. That production changed.
Continuous delivery Is a verified artifact kept in a deployable state? Immutable artifact/digest, gate outcome, release candidate evidence. That deployment was approved or healthy.
Continuous deployment Should verified change automatically reach a target? Deployment authorization, provider response, target health. Long-term service health after rollout.

A mature pipeline promotes evidence rather than merely chaining commands. Build/test evidence should identify the exact source; deployment should use the verified artifact rather than silently rebuilding; post-deploy health should come from the target system, not from wishful interpretation of a successful API call.

9. Read-only inspection first

Before changing repository settings or introducing credentials, inspect the current workflow/run state. In the GitHub web UI, open Actions → a run → a job and locate the event, branch/ref, commit, job name, runner setup, and step conclusions. For CLI users, gh run list and gh run view provide another read-only surface after normal local authentication.

The evidence questions are more important than the UI path:

  • Which event created this run?
  • Which immutable SHA is associated with the event?
  • Which run ID and attempt are these logs from?
  • Which runner label/image executed the job?
  • What repository permission did the job actually need?
  • Which step first changed from expected to unexpected state?
  • Did anything outside GitHub change, and how is that proved independently?

10. Foundation mistakes to eliminate early

  • “The YAML parses, therefore CI works.” Syntax can be valid while the trigger never selects the workflow or a condition skips the job.
  • “The branch name tells me exactly what ran.” Record the event SHA and workflow/run identity.
  • “All jobs share one machine.” Hosted jobs are separate execution environments; only steps within a job share that job's runner filesystem.
  • “A green step means deployment succeeded.” It proves only that the step concluded successfully; target health needs target evidence.
  • “The runner can keep important state for the next run.” Hosted compute is ephemeral; durable evidence belongs in explicit storage/services, not an incidental workspace.
  • “More token permission is harmless.” Unneeded authority increases blast radius if a command, dependency, or input is compromised.

11. Micro-lab: predict a run before creating one

Do this on paper or in a local note before Lesson 2. Imagine a workflow triggered by push to main, containing one job on ubuntu-24.04 and three shell steps. Predict these facts before any run exists:

  1. A push to another branch should not create a matching run if the workflow's branch filter excludes it.
  2. A selected push should create one run identity with attempt 1.
  3. The single job should be queued and then assigned to one hosted runner.
  4. All three steps should see files created by earlier steps in that same job.
  5. A second job would not automatically see those files.
  6. With permissions: {}, the job should not rely on repository write access.

Lesson 2 turns these predictions into a disposable live experiment. The goal is not merely to make a green badge; it is to prove each predicted state independently.

Next lesson

Guided Hands-On Workflow

Build a minimal push/manual workflow, capture event and run evidence, and connect every green indicator back to the exact revision and execution layer.

Knowledge check

A step prints “deployment request accepted” and exits 0. What is proved?

Why preserve both GITHUB_RUN_ID and GITHUB_RUN_ATTEMPT?

Can two separate GitHub-hosted jobs safely assume they share a file created in $GITHUB_WORKSPACE?

Why use permissions: {} in the Chapter 01 observation workflow?

What is the first identity to record when someone says “the main branch workflow failed”?

Official references and version notes

Version and compatibility note

Version-sensitive statements were rechecked against primary GitHub documentation and GitHub-maintained runner-image information on 2026-09-09. The executable Chapter 01 examples pin ubuntu-24.04; at verification time ubuntu-latest maps to Ubuntu 24.04, but hosted images and preinstalled tools continue to update. The labs use no external actions and no secrets, and explicitly set permissions: {}.

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.