fix: book contract enforcement — PCU IDs match contract filenames (To… #36
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
| # Per-repo release workflow — tagged releases only | ||
| # Generated by machines/clean-room/deploy-workflows.sh — do not edit manually. | ||
| # Spec: docs/specifications/sovereign-stack-protected-branch-strategy.md | ||
| # | ||
| # Flow: tag push → clean-room gate → package verify → trusted publish → GitHub Release | ||
| # | ||
| # Tag formats: | ||
| # v1.0.0 — single-crate repos | ||
| # v-<crate>-1.0.0 — workspace repos (e.g. v-apr-cli-0.4.0) | ||
| # | ||
| # IMPORTANT: Tags must be pushed with a PAT or deploy key (not GITHUB_TOKEN), | ||
| # otherwise this workflow will not trigger (GitHub anti-recursion measure). | ||
| name: Release | ||
| on: | ||
| push: | ||
| tags: ['v*'] | ||
| permissions: | ||
| contents: write # create GitHub Release | ||
| id-token: write # OIDC for crates.io Trusted Publishing | ||
| # One release at a time per repo | ||
| concurrency: | ||
| group: release-${{ github.repository }} | ||
| cancel-in-progress: false | ||
| jobs: | ||
| # ── Gate: clean-room must pass before publish ─────────── | ||
| gate: | ||
| uses: paiml/infra/.github/workflows/clean-room-gate.yml@main | ||
| timeout-minutes: 30 | ||
| with: | ||
| repo: ${{ github.event.repository.name }} | ||
| pr_sha: ${{ github.sha }} | ||
| secrets: inherit | ||
| # ── Verify: tag-version match + package tarball ───────── | ||
| verify: | ||
| needs: gate | ||
| runs-on: [self-hosted, clean-room] | ||
| timeout-minutes: 30 | ||
| outputs: | ||
| crate_name: ${{ steps.parse.outputs.crate_name }} | ||
| version: ${{ steps.parse.outputs.version }} | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | ||
| with: | ||
| persist-credentials: false | ||
| - name: Parse tag and verify version | ||
| id: parse | ||
| run: | | ||
| TAG="${GITHUB_REF_NAME}" | ||
| # Parse tag format: v1.0.0 or v-cratename-1.0.0 | ||
| if [[ "$TAG" =~ ^v-([a-z][a-z0-9_-]*)-([0-9]+\..+)$ ]]; then | ||
| CRATE_NAME="${BASH_REMATCH[1]}" | ||
| TAG_VER="${BASH_REMATCH[2]}" | ||
| echo "Workspace release: crate=$CRATE_NAME version=$TAG_VER" | ||
| elif [[ "$TAG" =~ ^v([0-9]+\..+)$ ]]; then | ||
| CRATE_NAME="" | ||
| TAG_VER="${BASH_REMATCH[1]}" | ||
| echo "Single-crate release: version=$TAG_VER" | ||
| else | ||
| echo "::error::Tag '$TAG' does not match expected format (v1.0.0 or v-crate-1.0.0)" | ||
| exit 1 | ||
| fi | ||
| # Use cargo metadata for reliable version extraction | ||
| if [ -n "$CRATE_NAME" ]; then | ||
| CARGO_VER=$(cargo metadata --format-version 1 --no-deps \ | ||
| | jq -r ".packages[] | select(.name == \"$CRATE_NAME\") | .version") | ||
| if [ -z "$CARGO_VER" ] || [ "$CARGO_VER" = "null" ]; then | ||
| echo "::error::Crate '$CRATE_NAME' not found in workspace" | ||
| exit 1 | ||
| fi | ||
| else | ||
| CARGO_VER=$(cargo metadata --format-version 1 --no-deps \ | ||
| | jq -r '.packages[0].version') | ||
| fi | ||
| if [ "$TAG_VER" != "$CARGO_VER" ]; then | ||
| echo "::error::Tag version $TAG_VER != Cargo.toml version $CARGO_VER" | ||
| exit 1 | ||
| fi | ||
| echo "crate_name=$CRATE_NAME" >> "$GITHUB_OUTPUT" | ||
| echo "version=$TAG_VER" >> "$GITHUB_OUTPUT" | ||
| echo "Version verified: $TAG_VER" | ||
| - name: Verify package tarball | ||
| run: | | ||
| CRATE="${{ steps.parse.outputs.crate_name }}" | ||
| if [ -n "$CRATE" ]; then | ||
| cargo package --verify -p "$CRATE" | ||
| else | ||
| cargo package --verify | ||
| fi | ||
| # ── Publish: OIDC trusted publishing to crates.io ────── | ||
| publish: | ||
| needs: verify | ||
| runs-on: [self-hosted, clean-room] | ||
| timeout-minutes: 30 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | ||
| with: | ||
| persist-credentials: false | ||
| - name: Authenticate to crates.io (OIDC) | ||
| uses: rust-lang/crates-io-auth-action@b7e9a28eded4986ec6b1fa40eeee8f8f165559ec # v1.0.3 | ||
| - name: Publish | ||
| run: | | ||
| CRATE="${{ needs.verify.outputs.crate_name }}" | ||
| if [ -n "$CRATE" ]; then | ||
| cargo publish -p "$CRATE" | ||
| else | ||
| cargo publish | ||
| fi | ||
| - name: Create GitHub Release | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| gh release create "$GITHUB_REF_NAME" \ | ||
| --title "$GITHUB_REF_NAME" \ | ||
| --generate-notes | ||