Skip to content

WorkWingman workflow changes (do these IN the WorkWingman repo)

This repo does not modify WorkWingman. This doc lists the exact runs-on: label edits the WorkWingman workflows need so their jobs route to the self-hosted warm pool instead of GitHub-hosted runners, plus the concurrency groups that provide duplicate suppression.

Job inventory was taken from the current WorkWingman workflows: .github/workflows/ci.yml and .github/workflows/mutation.yml.

Label sets

  • Linux (Docker) runner: [self-hosted, workwingman, linux, docker, x64]
  • Windows (host) runner: [self-hosted, workwingman, windows, x64]

Always list ALL the labels (array form) so a job only lands on a fully-matching runner.

ci.yml — per-job runs-on: changes

Job Before After
backend windows-latest [self-hosted, workwingman, windows, x64]
frontend ubuntu-latest [self-hosted, workwingman, linux, docker, x64]
sast ubuntu-latest [self-hosted, workwingman, linux, docker, x64]
secrets ubuntu-latest [self-hosted, workwingman, linux, docker, x64]
dast ubuntu-latest [self-hosted, workwingman, linux, docker, x64]
security ubuntu-latest [self-hosted, workwingman, linux, docker, x64]
churn ubuntu-latest [self-hosted, workwingman, linux, docker, x64]
docs ubuntu-latest [self-hosted, workwingman, linux, docker, x64]
diagrams ubuntu-latest [self-hosted, workwingman, linux, docker, x64]
dotnet-e2e ubuntu-latest [self-hosted, workwingman, linux, docker, x64]
electron-e2e ubuntu-latest [self-hosted, workwingman, linux, docker, x64]

Only backend is Windows (it exercises the DPAPI / System.Security.Cryptography.ProtectedData path and installs Playwright via PowerShell). Everything else is Linux.

mutation.yml — per-job runs-on: changes

Job Before After
backend-mutation ubuntu-latest [self-hosted, workwingman, linux, docker, x64]
frontend-mutation ubuntu-latest [self-hosted, workwingman, linux, docker, x64]

Note: backend-mutation currently runs on ubuntu (Stryker.NET on the Linux .NET SDK), so it stays on the Linux label set. Only backend in ci.yml needs Windows.

Before/after YAML snippet (illustrative)

# ci.yml — backend (Windows job)
  backend:
-   runs-on: windows-latest
+   runs-on: [self-hosted, workwingman, windows, x64]

# ci.yml — every ubuntu job, e.g. frontend
  frontend:
-   runs-on: ubuntu-latest
+   runs-on: [self-hosted, workwingman, linux, docker, x64]

Duplicate suppression — add concurrency

The warm pool deliberately has NO runner-side coordination. To stop overlapping runs of the same ref from piling up (and to make requeues idempotent), add a concurrency group. Top-of-file (workflow-level) is simplest:

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

Add this to both ci.yml and mutation.yml. For mutation (long, scheduled) you may prefer cancel-in-progress: false so a running mutation isn't killed by a newer push — pick per workflow.

Things to check when migrating

  • Docker-in-job: sast, secrets, dast use Docker/containers. The Linux runner container would need Docker access (docker-outside-of-docker via the host socket) for those. Options: (a) mount the host Docker socket into the runner container in Watchdog-Linux.ps1 (-v /var/run/docker.sock:... — note security tradeoff), or (b) keep those three specific jobs on ubuntu-latest (GitHub-hosted) and only self-host the rest. Decide during rollout; this is the one place the OS-matrix split may widen.
  • xvfb / Electron (electron-e2e): already installs its own xvfb; the Linux image has the base deps. Verify display setup inside the container on first run.
  • Tool availability: the pinned Linux image is intentionally minimal (git, curl, jq, unzip). Jobs relying on actions/setup-node / setup-dotnet will install their own toolchains at job time, which works on self-hosted runners.
  • First-run: trigger one PR and watch Runner-Status.ps1 — the queued job should pick up on an idle ww-<pc>-<guid> runner within seconds.