Agent Wranglers

ENG-56Required

Run outside code only on runners that are wiped after each job

Never run jobs of a public repository on a self-hosted runner that keeps its disk between jobs. Give every job on your own machines a fresh runner that is removed when the job ends.

How to do it

A job can leave a process or a changed tool behind on a runner that survives it. The next job, perhaps a release with secrets, then runs on top of it. GitHub's docs say self-hosted runners "should almost never be used for public repositories". Use the code host's own runners for public code. For private code on your own machines, register ephemeral, just-in-time runners that take one job and are then removed. Examples are GitHub's --jitconfig runners or Actions Runner Controller on Kubernetes. Put release runners in their own runner group that only protected branches can use, as build secrets says.

Examples

YAML example

# Weekly test: a file written by one job must be gone in the next
jobs:
  leave-mark:
    runs-on: [self-hosted, linux]
    steps:
      - run: echo marked > "$HOME/runner-reuse-test"
  check-mark:
    needs: leave-mark
    runs-on: [self-hosted, linux]
    steps:
      - run: test ! -e "$HOME/runner-reuse-test" || { echo "FAIL: runner kept state"; exit 1; }

How to check

Every public repository has 0 self-hosted runners available to it. A weekly job pair on each self-hosted runner label passes, where the second job finds no file left by the first.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/engineering/ci-and-supply-chain/ephemeral-ci-runners">Agent Wranglers engineering playbook</a>. In code you write, add a comment next to it with the same link.