Skip to content

Nightly Release (ORAS) #228

Nightly Release (ORAS)

Nightly Release (ORAS) #228

Workflow file for this run

name: Nightly Release (ORAS)
on:
schedule:
- cron: "0 0 * * *" # midnight GMT
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
jobs:
prepare-nightly-release:
name: Prepare nightly tag + delete prior release
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Set nightly tag to latest main
shell: bash
run: |
set -euo pipefail
git fetch origin main
git tag -f nightly origin/main
git push -f origin nightly
- name: Delete existing nightly release (if any)
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release delete nightly --yes || true
build-wasm:
name: Build plugin.wasm
needs: prepare-nightly-release
runs-on: ubuntu-24.04
permissions:
contents: read
outputs:
sha: ${{ steps.meta.outputs.sha }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
fetch-depth: 0
submodules: true
- name: Install Rust toolchain + wasm target
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: "1.94"
components: rustc rust-std cargo clippy rustfmt
targets: wasm32-wasip1
- name: Show active toolchain
shell: bash
run: |
set -euo pipefail
rustc -Vv
cargo -V
rustup target list --installed
- name: Install cargo-auditable
shell: bash
run: cargo install cargo-auditable
- name: Build wasm (auditable)
shell: bash
run: |
set -euo pipefail
cargo +1.94 fetch
cargo +1.94 auditable build --release --target wasm32-wasip1
cp target/wasm32-wasip1/release/plugin.wasm ./plugin.wasm
- name: Ensure plugin.wasm exists
shell: bash
run: |
set -euo pipefail
ls -lh ./plugin.wasm
- name: Record commit sha
id: meta
shell: bash
run: |
set -euo pipefail
echo "sha=${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
- name: Upload wasm artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: plugin-wasm
path: plugin.wasm
if-no-files-found: error
publish-oras:
name: Publish ORAS artifact + sign
needs: build-wasm
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
id-token: write # keyless signing
outputs:
nightly_ref: ${{ steps.meta.outputs.nightly_ref }}
nightly_digest: ${{ steps.digest.outputs.nightly_digest }}
steps:
- name: Download wasm artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: plugin-wasm
path: .
- name: Install ORAS
uses: oras-project/setup-oras@38de303aac69abb66f3e6255b7198bff35f323e3 # v2.0.0
- name: Install cosign
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
- name: ORAS login to GHCR
shell: bash
run: |
set -euo pipefail
echo "${{ secrets.GITHUB_TOKEN }}" | oras login ghcr.io -u "${{ github.actor }}" --password-stdin
- name: Compute ORAS ref
id: meta
shell: bash
run: |
set -euo pipefail
REF="ghcr.io/${{ github.repository }}:nightly"
echo "nightly_ref=$REF" >> "$GITHUB_OUTPUT"
- name: Push ORAS artifact (plugin.wasm)
shell: bash
run: |
set -euo pipefail
REF="${{ steps.meta.outputs.nightly_ref }}"
# Publish as an OCI artifact:
# - artifact type: identifies "this is a hyper-mcp plugin artifact"
# - layer: the wasm blob
oras push "$REF" \
--artifact-type application/vnd.hyper-mcp.plugin.v2 \
./plugin.wasm:application/wasm
- name: Resolve ORAS digest
id: digest
shell: bash
run: |
set -euo pipefail
REF="${{ steps.meta.outputs.nightly_ref }}"
# Get the descriptor JSON and extract the digest
nightly_digest="$(
oras manifest fetch "$REF" --descriptor \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["digest"])'
)"
if [[ ! "$nightly_digest" =~ ^sha256:[0-9a-f]{64}$ ]]; then
echo "ERROR: Invalid digest: '$nightly_digest'" >&2
exit 1
fi
echo "nightly_digest=$nightly_digest" >> "$GITHUB_OUTPUT"
echo "Resolved nightly digest: $nightly_digest"
- name: Sign ORAS artifact by digest
shell: bash
run: |
set -euo pipefail
IMAGE="ghcr.io/${{ github.repository }}"
cosign sign --yes "${IMAGE}@${{ steps.digest.outputs.nightly_digest }}"
sbom:
name: SBOM
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
submodules: true
- name: Install cargo-cyclonedx
run: cargo install cargo-cyclonedx --locked
- name: Generate CycloneDX SBOM
run: cargo cyclonedx -f json --all-features --override-filename temp
- name: Clean SBOM
run: jq '
del(.metadata.component."bom-ref")
| del(.metadata.component.purl)
| del(.metadata.component.components[0]."bom-ref")
| del(.metadata.component.components[0].purl)
' temp.json > sbom.cdx.json
- name: Upload sbom artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sbom-cdx-json
path: sbom.cdx.json
if-no-files-found: error
publish-nightly-release:
name: Publish nightly GitHub Release
needs: [publish-oras, sbom]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download wasm artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: plugin-wasm
path: .
- name: Download sbom artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: sbom-cdx-json
path: .
- name: Create release notes
shell: bash
run: |
set -euo pipefail
IMAGE="ghcr.io/${{ github.repository }}"
REF="${{ needs.publish-oras.outputs.nightly_ref }}"
DIGEST="${{ needs.publish-oras.outputs.nightly_digest }}"
cat > release-body.md <<EOF
Nightly build from \`main\`.
OCI artifact (tag):
- \`${REF}\`
✅ Immutable digest (recommended for pinning):
- \`${IMAGE}@${DIGEST}\`
Release asset:
- \`plugin.wasm\`
- \`sbom.cdx.json\`
Pull with ORAS:
\`\`\`bash
oras pull ${REF}
\`\`\`
All artifacts are signed with Cosign. Verify the **immutable digest** with:
\`\`\`bash
cosign verify \
--certificate-identity-regexp "https://github.com/${{ github.repository }}/.github/workflows/nightly.yml@refs/heads/main" \
--certificate-oidc-issuer-regexp "https://token.actions.githubusercontent.com" \
${IMAGE}@${DIGEST}
\`\`\`
EOF
- name: Create new nightly release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
tag_name: nightly
name: Nightly build (ORAS)
draft: false
prerelease: true
generate_release_notes: true
preserve_order: true
body_path: release-body.md
files: |
plugin.wasm
sbom.cdx.json