From 9ac54e826daa76c610120c2c88ea41304eb51c8b Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 26 Aug 2026 09:48:29 +0200 Subject: [PATCH 01/11] ci(e2e): use prebuilt gateway for external drivers Signed-off-by: Evan Lezar --- .github/workflows/branch-e2e.yml | 14 +++++++++- .github/workflows/docker-build.yml | 9 +++++++ .github/workflows/e2e-test.yml | 35 ++++++++++++++++++++----- .github/workflows/rust-native-build.yml | 8 ++++++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/.github/workflows/branch-e2e.yml b/.github/workflows/branch-e2e.yml index 2b4d9d5d46..74fef8e5e6 100644 --- a/.github/workflows/branch-e2e.yml +++ b/.github/workflows/branch-e2e.yml @@ -87,6 +87,17 @@ jobs: component: gateway image-tag: ${{ github.sha }} + build-gateway-external: + needs: [pr_metadata] + if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_core_e2e == 'true' + permissions: + contents: read + packages: read + uses: ./.github/workflows/docker-build.yml + with: + component: gateway-external + image-tag: ${{ github.sha }} + build-supervisor: needs: [pr_metadata] if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_any_e2e == 'true' @@ -124,7 +135,7 @@ jobs: [{"arch":"amd64","runner":"linux-amd64-cpu8","target":"x86_64-unknown-linux-gnu","zig_target":"x86_64-unknown-linux-gnu.2.28","platform":"linux-x86_64","guest_arch":"x86_64"}] e2e: - needs: [pr_metadata, build-gateway, build-supervisor, build-cli, build-driver-vm-linux] + needs: [pr_metadata, build-gateway, build-gateway-external, build-supervisor, build-cli, build-driver-vm-linux] if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_core_e2e == 'true' permissions: actions: read @@ -136,6 +147,7 @@ jobs: runner: linux-arm64-cpu8 cli-artifact-prefix: rust-binary-cli gateway-artifact-prefix: rust-binary-gateway + external-gateway-artifact-prefix: rust-binary-gateway-external vm-driver-artifact-name: driver-vm-linux-amd64 gpu-e2e: diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 2e7abe2008..ffc5045833 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -77,6 +77,7 @@ jobs: artifact_prefix: ${{ steps.resolve.outputs.artifact_prefix }} image_tag_base: ${{ steps.resolve.outputs.image_tag_base }} features: ${{ steps.resolve.outputs.features }} + no_default_features: ${{ steps.resolve.outputs.no_default_features }} has_image: ${{ steps.resolve.outputs.has_image }} steps: - name: Resolve component and platform matrix @@ -92,6 +93,13 @@ jobs: features="bundled-z3" has_image=true ;; + gateway-external) + binary_component=gateway + binary_name=openshell-gateway + features="telemetry" + no_default_features=true + has_image=false + ;; supervisor) binary_component=sandbox binary_name=openshell-sandbox @@ -162,6 +170,7 @@ jobs: echo "artifact_prefix=rust-binary-${component}" echo "image_tag_base=$image_tag_base" echo "features=$features" + echo "no_default_features=${no_default_features:-false}" echo "has_image=$has_image" } >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index f176953048..8579bcd438 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -27,6 +27,11 @@ on: required: false type: string default: "" + external-gateway-artifact-prefix: + description: "Prebuilt gateway artifact prefix for external-driver suites" + required: false + type: string + default: "" vm-driver-artifact-name: description: "Optional prebuilt VM driver artifact name" required: false @@ -60,7 +65,7 @@ jobs: cmd: "mise run --no-deps --skip-deps e2e:rust" apt_packages: "openssh-client" - suite: rust-docker-external-driver - cmd: "env -u OPENSHELL_GATEWAY_BIN mise run --no-deps --skip-deps e2e:docker:external-driver" + cmd: "mise run --no-deps --skip-deps e2e:docker:external-driver" apt_packages: "openssh-client" - suite: mcp cmd: "mise run --no-deps --skip-deps e2e:mcp" @@ -95,11 +100,17 @@ jobs: artifact-prefix: ${{ inputs.cli-artifact-prefix }} - name: Use prebuilt OpenShell gateway - if: inputs.gateway-artifact-prefix != '' + if: inputs.gateway-artifact-prefix != '' && matrix.suite != 'rust-docker-external-driver' uses: ./.github/actions/setup-e2e-gateway with: artifact-prefix: ${{ inputs.gateway-artifact-prefix }} + - name: Use prebuilt external-driver gateway + if: inputs.external-gateway-artifact-prefix != '' && matrix.suite == 'rust-docker-external-driver' + uses: ./.github/actions/setup-e2e-gateway + with: + artifact-prefix: ${{ inputs.external-gateway-artifact-prefix }} + - name: Check out MCP conformance tests if: matrix.suite == 'mcp' uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -156,7 +167,7 @@ jobs: podman_major: "5" podman_package_version: "5.7.0+ds2-3build1" conmon_package_version: "2.1.13+ds1-2" - cmd: "env -u OPENSHELL_GATEWAY_BIN mise run --no-deps --skip-deps e2e:podman:external-driver" + cmd: "mise run --no-deps --skip-deps e2e:podman:external-driver" - suite: provider-refresh-keycloak runner: ubuntu-26.04 podman_major: "5" @@ -185,11 +196,17 @@ jobs: artifact-prefix: ${{ inputs.cli-artifact-prefix }} - name: Use prebuilt OpenShell gateway - if: inputs.gateway-artifact-prefix != '' + if: inputs.gateway-artifact-prefix != '' && matrix.suite != 'external-driver' uses: ./.github/actions/setup-e2e-gateway with: artifact-prefix: ${{ inputs.gateway-artifact-prefix }} + - name: Use prebuilt external-driver gateway + if: inputs.external-gateway-artifact-prefix != '' && matrix.suite == 'external-driver' + uses: ./.github/actions/setup-e2e-gateway + with: + artifact-prefix: ${{ inputs.external-gateway-artifact-prefix }} + - name: Install mise run: | curl https://mise.run | MISE_VERSION=v2026.4.25 sh @@ -325,7 +342,7 @@ jobs: - suite: managed cmd: "mise run --no-deps --skip-deps e2e:vm" - suite: external-driver - cmd: "env -u OPENSHELL_GATEWAY_BIN mise run --no-deps --skip-deps e2e:vm:external-driver" + cmd: "mise run --no-deps --skip-deps e2e:vm:external-driver" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -342,11 +359,17 @@ jobs: artifact-prefix: ${{ inputs.cli-artifact-prefix }} - name: Use prebuilt OpenShell gateway - if: inputs.gateway-artifact-prefix != '' + if: inputs.gateway-artifact-prefix != '' && matrix.suite != 'external-driver' uses: ./.github/actions/setup-e2e-gateway with: artifact-prefix: ${{ inputs.gateway-artifact-prefix }} + - name: Use prebuilt external-driver gateway + if: inputs.external-gateway-artifact-prefix != '' && matrix.suite == 'external-driver' + uses: ./.github/actions/setup-e2e-gateway + with: + artifact-prefix: ${{ inputs.external-gateway-artifact-prefix }} + - name: Use prebuilt OpenShell VM driver if: inputs.vm-driver-artifact-name != '' uses: ./.github/actions/setup-e2e-vm-driver diff --git a/.github/workflows/rust-native-build.yml b/.github/workflows/rust-native-build.yml index 3496f4779f..2aa9f9521e 100644 --- a/.github/workflows/rust-native-build.yml +++ b/.github/workflows/rust-native-build.yml @@ -40,6 +40,11 @@ on: required: false type: string default: "" + no-default-features: + description: "Build without Cargo default features" + required: false + type: boolean + default: false auditable: description: "Embed cargo-auditable dependency metadata in the binary" required: false @@ -300,6 +305,9 @@ jobs: if [[ -n "$FEATURES" ]]; then args+=(--features "$FEATURES") fi + if [[ "${{ inputs['no-default-features'] }}" == "true" ]]; then + args+=(--no-default-features) + fi if [[ -n "${{ steps.version.outputs.cargo_version }}" ]]; then export GIT_DIR=/nonexistent fi From 25cb930c171c7a72ef5f436ca83f1fefd8cc64c5 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 26 Aug 2026 10:50:41 +0200 Subject: [PATCH 02/11] ci(e2e): reuse release test binaries Signed-off-by: Evan Lezar --- .github/workflows/release-dev.yml | 22 +++++++++++++++++++++- .github/workflows/release-tag.yml | 26 +++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-dev.yml b/.github/workflows/release-dev.yml index 500fcb4be6..7e49244a1f 100644 --- a/.github/workflows/release-dev.yml +++ b/.github/workflows/release-dev.yml @@ -69,8 +69,25 @@ jobs: cargo-version: ${{ needs.compute-versions.outputs.cargo_version }} auditable: true + build-cli: + needs: [compute-versions] + uses: ./.github/workflows/docker-build.yml + with: + component: cli + cargo-version: ${{ needs.compute-versions.outputs.cargo_version }} + auditable: true + platform: linux/amd64,linux/arm64 + + build-gateway-external: + needs: [compute-versions] + uses: ./.github/workflows/docker-build.yml + with: + component: gateway-external + cargo-version: ${{ needs.compute-versions.outputs.cargo_version }} + auditable: true + e2e: - needs: [build-gateway, build-supervisor] + needs: [build-gateway, build-supervisor, build-cli, build-gateway-external] permissions: actions: read contents: read @@ -79,6 +96,9 @@ jobs: with: image-tag: ${{ github.sha }} runner: linux-arm64-cpu8 + cli-artifact-prefix: rust-binary-cli + gateway-artifact-prefix: rust-binary-gateway + external-gateway-artifact-prefix: rust-binary-gateway-external tag-ghcr-dev: name: Tag GHCR Images as Dev diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 74be300b0c..6ba5ec66a4 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -93,8 +93,29 @@ jobs: checkout-ref: ${{ inputs.tag || github.ref }} auditable: true + build-cli: + needs: [compute-versions] + uses: ./.github/workflows/docker-build.yml + with: + component: cli + cargo-version: ${{ needs.compute-versions.outputs.cargo_version }} + image-tag: ${{ needs.compute-versions.outputs.source_sha }} + checkout-ref: ${{ inputs.tag || github.ref }} + auditable: true + platform: linux/amd64,linux/arm64 + + build-gateway-external: + needs: [compute-versions] + uses: ./.github/workflows/docker-build.yml + with: + component: gateway-external + cargo-version: ${{ needs.compute-versions.outputs.cargo_version }} + image-tag: ${{ needs.compute-versions.outputs.source_sha }} + checkout-ref: ${{ inputs.tag || github.ref }} + auditable: true + e2e: - needs: [compute-versions, build-gateway, build-supervisor] + needs: [compute-versions, build-gateway, build-supervisor, build-cli, build-gateway-external] permissions: actions: read contents: read @@ -104,6 +125,9 @@ jobs: image-tag: ${{ needs.compute-versions.outputs.source_sha }} checkout-ref: ${{ inputs.tag || github.ref }} runner: linux-arm64-cpu8 + cli-artifact-prefix: rust-binary-cli + gateway-artifact-prefix: rust-binary-gateway + external-gateway-artifact-prefix: rust-binary-gateway-external tag-ghcr-release: name: Tag GHCR Images for Release From 046109ef18edb49fb4ae029d7fc479088cb9ed70 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 26 Aug 2026 11:49:16 +0200 Subject: [PATCH 03/11] ci(e2e): reuse prebuilt CLI in Podman tests Signed-off-by: Evan Lezar --- e2e/rust/e2e-podman.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/e2e/rust/e2e-podman.sh b/e2e/rust/e2e-podman.sh index f5f1effd18..fdf1e63754 100755 --- a/e2e/rust/e2e-podman.sh +++ b/e2e/rust/e2e-podman.sh @@ -22,7 +22,11 @@ if [ -z "${E2E_TEST}" ] || [ "${E2E_TEST}" = "provider_token_exchange" ]; then export OPENSHELL_E2E_SPIFFE_FIXTURE="${OPENSHELL_E2E_SPIFFE_FIXTURE:-1}" fi -cargo build -p openshell-cli +if [ -z "${OPENSHELL_BIN:-}" ]; then + cargo build -p openshell-cli +else + echo "Using prebuilt openshell CLI at ${OPENSHELL_BIN}" +fi TEST_ARGS=( cargo test --manifest-path "${ROOT}/e2e/rust/Cargo.toml" From 11816b11bf24bd0f46ef6756519c3785b5f57ff6 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 26 Aug 2026 13:47:41 +0200 Subject: [PATCH 04/11] fix(ci): align external gateway workflow permissions Signed-off-by: Evan Lezar --- .github/workflows/branch-e2e.yml | 2 +- .github/workflows/docker-build.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/branch-e2e.yml b/.github/workflows/branch-e2e.yml index 74fef8e5e6..87fdf019e3 100644 --- a/.github/workflows/branch-e2e.yml +++ b/.github/workflows/branch-e2e.yml @@ -92,7 +92,7 @@ jobs: if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_core_e2e == 'true' permissions: contents: read - packages: read + packages: write uses: ./.github/workflows/docker-build.yml with: component: gateway-external diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index ffc5045833..56ec6892fb 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -191,6 +191,7 @@ jobs: image-tag: ${{ needs.resolve.outputs.image_tag_base }} checkout-ref: ${{ inputs['checkout-ref'] }} features: ${{ needs.resolve.outputs.features }} + no-default-features: ${{ needs.resolve.outputs.no_default_features == 'true' }} auditable: ${{ inputs.auditable }} artifact-name: ${{ needs.resolve.outputs.artifact_prefix }}-linux-${{ matrix.arch }} secrets: inherit From 568b0b9f35bee0097134af807a3775a03f6968c2 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 26 Aug 2026 14:05:46 +0200 Subject: [PATCH 05/11] ci(artifacts): publish SHA-addressed E2E binaries Signed-off-by: Evan Lezar --- .github/workflows/branch-e2e.yml | 15 ++++ .github/workflows/publish-sha-artifacts.yml | 96 +++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 .github/workflows/publish-sha-artifacts.yml diff --git a/.github/workflows/branch-e2e.yml b/.github/workflows/branch-e2e.yml index 87fdf019e3..9c4b1a878a 100644 --- a/.github/workflows/branch-e2e.yml +++ b/.github/workflows/branch-e2e.yml @@ -134,6 +134,21 @@ jobs: driver-targets: >- [{"arch":"amd64","runner":"linux-amd64-cpu8","target":"x86_64-unknown-linux-gnu","zig_target":"x86_64-unknown-linux-gnu.2.28","platform":"linux-x86_64","guest_arch":"x86_64"}] + publish-sha-artifacts: + needs: [pr_metadata, build-gateway, build-gateway-external, build-cli] + if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_core_e2e == 'true' + permissions: + actions: read + attestations: write + artifact-metadata: write + contents: read + id-token: write + packages: write + uses: ./.github/workflows/publish-sha-artifacts.yml + with: + source-sha: ${{ github.sha }} + artifact-set: branch-e2e + e2e: needs: [pr_metadata, build-gateway, build-gateway-external, build-supervisor, build-cli, build-driver-vm-linux] if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_core_e2e == 'true' diff --git a/.github/workflows/publish-sha-artifacts.yml b/.github/workflows/publish-sha-artifacts.yml new file mode 100644 index 0000000000..b724383ead --- /dev/null +++ b/.github/workflows/publish-sha-artifacts.yml @@ -0,0 +1,96 @@ +name: Publish SHA Artifacts + +on: + workflow_call: + inputs: + source-sha: + description: "Full source commit SHA represented by the artifacts" + required: true + type: string + artifact-set: + description: "Named build-profile variant for this artifact set" + required: true + type: string + artifact-pattern: + description: "GitHub Actions artifact pattern to publish" + required: false + type: string + default: "rust-binary-*" + outputs: + manifest-ref: + description: "Digest-pinned OCI manifest reference" + value: ${{ jobs.publish.outputs.manifest_ref }} + +permissions: + actions: read + attestations: write + artifact-metadata: write + contents: read + id-token: write + packages: write + +jobs: + publish: + name: Publish SHA artifact manifest + runs-on: linux-amd64-cpu8 + timeout-minutes: 15 + outputs: + manifest_ref: ${{ steps.publish.outputs.manifest_ref }} + steps: + - name: Download build artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + pattern: ${{ inputs.artifact-pattern }} + path: artifacts + + - name: Install ORAS + uses: oras-project/setup-oras@22ce207df3b08e061f537244349aac6ae1d214f6 # v2.0.1 + + - name: Assemble deterministic artifact bundle + env: + SOURCE_SHA: ${{ inputs.source-sha }} + ARTIFACT_SET: ${{ inputs.artifact-set }} + run: | + set -euo pipefail + test "${#SOURCE_SHA}" -eq 40 + mkdir -p bundle + cp -a artifacts/. bundle/ + find bundle -type f -print0 | sort -z | xargs -0 sha256sum > artifact-checksums.txt + jq -n \ + --arg schema_version "1" \ + --arg source_sha "$SOURCE_SHA" \ + --arg artifact_set "$ARTIFACT_SET" \ + --argjson artifacts "$(jq -R -s -c 'split("\n") | map(select(length > 0) | capture("^(?[0-9a-f]{64}) (?.+)$"))' artifact-checksums.txt)" \ + '{schema_version: ($schema_version | tonumber), source: {repository: env.GITHUB_REPOSITORY, sha: $source_sha}, artifact_set: $artifact_set, artifacts: $artifacts}' \ + > sha-artifacts.json + tar --sort=name --mtime='@0' --owner=0 --group=0 --numeric-owner -C bundle -cf - . | gzip -n > sha-artifacts.tar.gz + + - name: Publish immutable OCI artifact + id: publish + env: + SOURCE_SHA: ${{ inputs.source-sha }} + ARTIFACT_SET: ${{ inputs.artifact-set }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + repository="ghcr.io/${GITHUB_REPOSITORY,,}/ci-artifacts" + tag="sha-${SOURCE_SHA}-${ARTIFACT_SET}" + ref="${repository}:${tag}" + echo "$GH_TOKEN" | oras login ghcr.io -u "$GITHUB_ACTOR" --password-stdin + if oras manifest fetch --descriptor "$ref" >/dev/null 2>&1; then + echo "refusing to overwrite existing SHA artifact manifest: $ref" >&2 + exit 1 + fi + digest="$(oras push --format json \ + --artifact-type application/vnd.nvidia.openshell.sha-artifacts.v1 \ + --annotation "org.opencontainers.image.revision=${SOURCE_SHA}" \ + --annotation "io.openshell.artifact-set=${ARTIFACT_SET}" \ + "$ref" \ + sha-artifacts.json:application/vnd.nvidia.openshell.sha-artifacts.manifest.v1+json \ + sha-artifacts.tar.gz:application/vnd.nvidia.openshell.sha-artifacts.bundle.v1+gzip | jq -r '.digest')" + echo "manifest_ref=${repository}@${digest}" >> "$GITHUB_OUTPUT" + + - name: Attest SHA artifact manifest + uses: actions/attest@508db95dd578ae2727ebd6217d5ba78e4fbda05d # v4.2.1 + with: + subject-path: sha-artifacts.json From 9951f9a3def93e61e31adc4ef4339ae3dcf5e507 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 26 Aug 2026 14:09:50 +0200 Subject: [PATCH 06/11] ci(artifacts): use public runner for publishing Signed-off-by: Evan Lezar --- .github/workflows/publish-sha-artifacts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-sha-artifacts.yml b/.github/workflows/publish-sha-artifacts.yml index b724383ead..f05a11a0d4 100644 --- a/.github/workflows/publish-sha-artifacts.yml +++ b/.github/workflows/publish-sha-artifacts.yml @@ -32,7 +32,7 @@ permissions: jobs: publish: name: Publish SHA artifact manifest - runs-on: linux-amd64-cpu8 + runs-on: ubuntu-latest timeout-minutes: 15 outputs: manifest_ref: ${{ steps.publish.outputs.manifest_ref }} From 888c1b4983d5fd8d1b388ac25bf0763dd0a0a121 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 26 Aug 2026 14:15:05 +0200 Subject: [PATCH 07/11] ci(artifacts): verify published SHA bundles Signed-off-by: Evan Lezar --- .../actions/resolve-sha-artifacts/action.yml | 73 +++++++++++++++++++ .github/workflows/branch-e2e.yml | 25 +++++++ 2 files changed, 98 insertions(+) create mode 100644 .github/actions/resolve-sha-artifacts/action.yml diff --git a/.github/actions/resolve-sha-artifacts/action.yml b/.github/actions/resolve-sha-artifacts/action.yml new file mode 100644 index 0000000000..04bdbd6aa0 --- /dev/null +++ b/.github/actions/resolve-sha-artifacts/action.yml @@ -0,0 +1,73 @@ +name: Resolve SHA Artifacts +description: Download and verify a digest-pinned OpenShell SHA artifact bundle from GHCR. + +inputs: + manifest-ref: + description: "Digest-pinned OCI artifact manifest reference" + required: true + source-sha: + description: "Expected full source commit SHA" + required: true + token: + description: "Token with packages:read permission" + required: true + path: + description: "Directory into which the verified bundle is extracted" + required: false + default: .sha-artifacts + +outputs: + path: + description: "Directory containing the verified artifact files" + value: ${{ steps.resolve.outputs.path }} + +runs: + using: composite + steps: + - name: Install ORAS + uses: oras-project/setup-oras@22ce207df3b08e061f537244349aac6ae1d214f6 # v2.0.1 + + - name: Download and verify SHA artifacts + id: resolve + shell: bash + env: + MANIFEST_REF: ${{ inputs.manifest-ref }} + EXPECTED_SOURCE_SHA: ${{ inputs.source-sha }} + GH_TOKEN: ${{ inputs.token }} + OUTPUT_PATH: ${{ inputs.path }} + run: | + set -euo pipefail + test "${#EXPECTED_SOURCE_SHA}" -eq 40 + case "$MANIFEST_REF" in + ghcr.io/*@sha256:*) ;; + *) + echo "manifest-ref must be a digest-pinned GHCR reference" >&2 + exit 1 + ;; + esac + if [ -e "$OUTPUT_PATH" ]; then + echo "artifact output path already exists: $OUTPUT_PATH" >&2 + exit 1 + fi + mkdir -p "$OUTPUT_PATH" + echo "$GH_TOKEN" | oras login ghcr.io -u "$GITHUB_ACTOR" --password-stdin + oras pull "$MANIFEST_REF" -o "$OUTPUT_PATH" + manifest="$OUTPUT_PATH/sha-artifacts.json" + bundle="$OUTPUT_PATH/sha-artifacts.tar.gz" + test -f "$manifest" + test -f "$bundle" + actual_source_sha="$(jq -r '.source.sha' "$manifest")" + if [ "$actual_source_sha" != "$EXPECTED_SOURCE_SHA" ]; then + echo "artifact manifest source SHA does not match the expected commit" >&2 + exit 1 + fi + jq -e '.schema_version == 1 and (.artifacts | type == "array" and length > 0)' "$manifest" >/dev/null + mkdir "$OUTPUT_PATH/bundle" + tar -xzf "$bundle" --no-same-owner -C "$OUTPUT_PATH/bundle" + jq -e 'all(.artifacts[]; (.sha256 | test("^[0-9a-f]{64}$")) and (.path | test("^(?!/)(?!.*(^|/)\\.\\.(/|$)).+$")))' "$manifest" >/dev/null + jq -r '.artifacts[] | "\(.sha256) \(.path)"' "$manifest" > "$OUTPUT_PATH/checksums.txt" + ( + cd "$OUTPUT_PATH/bundle" + sha256sum -c ../checksums.txt + ) + echo "path=$OUTPUT_PATH/bundle" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/branch-e2e.yml b/.github/workflows/branch-e2e.yml index 9c4b1a878a..7789435f11 100644 --- a/.github/workflows/branch-e2e.yml +++ b/.github/workflows/branch-e2e.yml @@ -149,6 +149,31 @@ jobs: source-sha: ${{ github.sha }} artifact-set: branch-e2e + verify-sha-artifacts: + needs: [pr_metadata, publish-sha-artifacts] + if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_core_e2e == 'true' + runs-on: ubuntu-latest + permissions: + contents: read + packages: read + steps: + - name: Resolve published SHA artifacts + id: artifacts + uses: ./.github/actions/resolve-sha-artifacts + with: + manifest-ref: ${{ needs.publish-sha-artifacts.outputs.manifest-ref }} + source-sha: ${{ github.sha }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Verify amd64 binaries execute + env: + ARTIFACTS_DIR: ${{ steps.artifacts.outputs.path }} + run: | + set -euo pipefail + "$ARTIFACTS_DIR/rust-binary-cli-linux-amd64/openshell" --version + "$ARTIFACTS_DIR/rust-binary-gateway-linux-amd64/openshell-gateway" --version + "$ARTIFACTS_DIR/rust-binary-gateway-external-linux-amd64/openshell-gateway" --version + e2e: needs: [pr_metadata, build-gateway, build-gateway-external, build-supervisor, build-cli, build-driver-vm-linux] if: needs.pr_metadata.outputs.should_run == 'true' && needs.pr_metadata.outputs.run_core_e2e == 'true' From 3b9c2c42564ed33022c40cb065a73b69da6ba7a0 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 26 Aug 2026 14:17:54 +0200 Subject: [PATCH 08/11] fix(ci): expose SHA artifact manifest output Signed-off-by: Evan Lezar --- .github/workflows/branch-e2e.yml | 4 +++- .github/workflows/publish-sha-artifacts.yml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/branch-e2e.yml b/.github/workflows/branch-e2e.yml index 7789435f11..c40557b41d 100644 --- a/.github/workflows/branch-e2e.yml +++ b/.github/workflows/branch-e2e.yml @@ -157,11 +157,13 @@ jobs: contents: read packages: read steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Resolve published SHA artifacts id: artifacts uses: ./.github/actions/resolve-sha-artifacts with: - manifest-ref: ${{ needs.publish-sha-artifacts.outputs.manifest-ref }} + manifest-ref: ${{ needs.publish-sha-artifacts.outputs.manifest_ref }} source-sha: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish-sha-artifacts.yml b/.github/workflows/publish-sha-artifacts.yml index f05a11a0d4..8618b5a075 100644 --- a/.github/workflows/publish-sha-artifacts.yml +++ b/.github/workflows/publish-sha-artifacts.yml @@ -17,7 +17,7 @@ on: type: string default: "rust-binary-*" outputs: - manifest-ref: + manifest_ref: description: "Digest-pinned OCI manifest reference" value: ${{ jobs.publish.outputs.manifest_ref }} From e255b167c2ec5a9a0818720459fe86171877fe86 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 26 Aug 2026 14:20:56 +0200 Subject: [PATCH 09/11] fix(ci): remove invalid artifact permission Signed-off-by: Evan Lezar --- .github/workflows/branch-e2e.yml | 3 +-- .github/workflows/publish-sha-artifacts.yml | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/branch-e2e.yml b/.github/workflows/branch-e2e.yml index c40557b41d..ae8e8fa83c 100644 --- a/.github/workflows/branch-e2e.yml +++ b/.github/workflows/branch-e2e.yml @@ -140,7 +140,6 @@ jobs: permissions: actions: read attestations: write - artifact-metadata: write contents: read id-token: write packages: write @@ -163,7 +162,7 @@ jobs: id: artifacts uses: ./.github/actions/resolve-sha-artifacts with: - manifest-ref: ${{ needs.publish-sha-artifacts.outputs.manifest_ref }} + manifest-ref: ${{ needs.publish-sha-artifacts.outputs.manifest-ref }} source-sha: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish-sha-artifacts.yml b/.github/workflows/publish-sha-artifacts.yml index 8618b5a075..8cdec63de6 100644 --- a/.github/workflows/publish-sha-artifacts.yml +++ b/.github/workflows/publish-sha-artifacts.yml @@ -17,14 +17,13 @@ on: type: string default: "rust-binary-*" outputs: - manifest_ref: + manifest-ref: description: "Digest-pinned OCI manifest reference" value: ${{ jobs.publish.outputs.manifest_ref }} permissions: actions: read attestations: write - artifact-metadata: write contents: read id-token: write packages: write From bc1b7ffa1e303d7ce22047358e66e7d248ec1fb1 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 26 Aug 2026 14:22:46 +0200 Subject: [PATCH 10/11] fix(ci): use valid SHA manifest output name Signed-off-by: Evan Lezar --- .github/workflows/branch-e2e.yml | 2 +- .github/workflows/publish-sha-artifacts.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/branch-e2e.yml b/.github/workflows/branch-e2e.yml index ae8e8fa83c..b6e63d8833 100644 --- a/.github/workflows/branch-e2e.yml +++ b/.github/workflows/branch-e2e.yml @@ -162,7 +162,7 @@ jobs: id: artifacts uses: ./.github/actions/resolve-sha-artifacts with: - manifest-ref: ${{ needs.publish-sha-artifacts.outputs.manifest-ref }} + manifest-ref: ${{ needs.publish-sha-artifacts.outputs.manifest_ref }} source-sha: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish-sha-artifacts.yml b/.github/workflows/publish-sha-artifacts.yml index 8cdec63de6..e56f89aaf9 100644 --- a/.github/workflows/publish-sha-artifacts.yml +++ b/.github/workflows/publish-sha-artifacts.yml @@ -17,7 +17,7 @@ on: type: string default: "rust-binary-*" outputs: - manifest-ref: + manifest_ref: description: "Digest-pinned OCI manifest reference" value: ${{ jobs.publish.outputs.manifest_ref }} From 64d2134e379ada5da8f42e4efe575c421a7d77d3 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Wed, 26 Aug 2026 14:24:21 +0200 Subject: [PATCH 11/11] fix(ci): inherit publisher workflow secrets Signed-off-by: Evan Lezar --- .github/workflows/branch-e2e.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/branch-e2e.yml b/.github/workflows/branch-e2e.yml index b6e63d8833..001076b364 100644 --- a/.github/workflows/branch-e2e.yml +++ b/.github/workflows/branch-e2e.yml @@ -147,6 +147,7 @@ jobs: with: source-sha: ${{ github.sha }} artifact-set: branch-e2e + secrets: inherit verify-sha-artifacts: needs: [pr_metadata, publish-sha-artifacts]