Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXL · RunnersRunners

Runner tooling and actions — what is installed, GitHub-managed actions, and the marketplace

Intermediate⏱ ~21 mingit

What you'll learn

  • Identify the runtime that a runner image provides out of the box
  • Distinguish GitHub-managed actions from first-party actions from third-party marketplace actions
  • Pin actions by full-length commit SHA rather than by tag
  • Recognise the supply-chain risk of arbitrary marketplace actions
  • Decide when to use an action versus when to write the step inline

Prerequisites

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.

A runner is the trust boundary for code. A workflow that says uses: someorg/someaction@v1 is asking GitHub to clone the someorg/someaction repository at the v1 tag and run its entrypoint inside the workflow job. The action runs as the runner user, with the runner’s secrets, on the runner’s host. Picking an action is picking code to run.

Knowing which actions to trust, which to pin, and which to audit is the supply-chain half of CI security.

What the runner image provides

flowchart LR
    IMG["Runner image"] --> OS["OS packages\n(apt / brew / choco)"]
    IMG --> LANG["Languages\n(python, node, go, ruby)"]
    IMG --> TOOLS["Tools\n(git, docker, jq, curl)"]
    IMG --> RUNNER["Runner binary"]
    IMG --> NULL["(no extra CI tooling)"]

The image provides the operating system, the language runtimes, and the common tools. It does not provide CI tooling. There is no pytest, no eslint, no terraform baked in — those come from actions/setup-* or from explicit pip install / npm install steps inside the job. This is by design: the team owns what the workflow needs.

ToolOn hosted ubuntu-latestOn self-hosted
gitYesDepends
python3YesDepends
nodeYesDepends
dockerYes (rootless)Team installs
terraformNoTeam installs
kubectlNoTeam installs

Actions: three tiers

flowchart TB
    T1["Tier 1: GitHub-managed\n(actions/*)"] --> SAFE["Highest trust:\nGitHub owns and patches"]
    T2["Tier 2: First-party\n(github.com/*)"] --> SAFE2["Trusted:\nforge-owned, audited"]
    T3["Tier 3: Marketplace\n(community)"] --> RISK["Lowest trust:\nanyone can publish"]

The three tiers of actions, ordered by trust:

  1. GitHub-managed actions. Repositories under the actions/ organisation: actions/checkout, actions/setup-node, actions/setup-python, actions/cache, actions/upload-artifact. GitHub owns these, patches them, and is the canonical source. Use freely.
  2. First-party actions. Repositories under github.com/* that the forge or GitHub org maintain: github/codeql-action, github/import-into-pulumi, etc. Owned by GitHub or closely audited. Use with pinning.
  3. Third-party marketplace actions. Anyone with a GitHub account can publish one. Examples: third-party Docker build actions, language installers from community maintainers, integration actions for SaaS APIs. Use with SHA pinning and review.

Pinning by SHA

flowchart LR
    A["uses: actions/checkout@v4"] -->|"mutable tag"| B["v4 = whatever the\nmaintainer tagged today"]
    C["uses: actions/checkout@\nb4b15b8a7c6d21ea4f18a9f63d6d8e6e3c6e8e3f"] -->|"immutable"| D["Exact commit,\nforever"]

Tags are mutable. The maintainer can move the v4 tag to a different commit tomorrow; the workflow that said @v4 yesterday is now running a different action today. Tags are also forge-controlled — anyone with write access to the action repository can move them.

Commit SHAs are immutable. A workflow that pins by SHA runs the same code today, next month, and in three years. The trade is that humans do not read SHAs, so the team pairs SHA pinning with a code-review step that approves the specific commit.

# Mutable (do not use in production)
- uses: actions/checkout@v4

# Pinned to a tag's commit (better)
- uses: actions/checkout@v4.1.7

# Pinned to a full SHA (best)
- uses: actions/checkout@b4b15b8a7c6d21ea4f18a9f63d6d8e6e3c6e8e3f

The build-versus-buy decision

flowchart LR
    A["Need X in workflow"] --> Q{"Does GitHub\nship an action?"}
    Q -->|Yes| USE["Use GitHub-managed\naction, pinned by SHA"]
    Q -->|No| Q2{"Does a\nfirst-party action\ncover it?"}
    Q2 -->|Yes| USE2["Use first-party\naction, pinned, audited"]
    Q2 -->|No| Q3{"Is the third-party\naction trustworthy?"}
    Q3 -->|Yes| USE3["Use, pin by SHA,\naudit code"]
    Q3 -->|No| WRITE["Write the step inline\nin the workflow"]

The default answer for a step the workflow needs is:

  1. GitHub-managed action first. actions/checkout, actions/setup-node, actions/cache — these exist for almost every common need and are the safest choice.
  2. First-party action if GitHub does not ship one. A github/codeql-action or similar is owned by the forge.
  3. Third-party action only after audit. Read the code, pin by SHA, document the rationale in the repo.
  4. Inline shell if no action is trustworthy. A 5-line shell snippet is more auditable than a 200-line action the team has not read.

The marketplace trap

A common anti-pattern:

# Anti-pattern: chained marketplace actions
- uses: org-A/setup-foo@v2
- uses: org-B/setup-bar@v1
- uses: org-C/deploy@v3

Each uses clause is a third-party code dependency. Three clauses means three supply-chain trusts. The team has to audit three repositories, monitor three SHA pin updates, and trust three maintainers. If any one is compromised, the workflow is compromised.

The counter-pattern: pick a small set of trusted actions, pin them by SHA, and write the rest inline. A workflow with two uses: actions/* clauses and ten run: | steps is more auditable than a workflow with five third-party uses clauses.

Production discipline

  1. Pin every action by full-length SHA. Tags are mutable; SHAs are immutable.
  2. Use GitHub-managed actions by default. actions/* is the safest set.
  3. Audit any third-party action before use. Read the source, check the maintainers, check the network calls.
  4. Limit the number of distinct actions. A workflow that uses 15 actions has 15 supply-chain trusts.
  5. Document the action policy. A CONTRIBUTING.md note explaining “we use GitHub-managed actions pinned by SHA” prevents ad-hoc drift.

Cross-course references

  • Linux for Production Sysadmins - Part XXX (PkgTrust) covers the package-pinning patterns that map onto action SHA pinning.
  • Ansible for Production Sysadmins - Part XXXVI (ModuleTrust) covers the role-trust patterns that map onto third-party actions.
  • Terraform for Production Sysadmins - Part XXXIX (ProvTrust) covers the provider-pinning patterns that match action SHA pinning.

Quiz

Knowledge check · 4 questions

  1. Q1. Why is pinning an action by full-length commit SHA safer than pinning by tag?

  2. Q2. A third-party marketplace action runs with the same access to the runner host and job secrets as a step written inline in the workflow.

  3. Q3. Name the three tiers of actions in order of trust, and which tier GitHub-managed actions like `actions/checkout` belong to.

  4. Q4. Audit a workflow's action list and replace unsafe uses clauses with safer alternatives.

    Team T's deploy workflow uses the following actions: `actions/checkout@v4`, `actions/setup-node@v4`, `random-org/fancy-deploy@v2`, `another-org/secret-rotator@main`, `third-org/cleanup@v1`. None are SHA-pinned. The team is concerned about supply-chain risk.

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