Isolate release preparation and qualification on hosted VMs

Persistent prerelease runners can retain state from earlier source execution
and influence later admission, build output or qualification. Use the
existing hosted stable-release path for every channel while preserving
exact-source checks, resource planning, watchdogs and release gates.
This commit is contained in:
rcourtman
2026-09-12 15:44:11 +01:00
parent 5bf075e6ef
commit 051ce81a72
4 changed files with 33 additions and 51 deletions
+7 -8
View File
@@ -97,9 +97,9 @@ jobs:
actions: read
contents: read
pull-requests: read
# Stable releases use hosted runners regardless of their Windows-signing
# decision. Prereleases retain the credential-free PVE acceleration path.
runs-on: ${{ !contains(inputs.version, '-') && 'ubuntu-24.04' || fromJSON('["self-hosted","Linux","X64","pulse-pve-compile"]') }}
# Admission must start from a fresh VM for every release channel so earlier
# source execution cannot influence release preparation or its outputs.
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
version: ${{ steps.extract.outputs.version }}
@@ -400,7 +400,7 @@ jobs:
- prepare
- publication_trust_preflight
if: ${{ needs.prepare.outputs.historical_asset_backfill_only != 'true' }}
runs-on: ${{ !contains(inputs.version, '-') && 'ubuntu-24.04' || fromJSON('["self-hosted","Linux","X64","pulse-pve-build"]') }}
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout repository
@@ -497,15 +497,14 @@ jobs:
working-directory: frontend-modern
run: npm test -- --run src/utils/__tests__/agentInstallCommand.windows.test.ts
# The dedicated PVE test runner provides the memory needed to run two
# complete, disjoint internal/api shards while all other packages run in a
# third lane. It holds no signing or publication credentials.
# Every channel qualifies on a fresh hosted VM. The existing planner admits
# disjoint API shards from measured capacity without sharing prior job state.
backend_tests:
needs:
- prepare
- frontend_bundle
if: ${{ needs.prepare.outputs.historical_asset_backfill_only != 'true' }}
runs-on: ${{ !contains(inputs.version, '-') && 'ubuntu-24.04' || fromJSON('["self-hosted","Linux","X64","pulse-pve-tests"]') }}
runs-on: ubuntu-24.04
# The rc.9 race-enabled API shards consumed more than 18 minutes on the PVE
# runner before post-step accounting. Keep the outer job above the canonical
# 45-minute API watchdog so checkout, bundle transfer, shard planning, and
@@ -18,10 +18,9 @@ permissions:
jobs:
qualify:
name: Exact-Candidate Container and Helm Smoke
# Stable qualification must be independent of persistent runner disk state.
# Prereleases keep the faster PVE lane, where a later clean rehearsal can
# expose and repair runner capacity without blocking a stable patch.
runs-on: ${{ !contains(inputs.version, '-') && 'ubuntu-24.04' || fromJSON('["self-hosted","Linux","X64","pulse-pve-build"]') }}
# Every channel qualifies on a fresh VM so previous source execution cannot
# influence the Docker daemon, smoke results or filesystem state.
runs-on: ubuntu-24.04
timeout-minutes: 15
env:
VERSION: ${{ inputs.version }}
@@ -1138,27 +1138,22 @@ artifact-selection behaviour.
integration-environment preparation as independent lanes after producing
the frontend embed bundle. Its receipt must distinguish elapsed wall time
from the sum of overlapping phase times.
The canonical public prerelease workflow may run its credential-free prepare
job on the PVE compilation identity so hosted-runner allocation cannot hold
the entire dependency graph. Stable releases must use GitHub-hosted runners
for preparation, the frontend embed bundle, and the backend race gate
regardless of whether Windows signing is required or a version-bound
unsigned-Windows exception applies. Runner selection is a release-channel
reliability decision and must not be coupled to signing policy. Prerelease
preparation must release the PVE identity before exact-SHA compilation
becomes eligible and must use a complete exact-SHA checkout: leaving
sparse-worktree state in the persistent runner can make the following
compilation checkout appear complete while required root files remain
absent.
Release preparation runs on a fresh GitHub-hosted VM for every channel.
Previous source execution must not influence admission or the outputs that
start the release dependency graph. It retains a complete exact-SHA checkout
and all snapshot, source and workflow identity checks. Frontend, backend and
exact-container qualification also use fresh hosted VMs for every channel,
independently of Windows-signing policy. Existing capacity planning, inner
watchdogs and qualification criteria remain unchanged.
Signing, package publication, and release mutation authority must remain on
hosted jobs. The bundle job must be independent from frontend quality so
backend and browser-smoke lanes can start as soon as the bundle is available.
Cross-platform compilation for every release channel runs once on the
dedicated, credential-free PVE compiler identity using only public embedding
keys in a separately dispatched GitHub Actions workflow run. The release
fresh GitHub-hosted compiler VM using only public embedding keys in a
separately dispatched GitHub Actions workflow run. The release
candidate and SignPath workflow run must contain only GitHub-hosted jobs;
its hosted handoff job may dispatch and wait for the isolated compiler run,
but the self-hosted job must never appear in the signing run. The compiler
and compilation must remain separate from signing authority. The compiler
workflow must execute from the same exact workflow SHA as the parent release
and must produce one exact-version, exact-source-SHA manifest
covering the complete frontend and binary payload. That manifest may cover
@@ -1179,7 +1174,7 @@ artifact-selection behaviour.
from an earlier sibling step, because GitHub Actions does not preserve
step-local environment variables across steps.
Private signing material and publication credentials must never enter the
PVE compilation job.
compilation job.
Post-publication secure-runtime qualification must authenticate before it
executes. `.github/workflows/qualify-secure-runtime-release.yml` may download
caller-owned release assets only into a non-executable holding directory.
@@ -1198,7 +1193,7 @@ artifact-selection behaviour.
useful test or compilation process has already completed.
Private Pro compilation must additionally bind the exact Pulse and
pulse-enterprise commits in a manifest-covered identity record. It runs once
on the dedicated credential-free PVE enterprise compiler for every channel,
on a fresh hosted VM for every channel without restored build caches,
then crosses the same immutable GitHub artifact-id, archive-digest, run-id,
head-SHA, and inner-manifest verification boundary before any hosted private
signing or publication step. The compiler must build only the public Unified Agent matrix
@@ -1777,7 +1777,7 @@ func TestReleaseCandidateRequiresPlatformNativeAgentSigning(t *testing.T) {
assertFileContainsAll(t, repoFile(".github", "workflows", "create-release.yml"),
`require_macos_signing: true`,
`require_windows_signing: ${{ needs.prepare.outputs.require_windows_signing == 'true' }}`,
`!contains(inputs.version, '-') && 'ubuntu-24.04'`,
`runs-on: ubuntu-24.04`,
`unsigned_windows_exception:`,
`unsigned_windows_reason:`,
`windows_signing_backend: signpath`,
@@ -1855,13 +1855,8 @@ func TestReleaseWorkflowsUseSecretSafeAttestedImageBuilds(t *testing.T) {
`uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2`,
}
containerJob := workflowJobBlock(t, string(qualifierWorkflowBytes), "qualify")
for _, needle := range []string{
`!contains(inputs.version, '-') && 'ubuntu-24.04'`,
"pulse-pve-build",
} {
if !strings.Contains(containerJob, needle) {
t.Fatalf("exact-candidate container qualification missing stable-hosted runner contract: %s", needle)
}
if !strings.Contains(containerJob, "runs-on: ubuntu-24.04") || strings.Contains(containerJob, "self-hosted") {
t.Fatal("container qualification must use a fresh hosted VM for every channel")
}
if !strings.Contains(string(candidateWorkflowBytes), "always() && inputs.qualify_containers && needs.build.result == 'success'") {
t.Fatal("standalone exact-candidate qualification must not inherit skipped native-signing dependencies")
@@ -3304,17 +3299,14 @@ func TestReleasePipelinePromotesOneImmutableCandidate(t *testing.T) {
candidateBuildJob := workflowJobBlock(t, candidateWorkflow, "build")
compiledPayloadVerificationStep := workflowStepBlock(t, candidateBuildJob, "Verify exact-SHA compiled payload")
for _, needle := range []string{
`!contains(inputs.version, '-') && 'ubuntu-24.04'`,
`'ubuntu-24.04'`,
`pulse-pve-compile`,
} {
if !strings.Contains(prepareJob, needle) {
t.Fatalf("release preparation missing stable-hosted runner selection: %s", needle)
}
if !strings.Contains(prepareJob, "runs-on: ubuntu-24.04") ||
strings.Contains(prepareJob, "self-hosted") ||
strings.Contains(prepareJob, "pulse-pve-compile") ||
strings.Contains(prepareJob, "contains(inputs.version") {
t.Fatal("release preparation must use a fresh hosted VM for every channel")
}
if strings.Contains(prepareJob, "sparse-checkout") {
t.Fatal("release preparation must leave a complete worktree for the following compile job")
t.Fatal("release preparation must use the complete admitted source")
}
for _, needle := range []string{
`runs-on: ubuntu-24.04`,
@@ -3383,11 +3375,8 @@ func TestReleasePipelinePromotesOneImmutableCandidate(t *testing.T) {
"frontend bundle": frontendBundleJob,
"backend tests": backendJob,
} {
if !strings.Contains(job, `!contains(inputs.version, '-') && 'ubuntu-24.04'`) {
t.Fatalf("%s must stay GitHub-hosted for every stable release", label)
}
if !strings.Contains(job, "pulse-pve-") {
t.Fatalf("%s must retain PVE acceleration for prereleases", label)
if !strings.Contains(job, "runs-on: ubuntu-24.04") || strings.Contains(job, "self-hosted") {
t.Fatalf("%s must use a fresh hosted VM for every channel", label)
}
if strings.Contains(job, "require_windows_signing") || strings.Contains(job, "unsigned_windows_exception") {
t.Fatalf("%s runner selection must not depend on the Windows-signing decision", label)