How Do I Audit Runner Configuration Changes?

Changes made through the WarpBuild API are attributable to the key that made them, so scoping one key per person and per automation keeps the record useful.

Last verified:

Answer

Changes made through the WarpBuild API are attributable to the API key that made them, so the key scheme is what decides whether the record is useful: one key per person and one key per automation, never one shared key for the whole platform team.

Runner configuration spans three surfaces, so the record sits in three places. Find the layer your change belongs to first, because the answer to "who changed this" comes from a different system in each one.

What changedWhere the change happensWhat carries the record
Which runner a job uses (the runs-on label)The workflow file in your repositoryThe commit, the pull request, and git blame on that line
Runner registration, removal, and runner group membershipYour GitHub organizationGitHub organization audit log events, including org.register_self_hosted_runner, org.remove_self_hosted_runner, org.runner_group_updated, and org.runner_group_runners_added (GitHub audit log events, checked 2026-08-13)
Custom runner definitions, runner images, pool sizes, and BYOC stacksThe WarpBuild dashboard or the WarpBuild APIThe API key on the call, plus the created_at and updated_at fields the API returns on every runner object (automation documentation)

The third row is the one teams get wrong. A setting edited by hand in a dashboard produces a new state with a timestamp on it, while the same setting changed through a key that belongs to one workflow produces a commit, a reviewer, a run log, and a timestamp. Routing configuration through the API is what turns the third row into evidence.

Detail

The API key model

API keys are created on the API keys page in your WarpBuild settings, and each key is scoped to a combination of WarpBuild products: CI, Cache, and Helios. The key is displayed once at creation, so it has to be stored at that moment. The name and the scope stay editable afterwards, which matters for the scheme below, because a key keeps working through a rename.

Calls carry the key in the Authorization header, and the key prefix makes it recognizable in a secret store:

curl -sS -X GET 'https://api.warpbuild.com/api/v1/runners?only_custom_runners=true' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer wkey-xxxx'

The automation documentation covers the runner and runner image endpoints and states that a key needs the ci and cache scopes for that work. It also flags one operational fact worth writing into a runbook: deleting a runner through DELETE /api/v1/runners/<runner-id> is irreversible, so that call belongs behind a review gate rather than in a shell history.

A key scheme that keeps changes attributable

Scopes are product level, so a ci key that can read runners can also write them. The separation that holds up is one key per caller plus a workflow that only issues the calls it needs. Treat the key name as the actor field of your record.

Key nameScopeHeld byCalls it makesRevoke or rotate
person-asharma-ciCIOne named platform engineer, in her password managerAd hoc reads and one-off fixesAt offboarding, and on a 90 day rotation
svc-runner-images-ci-cacheCI, CacheThe image build workflow, as a repository secretPOST and PUT on /api/v1/runner-images90 day rotation
svc-pool-apply-ciCIThe apply workflow, as a secret on a protected environmentPATCH on /api/v1/runners90 day rotation
svc-inventory-read-ciCIThe nightly snapshot workflowGET on /api/v1/runners only180 day rotation

Two rules make the table work. No key is shared between a person and an automation, because a shared key erases the difference between a scripted change and a manual one. Every key name starts with person- or svc-, so an unexpected change is traced to a human or to a workflow before anyone opens a log.

Put the change in a pull request

The strongest record is the one GitHub already keeps for you. Store the runner payload as a file in your repository, apply it from a workflow on merge, and the change carries a diff, a reviewer, and an Actions run log with a timestamp.

name: apply-runner-config
on:
  push:
    branches: [main]
    paths:
      - "runners/**.json"

permissions:
  contents: read

jobs:
  apply:
    runs-on: warp-ubuntu-latest-x64-2x
    environment: runner-admin
    env:
      RUNNER_ID: wrslzvbl322yttsc
    steps:
      - uses: actions/checkout@v5

      - name: Apply the runner definition
        env:
          WARPBUILD_API_KEY: ${{ secrets.WARPBUILD_POOL_APPLY_KEY }}
        run: |
          curl -sS --fail-with-body -X PATCH \
            "https://api.warpbuild.com/api/v1/runners/${RUNNER_ID}" \
            -H 'Accept: application/json' \
            -H "Authorization: Bearer ${WARPBUILD_API_KEY}" \
            -H 'Content-Type: application/json' \
            -d @runners/build-pool.json

The environment: runner-admin line is the review gate. Configure that environment with required reviewers in your repository settings and the job waits for a named approver before the PATCH is sent, so the approval is recorded next to the diff.

Snapshot the inventory on a schedule

Reviews ask what changed between two dates, and a scheduled read answers that without any product feature behind it. The runner objects returned by GET /api/v1/runners include updated_at, so a daily commit of the normalized list gives you a diffable history.

name: runner-inventory
on:
  schedule:
    - cron: "0 6 * * *"
  workflow_dispatch:

permissions:
  contents: write

jobs:
  snapshot:
    runs-on: warp-ubuntu-latest-x64-2x
    steps:
      - uses: actions/checkout@v5

      - name: Fetch the runner inventory
        env:
          WARPBUILD_API_KEY: ${{ secrets.WARPBUILD_INVENTORY_READ_KEY }}
        run: |
          curl -sS --fail-with-body \
            'https://api.warpbuild.com/api/v1/runners?only_custom_runners=true' \
            -H 'Accept: application/json' \
            -H "Authorization: Bearer ${WARPBUILD_API_KEY}" \
          | jq -S '[.[] | {name, active, labels, updated_at,
              image: .configuration.image,
              capacity_type: .configuration.capacity_type}]' \
          > inventory/runners.json

      - name: Commit the diff
        run: |
          git config user.name 'runner-inventory'
          git config user.email '[email protected]'
          git add inventory/runners.json
          git diff --cached --quiet || git commit -m "runner inventory $(date -u +%F)"
          git push

jq -S sorts keys so the diff is the change rather than a reordering. When a review asks who moved a pool from on demand to spot capacity in March, the commit that changed capacity_type is the answer, and the key that made the call is named in the apply workflow that produced it.

What the GitHub side already logs

WarpBuild runners register with GitHub as self-hosted runners, so GitHub's own organization audit log carries the registration and group events listed in the first table. Three limits are worth knowing before you rely on it. The log holds the last 180 days of events, only organization owners can open it, and the web view shows the past three months unless you pass a created date range, per the GitHub audit log documentation checked on 2026-08-13. Organizations on GitHub Enterprise Cloud can read the same events through the audit log REST and GraphQL APIs, which is the path to a longer retention window in your own store.

Why the label line deserves the same review

A one-line edit to runs-on changes what a job costs, which is the usual reason a finance question turns into an audit question. WarpBuild provides Linux x64, Linux ARM64, macOS, and Windows runners, and the per-minute rate is set by the label:

LabelvCPURAMUSD per minute
warp-ubuntu-latest-x64-2x28 GB$0.004
warp-ubuntu-latest-x64-4x416 GB$0.008
warp-ubuntu-latest-x64-8x832 GB$0.016
warp-ubuntu-latest-x64-16x1664 GB$0.032
warp-ubuntu-latest-x64-32x32128 GB$0.064

Rates from the pricing page, checked on 2026-08-13. A job that runs 20,000 minutes a month costs $160 on warp-ubuntu-latest-x64-4x and $640 on warp-ubuntu-latest-x64-16x, a difference of $480 a month from one edited line. It shows up in the usage line, which is why the commit that made it is the artifact you want.

SSO for teams managing access centrally

SSO decides who can reach the account where these settings live. WarpBuild supports SAML 2.0 and OIDC on enterprise plans for a flat $250 per month, whatever the user count, and works with Okta, Microsoft Entra ID, Google Workspace, Auth0, Microsoft AD FS, OneLogin, PingOne, JumpCloud, Rippling, and any SAML 2.0 or OIDC-compliant provider, per the SSO documentation. Provisioning runs through support, and the identity provider connection is then configured from a one-time setup link with no WarpBuild login required.

The tie-in to this page is offboarding. Removing a person in your identity provider ends their dashboard access, and it does nothing to an API key they created, because keys are issued and revoked inside the account. An offboarding checklist that covers both is the reason the person- prefix in the key table exists.

Where is the record of a runner configuration change?

In three places, depending on which setting moved. The runs-on label lives in the workflow file, so the commit and the pull request are the record. Runner registration and runner group membership are GitHub organization events that land in the GitHub audit log. Runner definitions, images, and pools live in WarpBuild, where a change made through the API is attributable to the key that made the call and every runner object returns created_at and updated_at. The audit log glossary entry covers the general shape of an audit record, and the security review checklist puts this question in the order reviewers ask it.

How should we scope API keys so changes stay attributable?

One key per person and one key per automation, with the owner and the purpose in the name. Scopes are product level (CI, Cache, and Helios), so the key name is what identifies the caller rather than the scope. Keys are displayed once at creation, so each one goes straight into the secret store that belongs to its holder: a password manager for a person, a repository or environment secret for a workflow. Revoke at offboarding and rotate on a schedule you write down. The API keys documentation covers creation, scopes, and editing.

Does SSO change who can edit runner settings?

SSO governs who can sign in to the WarpBuild account where runners, BYOC stacks, usage, and billing live, so deprovisioning a user in your identity provider removes that access. SSO costs a flat $250 per month, whatever the user count. API keys are separate and are revoked inside the account, so both belong on the same offboarding checklist. SSO for GitHub Actions runner access covers the protocols, the attribute mapping, and what happens to running workflows during a rollout.

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.