fix: use wsc for keyless signing, fix artifact collection #2
Workflow file for this run
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: Release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Tag to release (e.g., v1.0.0)" | |
| required: true | |
| type: string | |
| permissions: | |
| contents: write | |
| id-token: write | |
| attestations: write | |
| jobs: | |
| build-release: | |
| name: Build Release Components | |
| runs-on: ubuntu-latest | |
| outputs: | |
| tag_name: ${{ steps.get_tag.outputs.tag_name }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get tag name | |
| id: get_tag | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "tag_name=${{ inputs.tag }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "tag_name=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Install Bazelisk | |
| run: | | |
| curl -LO https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-amd64 | |
| chmod +x bazelisk-linux-amd64 | |
| sudo mv bazelisk-linux-amd64 /usr/local/bin/bazel | |
| - name: Build all components | |
| run: bazel build //... | |
| - name: Collect release artifacts | |
| id: collect | |
| run: | | |
| TAG_NAME="${{ steps.get_tag.outputs.tag_name }}" | |
| VERSION=${TAG_NAME#v} | |
| RELEASE_DIR="release-${VERSION}" | |
| mkdir -p "${RELEASE_DIR}/c" "${RELEASE_DIR}/cpp" "${RELEASE_DIR}/rust" | |
| # Find all built WASM files | |
| echo "=== Finding all WASM files ===" | |
| find bazel-out -name "*.wasm" -type f 2>/dev/null | head -50 | |
| # Collect C components (use find for more reliable collection) | |
| echo "=== Collecting C components ===" | |
| for name in hello_c_debug hello_c_release; do | |
| f=$(find bazel-out -name "${name}.wasm" -type f 2>/dev/null | head -1) | |
| if [ -n "$f" ]; then | |
| echo "Found: $f" | |
| cp "$f" "${RELEASE_DIR}/c/" | |
| fi | |
| done | |
| # Collect C++ components | |
| echo "=== Collecting C++ components ===" | |
| for name in hello_cpp_debug hello_cpp_release; do | |
| f=$(find bazel-out -name "${name}.wasm" -type f 2>/dev/null | head -1) | |
| if [ -n "$f" ]; then | |
| echo "Found: $f" | |
| cp "$f" "${RELEASE_DIR}/cpp/" | |
| fi | |
| done | |
| # Collect Rust CLI components | |
| echo "=== Collecting Rust CLI components ===" | |
| for name in hello_rust calculator datetime; do | |
| f=$(find bazel-out -name "${name}.wasm" -type f 2>/dev/null | head -1) | |
| if [ -n "$f" ]; then | |
| echo "Found: $f" | |
| cp "$f" "${RELEASE_DIR}/rust/" | |
| fi | |
| done | |
| # Collect Rust YOLO components (profile-based naming) | |
| echo "=== Collecting Rust YOLO components ===" | |
| for profile in debug release; do | |
| # Try different naming patterns | |
| for pattern in "yolo_inference_${profile}.wasm" "yolo_inference_wasm_lib_${profile}.wasm" "yolo_inference_*${profile}*.wasm"; do | |
| f=$(find bazel-out -name "$pattern" -type f 2>/dev/null | head -1) | |
| if [ -n "$f" ]; then | |
| echo "Found: $f" | |
| cp "$f" "${RELEASE_DIR}/rust/yolo_inference_${profile}.wasm" | |
| break | |
| fi | |
| done | |
| done | |
| # List what we collected | |
| echo "=== Collected artifacts ===" | |
| find "${RELEASE_DIR}" -name "*.wasm" -type f | |
| # Create archive | |
| ARCHIVE_NAME="wasm-components-${VERSION}.tar.gz" | |
| tar -czvf "$ARCHIVE_NAME" "${RELEASE_DIR}" | |
| echo "archive_name=$ARCHIVE_NAME" >> $GITHUB_OUTPUT | |
| echo "release_dir=$RELEASE_DIR" >> $GITHUB_OUTPUT | |
| echo "" | |
| echo "Created release archive:" | |
| ls -la "$ARCHIVE_NAME" | |
| echo "" | |
| echo "Contents:" | |
| tar -tzvf "$ARCHIVE_NAME" | |
| - name: Build wsc for signing | |
| run: | | |
| echo "Building wsc (WebAssembly Signature Component)..." | |
| git clone --depth 1 https://github.com/pulseengine/wsc.git /tmp/wsc | |
| cd /tmp/wsc | |
| cargo build --release --bin wsc | |
| sudo cp target/release/wsc /usr/local/bin/wsc | |
| wsc --version || echo "wsc built successfully" | |
| - name: Sign release components (keyless) | |
| run: | | |
| RELEASE_DIR="${{ steps.collect.outputs.release_dir }}" | |
| echo "🔐 Signing WASM artifacts with wsc keyless signing..." | |
| echo " - Identity: GitHub Actions OIDC" | |
| echo " - Certificate: Short-lived from Fulcio (Sigstore)" | |
| echo " - Transparency: Logged in Rekor" | |
| echo "" | |
| # Sign all WASM files with keyless signing | |
| find "${RELEASE_DIR}" -name "*.wasm" | while read wasm_file; do | |
| echo "Signing: $wasm_file" | |
| signed_file="${wasm_file%.wasm}.signed.wasm" | |
| wsc sign --keyless \ | |
| --input-file "$wasm_file" \ | |
| --output-file "$signed_file" | |
| # Replace original with signed version | |
| mv "$signed_file" "$wasm_file" | |
| done | |
| echo "✅ All WASM files signed with wsc (keyless)" | |
| # Create signed archive | |
| SIGNED_ARCHIVE="wasm-components-${{ steps.get_tag.outputs.tag_name }}-signed.tar.gz" | |
| tar -czvf "$SIGNED_ARCHIVE" "${RELEASE_DIR}" | |
| echo "signed_archive=$SIGNED_ARCHIVE" >> $GITHUB_OUTPUT | |
| - name: Generate Release Notes | |
| run: | | |
| TAG_NAME="${{ steps.get_tag.outputs.tag_name }}" | |
| cat > RELEASE_NOTES.md << 'EOF' | |
| ## WebAssembly Component Examples ${{ steps.get_tag.outputs.tag_name }} | |
| This release contains WebAssembly components built with [rules_wasm_component](https://github.com/pulseengine/rules_wasm_component). | |
| ### Components Included | |
| **C Components:** | |
| - `hello_c_debug.wasm` - Debug build | |
| - `hello_c_release.wasm` - Release build (optimized) | |
| **C++ Components:** | |
| - `hello_cpp_debug.wasm` - Debug build | |
| - `hello_cpp_release.wasm` - Release build (optimized) | |
| **Rust Components:** | |
| - `hello_rust.wasm` - Hello World CLI | |
| - `calculator.wasm` - Arithmetic calculator | |
| - `datetime.wasm` - Date/time display | |
| - `yolo_inference_debug.wasm` - YOLO detection (debug) | |
| - `yolo_inference_release.wasm` - YOLO detection (release) | |
| ### Security | |
| All components are signed using [wsc](https://github.com/pulseengine/wsc) with keyless Sigstore signing: | |
| - **Identity**: GitHub Actions OIDC | |
| - **Certificate**: Short-lived from Fulcio | |
| - **Transparency**: Logged in Rekor | |
| ### Running Components | |
| ```bash | |
| # Install wasmtime | |
| curl https://wasmtime.dev/install.sh -sSf | bash | |
| # Run Rust CLI examples | |
| wasmtime run hello_rust.wasm | |
| wasmtime run calculator.wasm 8 + 8 | |
| wasmtime run datetime.wasm | |
| # Run YOLO detection (requires ONNX model) | |
| wasmtime run --dir . -S cli -S nn -S nn-graph=onnx::./models/yolov8n \ | |
| yolo_inference_release.wasm ./image.jpg | |
| ``` | |
| ### Verification | |
| Signatures can be verified using wsc: | |
| ```bash | |
| wsc verify --keyless \ | |
| --identity "https://github.com/${{ github.repository }}" \ | |
| --issuer "https://token.actions.githubusercontent.com" \ | |
| --input-file component.wasm | |
| ``` | |
| EOF | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.get_tag.outputs.tag_name }} | |
| name: Release ${{ steps.get_tag.outputs.tag_name }} | |
| body_path: RELEASE_NOTES.md | |
| files: | | |
| ${{ steps.collect.outputs.archive_name }} | |
| wasm-components-${{ steps.get_tag.outputs.tag_name }}-signed.tar.gz | |
| draft: false | |
| prerelease: false | |
| generate_release_notes: true | |
| make_latest: true | |
| - name: Generate Provenance Attestation | |
| uses: actions/attest-build-provenance@v2 | |
| with: | |
| subject-path: ${{ steps.collect.outputs.archive_name }} |