◇ OpenCyber Academy
Technologist · Chapter 17 · English

Chapter 17 — Application and software supply chain security: tooling

Open, free learning for anyone who wants to protect people and technology. No account is required to read this text or its worked answers.

Chapter 17 — Application and software supply chain security: tooling

Lesson map

Lesson 17 published. Map, example, EX049.

flowchart TD
  N0["Learning outcomes"]
  N1["17.1 The pipeline as code"]
  N2["Lab — pipeline review"]
  N3["17.2 Lab result"]
  N4["17.3 Fixing permissions"]
  N5["17.4 Secrets and untrusted changes"]
  N6["17.5 Applying across projects"]
  N7["Keeping pins current"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7
  N7 --> EX["Worked example"]
  EX --> Q["Exercise EX049"]

Logical drawing

flowchart LR
  N0["Learning outcomes"]
  N1["17.1 The pipeline as code"]
  N2["Lab — pipeline review"]
  N3["17.2 Lab result"]
  N4["17.3 Fixing permissions"]
  N5["17.4 Secrets and untrusted changes"]
  N6["17.5 Applying across projects"]
  N7["Keeping pins current"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7 --> Q["EX049"]
[Learning outcomes]
    |
    v
[17.1 The pipeline as code]
    |
    v
[Lab — pipeline review]
    |
    v
[17.2 Lab result]
    |
    v
[17.3 Fixing permissions]
    |
    v
[17.4 Secrets and untrusted changes]
    |
    v
[17.5 Applying across projects]
    |
    v
[Keeping pins current]
    |
    v
[Worked example] --> [Exercise EX049]

Learning outcomes

You will (1) review build pipeline configuration; (2) pin pipeline actions; (3) limit token permissions; (4) protect secrets from untrusted changes.

17.1 The pipeline as code

Each project's pipeline is a configuration file in the repository. It decides which external actions run, which permissions the build token has and which secrets are available. Mistakes here affect every build. Because the configuration sits in the repository, changes to it go through the same review as code changes. The file also decides which branch can deploy, which is why the template restricts deployment to the main branch after review. Because the configuration lives in the repository, a change to it is visible in history, and reviewers can see when a permission was widened or an action changed. Diego's lab reads one such file and reports risky settings in plain language.

Lab — pipeline review

"""Check a synthetic CI configuration for risky settings."""
ci = {"steps": [{"uses": "checkout@v4"}, {"uses": "setup-node@3f2a9c1e"}, {"uses": "deploy-helper@main"}],
      "secrets_on_pull_requests_from_forks": True, "token_permissions": "write-all"}
issues = []
for s in ci["steps"]:
    ref = s["uses"].split("@")[1]
    if not (len(ref) >= 8 and all(c in "0123456789abcdef" for c in ref)):
        issues.append(f"step {s['uses']} not pinned to a commit")
if ci["secrets_on_pull_requests_from_forks"]: issues.append("secrets exposed to fork pull requests")
if ci["token_permissions"] != "read": issues.append(f"token permissions {ci['token_permissions']} (use read by default)")
for i in issues: print("-", i)
print(len(issues), "issues")

Run with python3 lab_ci.py. Verified output:

- step checkout@v4 not pinned to a commit
- step deploy-helper@main not pinned to a commit
- secrets exposed to fork pull requests
- token permissions write-all (use read by default)
4 issues

17.2 Lab result

The lab reports four issues in the synthetic pipeline: checkout@v4 and deploy-helper@main are not pinned to a commit, secrets are available to pull requests from forks, and the token has write-all permissions. Pinning to a full commit identifier means a changed action cannot silently enter the build. The lab treats any reference of at least eight hexadecimal characters as a commit, so setup-node@3f2a9c1e passes. That is looser than a full commit identifier, and Brightwave's template uses full identifiers.

17.3 Fixing permissions

The token gets read-only permission by default, with write only for the step that needs it. Write permission is granted only to the deployment step that pushes the image, after review on the main branch. The other steps can read the repository but cannot change it. Applying this across the nine pipelines that had write-all tokens is part of the three-week fix. Read-only by default means a mistaken or harmful step cannot push code or change settings in the repository.

17.4 Secrets and untrusted changes

Pull requests from outside contributors run without secrets. Deployment runs only from the main branch after review. Pull requests from forks are code written by people outside Brightwave, so running them with secrets would let an unknown change read deployment keys. Two pipelines exposed secrets this way, and both were fixed on the first day. Main-branch deployment means every change reaching a client has passed review. Contributors from outside still get test results on their pull requests, only without access to any secret.

17.5 Applying across projects

Diego runs the review across all 23 pipelines and opens fix pull requests in batches. Batching groups similar fixes, so reviewers see one kind of change at a time across several projects. The secret exposures are fixed first, unpinned actions and write-all tokens follow, and the template stops new projects repeating the same issues. The review script is the lab code extended to read every pipeline file in Brightwave's repositories. Across 23 pipelines it found 41 unpinned actions, 9 write-all tokens and 2 pipelines exposing secrets to forks. Each batch of fix pull requests is reviewed by the project owner.

Keeping pins current

Pinned actions are updated by the same weekly bot that updates libraries. Each update shows the old and new commit, and reviewers check the action's release notes before approving. This keeps the protection of pinning without leaving old versions in place forever. Diego also writes a short template pipeline with safe defaults (pinned actions, read-only token, no secrets for forks) that new projects copy, so the same mistakes are not repeated. Within two months every new project starts from the template.

Worked example

Across 23 pipelines, the review finds 41 unpinned actions, 9 write-all tokens and 2 pipelines exposing secrets to forks. All are fixed within three weeks, with the secret exposures fixed on the first day.

Synthetic case. Pipelines and counts are synthetic.

Errors and limits

Pinning needs updating too; a pinned old action can miss its own fixes.

Exercises

Synthesis

Treat pipeline configuration as security-critical code.

Continue studying — chapter 17 of 30

← Chapter 16 (draft) · Course chapter index · Chapter 18 (draft) →