Nightly Release (ORAS) #228
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |