Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXXXIX · PipelinesPipelines

Pipeline as code — the workflow file is committed

Intermediate⏱ ~20 mingit

What you'll learn

  • Explain what "pipeline as code" means and where the workflow file lives
  • Identify the four benefits of pipeline-as-code over GUI-configured pipelines
  • Recognise the three costs the model imposes on a team
  • Distinguish the workflow file from the runner that executes it
  • Locate the canonical file path for a GitHub Actions workflow

Prerequisites

Practice

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

The pipeline is a file in the repository. Not in a GUI. Not in a vendor portal. Not in a runner’s local filesystem. In the same Git repository as the application code, the Terraform module, the Ansible playbook, the Helm chart - whatever the pipeline builds. Every change to the pipeline is a commit, every commit is a pull request, every pull request is reviewed, and every reviewed change is auditable. This is pipeline-as-code.

Where the workflow file lives

flowchart LR
    A["Repository root"] --> B[".github/"]
    B --> C["workflows/"]
    C --> D["ci.yml"]
    C --> E["deploy.yml"]
    C --> F["scan.yml"]

The canonical location for a GitHub Actions workflow file is .github/workflows/<name>.yml (or .yaml). The directory name is fixed; the filenames are arbitrary but conventionally grouped by purpose: ci.yml for build and test, deploy.yml for environment promotion, scan.yml for security scans. Each file is a separate workflow with its own triggers, concurrency group, and runner pool.

# Inspect the workflow files in a repository
cat .github/workflows/ci.yml
cat .github/workflows/deploy.yml

# List every workflow in a repository from the command line
ls -1 .github/workflows/

The file is plain YAML. It can be read with a text editor, diffed with git diff, reviewed in a pull request, and reverted with git revert. None of these properties require the CI vendor’s UI.

The four benefits

Pipeline-as-code gives a team four operational properties that GUI-configured pipelines cannot:

  • History. Every change to the pipeline has a commit, an author, a timestamp, and a parent commit. The question “why did this job start running in parallel last month?” is answerable with git log -p .github/workflows/.
  • Review. A change to the pipeline is a pull request and can require approvals, status checks, and signed commits exactly like an application change. The reviewer is accountable for the pipeline change, not just the code change.
  • Rollback. A bad pipeline change is reverted with git revert <sha>. The next run picks up the reverted configuration. There is no “click the old version” in a vendor portal because there is no vendor portal; the workflow file is the single source of truth.
  • Portability. A workflow file in one repository can be moved to another repository with git mv and a pull request. The team can copy a workflow between projects without a vendor export/import flow.

The three costs

The model is not free. Three costs are paid by every team that adopts it:

  • The file is executable. A typo in jobs.<id>.runs-on fails the build; a typo in needs: breaks the DAG silently; a typo in a secret reference leaves the secret literal in the logs. YAML errors are runtime errors; they are not caught by the compiler.
  • The file is coupled to the vendor. A GitHub Actions workflow cannot run on GitLab CI; a GitLab CI YAML cannot run on GitHub Actions. The “as code” is “as code in this vendor’s dialect”. Portability is reduced to portability between repositories of the same vendor.
  • The file leaks operational detail. A workflow committed to a public repository publishes the runner, the action versions, the trigger, and the step sequence to anyone who can clone the repository. Internal repositories leak to anyone with read access. Secret references are environment names, not values; the secrets themselves live in the vendor’s secret store.

Workflow file versus runner

The workflow file is the configuration. The runner is the executor. The two are separate concerns:

flowchart LR
    A["Workflow file\n.github/workflows/ci.yml"] -->|"read by"| B["CI controller"]
    B -->|"schedules"| C["Runner pool"]
    C --> D["Runner 1"]
    C --> E["Runner 2"]
    C --> F["Runner N"]

A change to the workflow file changes what runs. A change to the runner changes where it runs. Mixing the two is a common configuration-management error: a workflow that hard-codes a runner label, a network assumption, or a tool path is a workflow that cannot be moved to a different runner without editing the workflow.

Production discipline

  1. The workflow file is review-gated. A change to .github/workflows/ requires a reviewer; treat it as production configuration.
  2. Validate the YAML on every PR. Use actionlint, ci-lint, or the vendor’s own validator. YAML errors are runtime errors; catch them at review time.
  3. Pin action versions to a SHA, not a tag. A tag can be re-pointed at a different commit; a SHA cannot.
  4. Do not commit secrets. Reference them by name. The workflow file is reviewable; secrets are not.
  5. Keep the workflow portable across runner images. Do not hard-code paths that exist only on the default GitHub-hosted runner.

Cross-course references

  • Linux for Production Sysadmins - Parts XXVIII (UnitConf) and XXXIV (ConfigMgmt) cover the same pattern: configuration lives in a versioned file, not in a runtime mutation.
  • Ansible for Production Sysadmins - Part XXXVII (RepoArch) treats the Ansible repository the same way: a single versioned artifact whose contents are review-gated.
  • Terraform for Production Sysadmins - Part XI (StateBackend) treats the Terraform configuration the same way; the CI pipeline is a peer of the configuration it applies.

Quiz

Knowledge check · 4 questions

  1. Q1. An engineer changes a workflow file in `.github/workflows/deploy.yml` to add a new step. Which property of the pipeline-as-code model makes this change auditable six months later?

  2. Q2. A workflow file is portable between any two CI vendors because it is plain YAML.

  3. Q3. State the canonical file path for a GitHub Actions workflow file and name the two commands used to read a workflow file from the repository root.

  4. Q4. Diagnose why a workflow change bypassed review and recommend a control to prevent recurrence.

    Engineer E pushes a commit directly to the default branch that modifies `.github/workflows/deploy.yml` to remove a required manual approval step. The next deploy runs without approval. The change is not in any pull request; it appears in `git log` with E's personal email. The team's branch protection rule exempts workflow files because 'they are not code'.

Passing score: 75%. Answers are checked in this browser.