Qualify release candidates against the branch that owns their version

The secure-runtime qualification required the candidate commit to be an
ancestor of origin/main. Under the release train a patch candidate is cut
from release/vX.Y and is not on main at all, so v6.4.3-rc.1's
qualification failed at "Verify detached release source" before running
any check, and the steward correctly refused to treat the candidate as
stable-capable. Resolve the branch the control plane maps the version to,
fetch that, check ancestry against it, and hand the same ref to the
attestation so the receipt records the line it was verified against.

Refs #1753

Contract-Neutral: release qualification checks ancestry against the mapped release branch; no product or contract change
This commit is contained in:
Richard Courtman 2026-09-02 17:52:33 +01:00
parent ac3dc2e953
commit 79d87a4a2c

View file

@ -65,14 +65,25 @@ jobs:
TAG: ${{ steps.release.outputs.tag }}
run: |
set -euo pipefail
git fetch --no-tags origin refs/heads/main:refs/remotes/origin/main
# The release train cuts patch candidates from release/vX.Y, so the
# candidate is reachable from the branch the control plane maps its
# version to, not necessarily from main (v6.4.3-rc.1, 2026-09-02).
required_branch="$(python3 scripts/release_control/control_plane.py \
--branch-for-version "${TAG#v}")"
[[ "${required_branch}" =~ ^(main|release/v[0-9]+\.[0-9]+)$ ]] || {
echo "::error::Control plane mapped ${TAG} to an unexpected branch: ${required_branch}"
exit 1
}
git fetch --no-tags origin \
"refs/heads/${required_branch}:refs/remotes/origin/${required_branch}"
commit="$(git rev-parse "${TAG}^{commit}")"
test "${GITHUB_REF}" = "refs/tags/${TAG}"
test "${GITHUB_SHA}" = "${commit}"
test "$(git branch --show-current)" = ""
test -z "$(git status --short --untracked-files=all)"
git merge-base --is-ancestor "${commit}" origin/main
git merge-base --is-ancestor "${commit}" "origin/${required_branch}"
python3 scripts/write_github_output.py commit "${commit}"
python3 scripts/write_github_output.py line_ref "origin/${required_branch}"
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@ -117,6 +128,7 @@ jobs:
GH_TOKEN: ${{ github.token }}
PULSE_UPDATE_SIGNING_PUBLIC_KEY: ${{ vars.PULSE_UPDATE_SIGNING_PUBLIC_KEY }}
QUALIFIED_COMMIT: ${{ steps.source.outputs.commit }}
LINE_REF: ${{ steps.source.outputs.line_ref }}
RELEASE_ID: ${{ steps.release.outputs.release_id }}
TAG: ${{ steps.release.outputs.tag }}
run: |
@ -132,7 +144,7 @@ jobs:
--verify-release-packet-only \
--checkout "${GITHUB_WORKSPACE}" \
--commit "${QUALIFIED_COMMIT}" \
--main-ref origin/main \
--main-ref "${LINE_REF}" \
--collector-v1 "${download_dir}/pulse-secure-runtime-collector-v1-linux-amd64" \
--collector-v2 "${download_dir}/pulse-secure-runtime-collector-v2-linux-amd64" \
--collector-v3 "${download_dir}/pulse-secure-runtime-collector-v3-linux-amd64" \
@ -299,6 +311,7 @@ jobs:
GH_TOKEN: ${{ github.token }}
PULSE_UPDATE_SIGNING_PUBLIC_KEY: ${{ vars.PULSE_UPDATE_SIGNING_PUBLIC_KEY }}
QUALIFIED_COMMIT: ${{ steps.source.outputs.commit }}
LINE_REF: ${{ steps.source.outputs.line_ref }}
RELEASE_ID: ${{ steps.release.outputs.release_id }}
TAG: ${{ steps.release.outputs.tag }}
WORKFLOW_OUTPUT_1: ${{ steps.lab.outputs.elapsed_seconds }}
@ -314,7 +327,7 @@ jobs:
python3 scripts/release_control/secure_runtime_attestation_v7.py \
--checkout "${GITHUB_WORKSPACE}" \
--commit "${QUALIFIED_COMMIT}" \
--main-ref origin/main \
--main-ref "${LINE_REF}" \
--receipt "${evidence_dir}/receipt.json" \
--receipt-record-path "docs/release-control/v6/internal/records/secure-agent-runtime-systemd-receipt-v7-${TAG}.json" \
--transcript "${evidence_dir}/transcript.jsonl" \