Integrate secure-runtime RC qualification control

Change-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot]
2026-09-28 21:43:04 +01:00
4 changed files with 39 additions and 8 deletions
+1 -1
View File
@@ -2163,7 +2163,7 @@ jobs:
dispatch="$(
jq -n \
--arg tag "${TAG}" \
'{ref: $tag, return_run_details: true, inputs: {tag: $tag}}' | \
'{ref: "main", return_run_details: true, inputs: {tag: $tag}}' | \
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
@@ -59,6 +59,20 @@ jobs:
fetch-depth: 0
ref: ${{ steps.release.outputs.tag }}
- name: Bind canonical Pulse origin
run: |
set -euo pipefail
test "${GITHUB_REPOSITORY}" = "rcourtman/Pulse"
# checkout v7 records the canonical HTTPS URL without .git. The
# released attestation expects the equivalent .git spelling and
# independently checks the remote tag and branch identities.
origin_url="$(git remote get-url origin)"
case "${origin_url}" in
https://github.com/rcourtman/Pulse|https://github.com/rcourtman/Pulse.git) ;;
*) echo "::error::Release checkout origin is not canonical Pulse."; exit 1 ;;
esac
git remote set-url origin https://github.com/rcourtman/Pulse.git
- name: Verify detached release source
id: source
env:
@@ -77,8 +91,11 @@ jobs:
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}"
# Run reviewed qualification control from protected main, while the
# checkout and the packet remain bound to the immutable release tag.
test "${GITHUB_REF}" = "refs/heads/main"
test "${GITHUB_WORKFLOW_REF}" = "${GITHUB_REPOSITORY}/.github/workflows/qualify-secure-runtime-release.yml@refs/heads/main"
test "${GITHUB_WORKFLOW_SHA}" = "${GITHUB_SHA}"
test "$(git branch --show-current)" = ""
test -z "$(git status --short --untracked-files=all)"
git merge-base --is-ancestor "${commit}" "origin/${required_branch}"
@@ -1219,7 +1219,16 @@ artifact-selection behaviour.
Private signing material and publication credentials must never enter the
compilation job.
Post-publication secure-runtime qualification must authenticate before it
executes. `.github/workflows/qualify-secure-runtime-release.yml` may download
executes. The publication workflow dispatches the reviewed qualification
control from protected `main`, with the immutable RC tag as its sole source
input. The qualification workflow must prove its own repository, workflow
ref and workflow SHA are that `main` control, then check out the detached
release tag and verify its commit is on the governed release line. Its
checkout may report either canonical HTTPS origin spelling, with or without
`.git`; it must reject every other origin before normalising to the exact
`.git` spelling required by the packet attester. Normalisation must not
relax the separate remote tag, branch, release and artifact identity checks.
`.github/workflows/qualify-secure-runtime-release.yml` may download
caller-owned release assets only into a non-executable holding directory.
`scripts/release_control/secure_runtime_attestation_v7.py` must copy the six
binaries, four collector signatures, checksum manifest, assembly and
@@ -2792,7 +2792,7 @@ func TestSecureRuntimeQualificationPacketIsHostedAndReleaseBound(t *testing.T) {
"release/pulse-secure-runtime-collector-v1-linux-amd64",
"release/pulse-secure-runtime-collector-v3-linux-amd64",
"qualify-secure-runtime-release.yml/dispatches",
`{ref: $tag, return_run_details: true, inputs: {tag: $tag}}`,
`{ref: "main", return_run_details: true, inputs: {tag: $tag}}`,
"Secure-runtime qualification dispatch did not return an exact workflow run.",
"Immutable RC publication did not retain an exact secure-runtime qualification run identity.",
} {
@@ -2805,9 +2805,11 @@ func TestSecureRuntimeQualificationPacketIsHostedAndReleaseBound(t *testing.T) {
if strings.Contains(qualificationWorkflow, "release:\n types: [published]") {
t.Fatal("secure-runtime qualification must be explicitly dispatched after immutable publication, not rely on suppressed release events")
}
originIndex := strings.Index(qualificationWorkflow, "Bind canonical Pulse origin")
sourceIndex := strings.Index(qualificationWorkflow, "Verify detached release source")
preauthenticationIndex := strings.Index(qualificationWorkflow, "Pre-authenticate exact qualification packet")
privilegedExecutionIndex := strings.Index(qualificationWorkflow, "docker run")
if preauthenticationIndex < 0 || privilegedExecutionIndex < 0 || preauthenticationIndex > privilegedExecutionIndex {
if originIndex < 0 || sourceIndex < originIndex || preauthenticationIndex < sourceIndex || privilegedExecutionIndex < preauthenticationIndex {
t.Fatal("secure-runtime release packet must be authenticated before any privileged Docker execution")
}
if strings.Contains(qualificationWorkflow, `$RUNNER_TEMP/secure-runtime-downloads:/release:ro`) {
@@ -2815,8 +2817,11 @@ func TestSecureRuntimeQualificationPacketIsHostedAndReleaseBound(t *testing.T) {
}
for _, required := range []string{
".immutable == true",
`test "${GITHUB_REF}" = "refs/tags/${TAG}"`,
`test "${GITHUB_SHA}" = "${commit}"`,
`test "${GITHUB_REF}" = "refs/heads/main"`,
`test "${GITHUB_WORKFLOW_SHA}" = "${GITHUB_SHA}"`,
`test "${GITHUB_REPOSITORY}" = "rcourtman/Pulse"`,
`https://github.com/rcourtman/Pulse|https://github.com/rcourtman/Pulse.git)`,
`git remote set-url origin https://github.com/rcourtman/Pulse.git`,
"ca-certificates curl dbus systemd systemd-sysv util-linux",
`docker:27.5.1-dind@sha256:f649ef046008ca7f926a2571c32b0ac22e5c59eb61b959617f9acc2a4c638cf5`,
`for command in curl docker dockerd id nsenter runuser systemctl`,