Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions .github/workflows/rust-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Rust CI

on:
push:
branches: [main]
branches: [build/kvm-ci-runner]
# Documentation-only edits do not affect the Rust artifact graph; skipping
# avoids spinning ~30min nextest lanes and cancelling in-flight runs via
# extra pushes (see paths-ignore semantics for bundled PR diffs).
Expand Down Expand Up @@ -41,9 +41,20 @@ env:
OTEL_EXPORTER_OTLP_ENDPOINT: ""

jobs:
# Wakes the self-hosted GCP runner (auto-stops after idle). All kvm-gcp
# jobs gate on this transitively via `changes`.
# id-token: write is required for the reusable workflow's WIF auth; it
# has to be granted at the caller side too (intersection semantics).
start-runner:
permissions:
id-token: write
contents: read
uses: ./.github/workflows/start-kvm-runner.yml

changes:
name: Detect sandbox lane changes
runs-on: arc-runner-set
runs-on: kvm-gcp
needs: start-runner
outputs:
sandbox_changed: ${{ steps.filter.outputs.sandbox }}
steps:
Expand All @@ -66,7 +77,7 @@ jobs:

doctor:
name: Workspace integrity (doctor)
runs-on: arc-runner-set
runs-on: kvm-gcp
needs: changes
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -104,7 +115,7 @@ jobs:

nextest:
name: Nextest (workspace)
runs-on: arc-runner-set
runs-on: kvm-gcp
needs: changes
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -312,7 +323,7 @@ jobs:

sandbox-adapter:
name: Sandbox adapter (stdio E2E + protocol)
runs-on: arc-runner-set
runs-on: kvm-gcp
needs: [changes, nextest]
if: needs.changes.outputs.sandbox_changed == 'true'
steps:
Expand Down Expand Up @@ -386,7 +397,7 @@ jobs:

sandbox-adapter-image:
name: Sandbox adapter image (no-publish)
runs-on: arc-runner-set
runs-on: kvm-gcp
needs: [changes, nextest]
if: needs.changes.outputs.sandbox_changed == 'true'
env:
Expand Down Expand Up @@ -575,7 +586,7 @@ jobs:

sandbox-adapter-image-handoff:
name: Sandbox image metadata handoff validation
runs-on: arc-runner-set
runs-on: kvm-gcp
needs: [changes, nextest, sandbox-adapter-image]
if: needs.changes.outputs.sandbox_changed == 'true'
steps:
Expand Down
11 changes: 9 additions & 2 deletions .github/workflows/sandbox-e2e-kvm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,16 @@ env:
ROOTFS_TAR: sandbox-echo-rootfs.tar

jobs:
start-runner:
permissions:
id-token: write
contents: read
uses: ./.github/workflows/start-kvm-runner.yml

prepare-fixture:
name: Prepare local sandbox fixture bind rootfs artifact
runs-on: kvm-enabled
runs-on: kvm-gcp
needs: start-runner

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -127,7 +134,7 @@ jobs:
kvm-e2e:
name: KVM E2E (baml-rt-tools)
needs: prepare-fixture
runs-on: kvm-enabled
runs-on: kvm-gcp

steps:
- uses: actions/checkout@v4
Expand Down
85 changes: 85 additions & 0 deletions .github/workflows/start-kvm-runner.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Start KVM Runner

# Reusable workflow that wakes the self-hosted GCP runner (auto-stopped after
# 20m idle) before jobs that need `runs-on: kvm-gcp`. Authenticates to GCP via
# Workload Identity Federation — no long-lived keys.
#
# Repo-level vars consumed (set via `gh variable set`):
# GCP_WIF_PROVIDER e.g. projects/123456789/locations/global/workloadIdentityPools/github/providers/github-oidc
# GCP_RUNNER_SA e.g. ci-agentium-os-ci-1@agentium-os.iam.gserviceaccount.com

on:
workflow_call:
inputs:
instance:
description: GCE instance name
type: string
default: agentium-os-ci-1
zone:
description: GCE zone
type: string
default: us-central1-a
project:
description: GCP project ID
type: string
default: agentium-os
wait_seconds:
description: Seconds to wait after `start` returns, so the actions-runner service has time to register with GitHub.
type: number
default: 60
workflow_dispatch:
inputs:
instance:
type: string
default: agentium-os-ci-1
zone:
type: string
default: us-central1-a
project:
type: string
default: agentium-os

permissions:
id-token: write
contents: read

# Two concurrent CI runs both call this — the second blocks on the first
# rather than racing the gcloud start API.
concurrency:
group: start-kvm-runner-${{ inputs.instance }}
cancel-in-progress: false

jobs:
start:
name: Start ${{ inputs.instance }}
runs-on: ubuntu-latest
steps:
- name: Authenticate to GCP
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ vars.GCP_WIF_PROVIDER }}
service_account: ${{ vars.GCP_RUNNER_SA }}

- name: Set up gcloud
uses: google-github-actions/setup-gcloud@v2

- name: Start instance if not running
run: |
set -euo pipefail
status=$(gcloud compute instances describe "${{ inputs.instance }}" \
--zone="${{ inputs.zone }}" --project="${{ inputs.project }}" \
--format='value(status)')
echo "current status: $status"
if [ "$status" = "RUNNING" ]; then
echo "instance already running, nothing to do"
exit 0
fi
gcloud compute instances start "${{ inputs.instance }}" \
--zone="${{ inputs.zone }}" --project="${{ inputs.project }}"

- name: Wait for actions-runner to register
# Cold-boot + idempotent startup-script + runner service ≈ 60s on
# resume. Listing self-hosted runners would need admin perms on the
# repo; instead we sleep and let GitHub queue dependent jobs until
# the runner re-registers itself.
run: sleep ${{ inputs.wait_seconds }}
Loading