Running Managed Runners on Open Source Projects

Managed runners reach public repositories once the Default runner group allows them. Enablement steps, fork pull request controls, and per-minute costs.

Managed runners run public repository jobs once an organization owner checks Allow public repositories on the Default runner group, because GitHub disables self-hosted and managed runners in public repositories by default. The rest of the work is deciding which jobs a pull request from a fork may run on, and pricing the jobs that outgrew the free GitHub-hosted pool.

This guide covers the enablement steps from the public repositories documentation, the fork pull request threat model with the GitHub settings that contain it, a routing workflow, and a cost model with the arithmetic written out.

Diagnosis

Open source projects hit three separate problems, and they get confused with each other because all three end with a slow or stalled pipeline.

Jobs queue forever on a warp- label. WarpBuild registers itself as a self-hosted runner in the Default runner group, id 1, for your GitHub organization, and GitHub disables self-hosted runners in public repositories by default. The runner fleet looks connected in the dashboard, the workflow file is valid, and the job never starts. That is the runner group setting rather than a capacity problem.

The maintainers vetoed managed runners on security grounds. GitHub's self-hosted runner guidance recommends disabling self-hosted runners on public repositories, and the reason is the machine rather than the trigger. A pull request is a proposal to run arbitrary code. On a persistent runner that code inherits the instance profile, the local caches, and the network routes of every job that ran before it. The public repositories documentation names container fleets such as actions-runner-controller as the sharp case, since workflows there run in containers that share a kernel with the host.

The free public shape ran out of cores. GitHub gives public repositories a 4 vCPU, 16 GB standard Linux runner, against 2 vCPU and 8 GB on private repositories (GitHub-hosted runner specs, checked on 2026-08-13). Compile-heavy projects saturate that shape and stay saturated. Reaching for a larger GitHub-hosted label is billed on a public repository at the same per-minute rates a private repository pays (GitHub Actions minute multipliers, checked on 2026-08-13), so the free path ends at that point regardless of which fleet you pick. Where exactly that boundary sits is worked through in are GitHub Actions free for open source repositories.

Fix

Work the three in order. Enablement is a two-minute change, containment is a settings pass, and routing is one workflow edit.

Enable the Default runner group for public repositories

From the public repositories documentation, an organization owner does this:

  1. Open https://github.com/organizations/[YOUR_ORG]/settings/actions/runner-groups/1.
  2. Check the box for Allow public repositories.

GitHub Enterprise supports creation of multiple runner groups, and WarpBuild runners are added to the Default group, id 1, there as well. On Enterprise the box to check is therefore on that group rather than on a group someone created for another fleet. Group membership and repository access are covered in GitHub's runner group access documentation.

Contain the fork pull request

State the threat model in both directions before touching settings.

What a fork's code reaches: the runner machine, whatever that machine can reach on the network, and whatever an earlier job left on its disk.

What it does not reach on the default pull_request trigger: repository secrets are not passed to workflows triggered from a fork, and the run's GITHUB_TOKEN is read-only (GitHub events reference, checked on 2026-08-13).

Four settings hold that line:

  • Fork pull request approval. In organization or repository Actions settings, require approval for all outside collaborators rather than first-time contributors only. A maintainer then reviews the diff before any job starts (approving runs from forks, checked on 2026-08-13).
  • Default workflow permissions. Set the repository default for GITHUB_TOKEN to read-only and grant write scopes per job in the workflow file (workflow syntax reference, checked on 2026-08-13).
  • Trigger choice. Keep build and test work on pull_request. The pull_request_target trigger runs with secrets and a writable token in the base repository's context, so a workflow that uses it and then checks out the fork's head commit hands over what the default trigger withholds.
  • Deployment secrets behind environments. Anything that needs a real credential belongs in a job gated by an environment with required reviewers, which keeps the credential out of any run a contributor can trigger.

One extra rule applies if the project reuses a prepared disk between runs: keep credential files off that disk. The specifics are in are snapshot runners safe for public repositories.

Put contributor code on a machine that ends with the job

The security documentation describes the runner lifecycle. Each runner runs in its own virtual machine, created on demand and destroyed after each build. The VMs are ephemeral and never reused. Each runner also gets its own encrypted storage volume on the same cycle, and WarpBuild does not access or store build secrets. One contributor's job cannot read what a previous job left behind, because the disk it would read is gone.

The runner images carry the same tools and versions as GitHub-hosted runners, so a public repository's workflow file stays portable between the two label sets and a contributor who only has the free pool can still reproduce a failure locally from the same tool versions.

Configuration

Rates below come from the pricing page and the cloud runners catalog, checked on 2026-08-13.

LabelShapePer minuteCost of an 8 minute job
warp-ubuntu-latest-x64-2x2 vCPU, 8 GB$0.004$0.032
warp-ubuntu-latest-x64-4x4 vCPU, 16 GB$0.008$0.064
warp-ubuntu-latest-x64-8x8 vCPU, 32 GB$0.016$0.128
warp-ubuntu-latest-x64-16x16 vCPU, 64 GB$0.032$0.256
warp-ubuntu-latest-arm64-8x8 vCPU, 32 GB$0.012$0.096
warp-windows-latest-x64-4x4 vCPU, 16 GB$0.016$0.128
warp-macos-latest-arm64-6x6 vCPU, 22 GB$0.08$0.64

The routing workflow resolves the label inline, so no extra job is needed:

name: ci

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

jobs:
  test:
    runs-on: >-
      ${{ github.event.pull_request.head.repo.fork
          && 'ubuntu-latest'
          || 'warp-ubuntu-latest-x64-8x' }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npm test

  release-build:
    if: github.event_name == 'push'
    runs-on: warp-macos-latest-arm64-6x
    environment: release
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/build-release.sh

Three things are happening. Fork pull requests stay on the free GitHub-hosted pool, so a drive-by contributor costs the project nothing and never lands on a machine with an account behind it. Pushes to main and pull requests from branches inside the repository take warp-ubuntu-latest-x64-8x. The release leg runs after merge only, on a macOS label, inside an environment that can require a reviewer before its credentials are issued.

Public OSS repositories running warp- labels are citable evidence for this shape, and the workflow files are open to read. The bitcoin/bitcoin GitHub Actions workflow sizes its Linux jobs per job across warp- labels, from warp-ubuntu-latest-x64-2x for lint up to warp-ubuntu-latest-x64-16x for the fuzz and MSan matrices, with compiler caches restored and saved between runs. FuelLabs/sway builds and tests the Sway compiler on warp-ubuntu-latest-x64-4x jobs alongside GitHub-hosted ones in the same file, which is the mixed-fleet pattern above. The triggerdotdev/trigger.dev end-to-end workflow runs its matrix across warp-ubuntu-latest-x64-4x and warp-windows-latest-x64-8x. All three checked on 2026-08-13.

Cost or Time Model

Price the split rather than the whole pipeline, because the fork side stays free. Assumptions for a mid-sized project:

  • 600 workflow runs in the month.
  • 420 of them come from fork pull requests and stay on ubuntu-latest, where minutes and storage cost a public repository nothing (GitHub Actions billing documentation, checked on 2026-08-13).
  • 180 come from maintainer branches and merges to main, each running one 9 minute Linux job on warp-ubuntu-latest-x64-8x.
  • 25 release runs add a 12 minute macOS leg on warp-macos-latest-arm64-6x.

The arithmetic at the rates in the table above:

LegMinutesRateCost
420 fork pull requests on ubuntu-latestfree$0.000$0.00
180 x 9 minutes on warp-ubuntu-latest-x64-8x1,620$0.016$25.92
25 x 12 minutes on warp-macos-latest-arm64-6x300$0.08$24.00
Month total1,920 billed$49.92

The dial to turn next is the fork share. Moving 100 of those 420 fork runs onto warp-ubuntu-latest-x64-4x at $0.008 per minute, for a 6 minute job, adds 600 minutes and $4.80 to the month. That is the honest price of giving trusted external contributors the faster machines, and it is small enough to test for a month and reverse with one line in the runs-on expression.

A quiet month bills less by the same arithmetic. There is no allowance to forfeit and no minimum to hit, so a project that ships nothing in August pays for the jobs it ran in August. Every per-size rate is on the pricing page, and do public repositories pay for runners prices a second job mix against the same table.

FAQ

Why do warp- labels never pick up jobs in my public repository?

GitHub blocks self-hosted and managed runners in public repositories by default. An organization owner has to open the Default runner group, id 1, at github.com/organizations/[YOUR_ORG]/settings/actions/runner-groups/1 and check Allow public repositories. Until that box is checked the job stays queued with no runner assigned. The public repositories documentation has the screenshot and the GitHub Enterprise note.

What can a pull request from a fork reach on a WarpBuild runner?

The machine it runs on, whatever that machine can reach on the network, and whatever is on its disk. On the default pull_request trigger it receives no repository secrets and a read-only GITHUB_TOKEN (GitHub events reference, checked on 2026-08-13). WarpBuild runs each job in its own virtual machine with its own encrypted volume, both destroyed when the job finishes, per the security documentation, so a contributor's job starts on a clean disk and leaves nothing behind.

Does an open source project need a seat count or a plan before it can use managed runners?

No. Managed runners are billed for the time jobs execute, so maintainers and drive-by contributors do not add a per-person charge. The pricing page lists the per-minute rates.

Start with $10 in free credits

Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.