Skip to content

Commit acca946

Browse files
committed
feat(release): publish immutable core runtime identity manifest
Bind standalone core archives and container images to their producing source commit and workflow run. Verify archive bytes, executable architecture and image executable hashes before assembling and attesting the development release manifest. Preserve same-run retry support while rejecting inconsistent identities. Document the inventory limits, installation workflow and release diagnostics. Related to #2946. Cross-workflow artifact resolution and packaging reuse remain separate work. Signed-off-by: Shiju <shiju@nvidia.com>
1 parent c108c31 commit acca946

8 files changed

Lines changed: 894 additions & 4 deletions

File tree

.agents/skills/test-release-canary/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ validation lives in the `TypeScript SDK` branch check, including a publish
3737
dry-run. The tagged release workflow publishes the package to GitHub Packages;
3838
verify that job directly when diagnosing SDK publication failures.
3939

40+
Release Dev also publishes an attested `openshell-release-manifest.json` for standalone core runtime archives and container images. The canary does not download or verify that manifest and continues to consume the rolling dev packages, chart and image tags. A passing canary proves only the install and runtime paths it exercises; it does not prove manifest attestation or digest selection. For manifest failures, inspect the producing Release Dev run's image identity, assembly and attestation steps with `watch-github-actions`.
41+
4042
## Trigger paths
4143

4244
The workflow has two triggers:

.agents/skills/watch-github-actions/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ not substitute the current `main` tip or the event's older PR base SHA. Merge
132132
groups and manual runs use their explicit baseline. Findings are reported by
133133
`Reject new high or critical findings`; distinguish those from scanner failures.
134134

135+
For core runtime release identity failures, inspect `Record immutable image identity` and `Verify SBOM attestation` in the Build Images jobs, then `Download producing image identities`, `Assemble immutable core runtime manifest` and `Attest core runtime manifest` in Release Dev. Build Images is shared by Branch E2E, Release Dev and Release Tag; only Release Dev assembles and publishes `openshell-release-manifest.json`. Compare the `core-image-identity-*` artifacts' source SHA and workflow run ID with the failing release job. A downstream retry can reuse completed image jobs from the same source and run; identities from a different run are rejected. Assembly also checks archive checksums and matches staged image executable hashes to the corresponding archives, so inspect the failed component and platform before rerunning jobs. Assembly and attestation finish before development release assets are replaced or image tags are promoted; successful canary installation does not verify the manifest.
136+
135137
View logs for a specific run:
136138

137139
```bash

.github/actions/build-docker-image/action.yml

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ inputs:
2424
runs:
2525
using: composite
2626
steps:
27+
- name: Set up release identity tooling
28+
uses: astral-sh/setup-uv@ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d # v10.0.0
29+
with:
30+
version: "0.10.12"
31+
enable-cache: false
32+
2733
- uses: ./.github/actions/setup-buildx
2834
with:
2935
buildkitd-config: /etc/buildkit/buildkitd.toml
@@ -56,6 +62,8 @@ runs:
5662
install -Dm0755 artifact/arm64/${BINARY} deploy/docker/.build/prebuilt-binaries/arm64/${BINARY}
5763
5864
- name: Build ${{ inputs.component }} image
65+
# Keep both exporters' manifest options identical: Buildx reports one
66+
# image digest, which must also identify the pushed registry object.
5967
shell: bash
6068
env:
6169
COMPONENT: ${{ inputs.component }}
@@ -72,15 +80,46 @@ runs:
7280
--cache-to type=gha,mode=max,scope=${COMPONENT} \
7381
--provenance=mode=min \
7482
--attest type=sbom \
83+
--metadata-file artifacts/images/${COMPONENT}-build-metadata.json \
7584
--output type=image,push=true,oci-mediatypes=true,oci-artifact=true \
76-
--output type=oci,dest=artifacts/images/${COMPONENT}.tar \
85+
--output type=oci,dest=artifacts/images/${COMPONENT}.tar,oci-mediatypes=true,oci-artifact=true \
7786
.
7887
88+
- name: Record immutable image identity
89+
shell: bash
90+
env:
91+
COMPONENT: ${{ inputs.component }}
92+
run: |
93+
set -euo pipefail
94+
metadata="artifacts/images/${COMPONENT}-build-metadata.json"
95+
digest=$(uv run --no-project --offline --no-python-downloads --python python3 python tasks/scripts/release.py image-build-digest --metadata-file "$metadata")
96+
docker buildx imagetools inspect "ghcr.io/nvidia/openshell/${COMPONENT}@${digest}" --raw > "artifacts/images/${COMPONENT}-index.json"
97+
uv run --no-project --offline --no-python-downloads --python python3 python tasks/scripts/release.py record-image-identity \
98+
--component "$COMPONENT" \
99+
--source-sha "$(git rev-parse HEAD)" \
100+
--run-id "$GITHUB_RUN_ID" \
101+
--run-attempt "$GITHUB_RUN_ATTEMPT" \
102+
--metadata-file "$metadata" \
103+
--index-file "artifacts/images/${COMPONENT}-index.json" \
104+
--binary-dir artifact \
105+
--output "image-identities/${COMPONENT}.json"
106+
79107
- name: Verify SBOM attestation
80108
shell: bash
81109
env:
82-
IMAGE_REF: ghcr.io/nvidia/openshell/${{ inputs.component }}:${{ inputs.image-tag }}
83-
run: tasks/scripts/verify-image-sbom.sh "${IMAGE_REF}" --require-cargo
110+
COMPONENT: ${{ inputs.component }}
111+
run: |
112+
set -euo pipefail
113+
digest=$(uv run --no-project --offline --no-python-downloads --python python3 python tasks/scripts/release.py image-build-digest --metadata-file "artifacts/images/${COMPONENT}-build-metadata.json")
114+
tasks/scripts/verify-image-sbom.sh "ghcr.io/nvidia/openshell/${COMPONENT}@${digest}" --require-cargo
115+
116+
- name: Upload ${{ inputs.component }} identity
117+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
118+
with:
119+
name: core-image-identity-${{ inputs.component }}
120+
path: image-identities/${{ inputs.component }}.json
121+
retention-days: 5
122+
if-no-files-found: error
84123

85124
- name: Upload ${{ inputs.component }} image
86125
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7

.github/workflows/release-dev.yml

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ jobs:
244244
# ---------------------------------------------------------------------------
245245
release-dev:
246246
name: Release Dev
247-
needs: [compute-versions, package-binaries, build-python-wheel, conformance, docker-e2e, podman-e2e, vm-e2e, build-deb, build-rpm, build-snap]
247+
needs: [compute-versions, package-binaries, build-images, build-python-wheel, conformance, docker-e2e, podman-e2e, vm-e2e, build-deb, build-rpm, build-snap]
248248
runs-on: linux-amd64-cpu8
249249
timeout-minutes: 10
250250
permissions:
@@ -257,6 +257,19 @@ jobs:
257257
steps:
258258
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
259259

260+
- name: Download producing image identities
261+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
262+
with:
263+
pattern: core-image-identity-*
264+
path: image-identities/
265+
merge-multiple: true
266+
267+
- name: Set up release identity tooling
268+
uses: astral-sh/setup-uv@ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d # v10.0.0
269+
with:
270+
version: "0.10.12"
271+
enable-cache: false
272+
260273
- name: Download all CLI artifacts
261274
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
262275
with:
@@ -399,6 +412,25 @@ jobs:
399412
openshell-supervisor-aarch64-unknown-linux-gnu.tar.gz > openshell-supervisor-checksums-sha256.txt
400413
cat openshell-supervisor-checksums-sha256.txt
401414
415+
- name: Assemble immutable core runtime manifest
416+
env:
417+
CARGO_VERSION: ${{ needs.compute-versions.outputs.cargo_version }}
418+
run: |
419+
set -euo pipefail
420+
uv run --no-project --offline --no-python-downloads --python python3 python tasks/scripts/release.py generate-release-manifest \
421+
--source-sha "$GITHUB_SHA" \
422+
--run-id "$GITHUB_RUN_ID" \
423+
--run-attempt "$GITHUB_RUN_ATTEMPT" \
424+
--cargo-version "$CARGO_VERSION" \
425+
--release-dir release \
426+
--image-dir image-identities \
427+
--output release/openshell-release-manifest.json
428+
429+
- name: Attest core runtime manifest
430+
uses: actions/attest@508db95dd578ae2727ebd6217d5ba78e4fbda05d # v4.2.1
431+
with:
432+
subject-path: release/openshell-release-manifest.json
433+
402434
- name: Generate Homebrew formula
403435
run: |
404436
set -euo pipefail
@@ -448,6 +480,7 @@ jobs:
448480
name.endsWith('.whl') ||
449481
name.endsWith('.deb') ||
450482
name.endsWith('.rpm') ||
483+
name === 'openshell-release-manifest.json' ||
451484
name.endsWith('.snap')
452485
)
453486
);
@@ -518,6 +551,7 @@ jobs:
518551
release/openshell-sandbox-checksums-sha256.txt
519552
release/openshell-supervisor-checksums-sha256.txt
520553
release/openshell-prover-checksums-sha256.txt
554+
release/openshell-release-manifest.json
521555
522556
release-helm:
523557
name: Release Helm Chart (OCI, dev)

architecture/build.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ generated by BuildKit's default Syft scanner. The registry exporter uses OCI
162162
media types and `oci-artifact=true`, so each attestation identifies its subject.
163163
GHCR exposes these through the image index because it has no referrers API.
164164

165+
The image-producing action also records the exact OCI index and Linux platform digests, source commit, workflow run and staged executable hashes. Release Dev joins those records with checksum-verified standalone core archives and checks that each image's staged executable matches the archive for the same component and platform. It assembles and attests a versioned `openshell-release-manifest.json` only after the complete core matrix validates, before replacing development release assets or promoting image tags, then publishes the manifest alongside the archives. A downstream retry may reuse completed image jobs from the same source and workflow run; another run's identities are rejected. The manifest describes artifact association, not tested protocol compatibility or live deployment health. Release Tag publication remains a separate release path.
166+
165167
Attestations require a registry-backed image index. Local builds therefore keep
166168
`--provenance=false`, and Podman builds carry neither attestation.
167169
`tasks/scripts/verify-image-sbom.sh` verifies the merged multi-arch tag and runs

docs/about/installation.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ The script detects your operating system and installs the OpenShell CLI, standal
2020

2121
You can also download release artifacts directly from the [OpenShell GitHub Releases](https://github.com/NVIDIA/OpenShell/releases) page.
2222

23+
Development builds publish `openshell-release-manifest.json` with an artifact attestation. Its `schema_version: 1` and `inventory_scope: "core-runtime"` describe the standalone CLI, gateway, sandbox and supervisor archives, and gateway/sandbox/supervisor container images. The manifest records the full source commit, Cargo version, workflow run, archive targets and SHA256 checksums, and image index and platform digests. Native installer packages, VM-driver bundles, the prover and SDKs are outside this inventory. Retain the manifest, verify downloaded archive bytes against its checksums, and use image references in the form `<repository>@<index_digest>` or the selected platform digest. The development download location can move; a checksum mismatch requires obtaining the matching build instead of silently adopting the new bytes. These identities describe one build and do not establish runtime qualification or upgrade compatibility.
24+
2325
### Install a prerelease
2426

2527
Prerelease packages are retained as GitHub Actions artifacts for 90 days and require an authenticated [GitHub CLI](https://cli.github.com/) session. The `pre` alias installs the latest prerelease:

0 commit comments

Comments
 (0)