From f83541061ea6397c8c04aec17fbb1b20e0f16ee7 Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Sat, 29 Aug 2026 11:01:59 +0100 Subject: [PATCH] Qualify embedded agent executable mode --- .github/workflows/qualify-release-containers.yml | 10 ++++++++++ .../subsystems/deployment-installability.md | 12 +++++++----- .../installtests/build_release_assets_test.go | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/.github/workflows/qualify-release-containers.yml b/.github/workflows/qualify-release-containers.yml index 714285d146..7a5c706aea 100644 --- a/.github/workflows/qualify-release-containers.yml +++ b/.github/workflows/qualify-release-containers.yml @@ -84,12 +84,22 @@ jobs: expected_server="$(sha256sum "$RUNNER_TEMP/release-container-payload/payload/release/amd64/bin/pulse" | awk '{print $1}')" actual_server="$(docker run --rm --entrypoint /bin/sh "pulse-helm-smoke:${{ inputs.version }}" -c 'sha256sum /app/pulse' | awk '{print $1}')" expected_agent="$(sha256sum "$RUNNER_TEMP/release-container-payload/payload/release/amd64/bin/pulse-agent-linux-amd64" | awk '{print $1}')" + actual_embedded_agent="$(docker run --rm --entrypoint /bin/sh "pulse-helm-smoke:${{ inputs.version }}" -c 'sha256sum /usr/local/bin/pulse-agent' | awk '{print $1}')" actual_agent="$(docker run --rm --entrypoint /bin/sh "pulse-agent-candidate:${{ inputs.version }}" -c 'sha256sum /usr/local/bin/pulse-agent' | awk '{print $1}')" expected_control_plane="$(sha256sum "$RUNNER_TEMP/release-container-payload/payload/compiled/binaries/pulse-control-plane-linux-amd64" | awk '{print $1}')" actual_control_plane="$(docker run --rm --entrypoint /bin/sh "pulse-control-plane-candidate:${{ inputs.version }}" -c 'sha256sum /usr/local/bin/pulse-control-plane' | awk '{print $1}')" test "${actual_server}" = "${expected_server}" + test "${actual_embedded_agent}" = "${expected_agent}" test "${actual_agent}" = "${expected_agent}" test "${actual_control_plane}" = "${expected_control_plane}" + docker run --rm --entrypoint /bin/sh "pulse-helm-smoke:${{ inputs.version }}" -c ' + set -euo pipefail + test "$(readlink /usr/local/bin/pulse-agent)" = "/opt/pulse/bin/pulse-agent-linux-amd64" + test -x /usr/local/bin/pulse-agent + for sidecar in /opt/pulse/bin/*.sig /opt/pulse/bin/*.sshsig; do + test ! -x "$sidecar" + done + ' - name: Set up Helm uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0 diff --git a/docs/release-control/v6/internal/subsystems/deployment-installability.md b/docs/release-control/v6/internal/subsystems/deployment-installability.md index 3afb69d725..01e932d679 100644 --- a/docs/release-control/v6/internal/subsystems/deployment-installability.md +++ b/docs/release-control/v6/internal/subsystems/deployment-installability.md @@ -113,11 +113,13 @@ deployment-specific paths. Images assembled from immutable release payload contexts must restore executable mode on copied Unified Agent binaries before creating the architecture-resolved `/usr/local/bin/pulse-agent` link. Detached signature -sidecars remain non-executable. Release validation may delete invalid assets -and rewrite validation annotations only while a release is still a draft. A -post-publication edit is observation, not authority to mutate or destroy an -immutable release; failed revalidation records a failing status and requires an -explicit corrective release path. +sidecars remain non-executable. Exact-candidate container qualification must +prove both mode boundaries on the assembled server image before publication, +rather than relying on post-publication image validation. Release validation +may delete invalid assets and rewrite validation annotations only while a +release is still a draft. A post-publication edit is observation, not authority +to mutate or destroy an immutable release; failed revalidation records a +failing status and requires an explicit corrective release path. The accelerated exact-SHA release worker must preserve release-gate fidelity under its own resource envelope. Bounded frontend static checks and integration diff --git a/scripts/installtests/build_release_assets_test.go b/scripts/installtests/build_release_assets_test.go index 87cead7c7f..44489a7660 100644 --- a/scripts/installtests/build_release_assets_test.go +++ b/scripts/installtests/build_release_assets_test.go @@ -193,8 +193,13 @@ func TestReleaseContainerTargetsConsumeImmutableCandidate(t *testing.T) { if err != nil { t.Fatalf("read prepare-release-container-context.sh: %v", err) } + qualifierBytes, err := os.ReadFile(repoFile(".github", "workflows", "qualify-release-containers.yml")) + if err != nil { + t.Fatalf("read qualify-release-containers.yml: %v", err) + } dockerfile := string(dockerfileBytes) prepareScript := string(prepareBytes) + qualifier := string(qualifierBytes) for _, needle := range []string{ "FROM pulse-runtime-foundation AS prebuilt-runtime-base", @@ -224,6 +229,17 @@ func TestReleaseContainerTargetsConsumeImmutableCandidate(t *testing.T) { t.Fatalf("prepare-release-container-context.sh missing candidate guard: %s", needle) } } + for _, needle := range []string{ + `actual_embedded_agent="$(docker run --rm --entrypoint /bin/sh`, + `test "${actual_embedded_agent}" = "${expected_agent}"`, + `test "$(readlink /usr/local/bin/pulse-agent)" = "/opt/pulse/bin/pulse-agent-linux-amd64"`, + `test -x /usr/local/bin/pulse-agent`, + `test ! -x "$sidecar"`, + } { + if !strings.Contains(qualifier, needle) { + t.Fatalf("exact-candidate container qualification missing embedded agent mode guard: %s", needle) + } + } } func TestReleaseContainerContextTreatsServerSignaturesAsArchitectureBound(t *testing.T) {