Skip to content

fix: use bazel cquery for reliable artifact collection #3

fix: use bazel cquery for reliable artifact collection

fix: use bazel cquery for reliable artifact collection #3

Workflow file for this run

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"
# Use bazel cquery to reliably find built WASM files
echo "=== Collecting C components ==="
for f in $(bazel cquery --output=files '//c:all' 2>/dev/null); do
if [[ "$f" == *.wasm ]]; then
echo "Found: $f"
cp "$f" "${RELEASE_DIR}/c/"
fi
done
echo "=== Collecting C++ components ==="
for f in $(bazel cquery --output=files '//cpp:all' 2>/dev/null); do
if [[ "$f" == *.wasm ]]; then
echo "Found: $f"
cp "$f" "${RELEASE_DIR}/cpp/"
fi
done
echo "=== Collecting Rust CLI components ==="
for target in hello_rust calculator datetime; do
f=$(bazel cquery --output=files "//rust:${target}" 2>/dev/null | head -1)
if [ -n "$f" ] && [[ "$f" == *.wasm ]]; then
echo "Found: $f"
cp "$f" "${RELEASE_DIR}/rust/"
fi
done
echo "=== Collecting Rust YOLO components ==="
for profile in debug release; do
# Query for specific profile targets
f=$(bazel cquery --output=files "//rust:yolo_inference_${profile}" 2>/dev/null | grep '\.wasm$' | head -1)
if [ -n "$f" ]; then
echo "Found: $f"
cp "$f" "${RELEASE_DIR}/rust/yolo_inference_${profile}.wasm"
fi
done
# List what we collected
echo "=== Collected artifacts ==="
find "${RELEASE_DIR}" -name "*.wasm" -type f
# Verify we have files
WASM_COUNT=$(find "${RELEASE_DIR}" -name "*.wasm" -type f | wc -l)
echo "Total WASM files collected: $WASM_COUNT"
if [ "$WASM_COUNT" -eq 0 ]; then
echo "ERROR: No WASM files were collected!"
echo "Listing bazel-out structure:"
find bazel-out -name "*.wasm" -type f 2>/dev/null | head -20 || echo "No files in bazel-out"
echo "Listing bazel-bin structure:"
find bazel-bin -name "*.wasm" -type f 2>/dev/null | head -20 || echo "No files in bazel-bin"
exit 1
fi
# 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 }}