v2026.05.18.2 #13
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
| # Sign Release Binaries | |
| # | |
| # This workflow signs all release artifacts with Ed25519 signatures | |
| # using zipsign. It runs automatically when a release is created. | |
| # | |
| # Prerequisites: | |
| # - ZIPSIGN_PRIVATE_KEY secret must be set in GitHub repository settings | |
| # - The private key should be the Ed25519 private key generated via | |
| # scripts/generate-zipsign-keypair.sh | |
| # | |
| # Security: | |
| # - Private key is stored as a GitHub secret (never in code) | |
| # - Signing happens in a clean GitHub Actions environment | |
| # - Signed artifacts are uploaded back to the release | |
| name: Sign Release | |
| on: | |
| release: | |
| types: [created] | |
| permissions: | |
| contents: write # Required to upload artifacts to releases | |
| jobs: | |
| sign: | |
| name: Sign Release Artifacts | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install zipsign | |
| run: | | |
| cargo install zipsign | |
| zipsign --version | |
| - name: Download release artifacts | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # Get the tag name without 'v' prefix | |
| VERSION="${GITHUB_REF#refs/tags/v}" | |
| echo "Version: $VERSION" | |
| echo "VERSION=$VERSION" >> $GITHUB_ENV | |
| # Create directory for artifacts | |
| mkdir -p artifacts | |
| # Download all assets from the release | |
| gh release view "$VERSION" --json assets --jq '.assets[].name' | \ | |
| while read -r asset_name; do | |
| # Remove quotes from asset name | |
| asset_name=$(echo "$asset_name" | tr -d '"') | |
| # Only download tar.gz and tar.zst archives | |
| if [[ "$asset_name" =~ \.(tar\.gz|tar\.zst)$ ]]; then | |
| echo "Downloading: $asset_name" | |
| gh release download "$VERSION" --pattern "$asset_name" --dir artifacts | |
| fi | |
| done | |
| # List downloaded artifacts | |
| echo "Downloaded artifacts:" | |
| ls -lh artifacts/ | |
| - name: Verify artifacts exist | |
| run: | | |
| if [ -z "$(ls -A artifacts/)" ]; then | |
| echo "No artifacts found to sign!" | |
| exit 1 | |
| fi | |
| # Count archives | |
| ARCHIVE_COUNT=$(find artifacts/ -type f \( -name "*.tar.gz" -o -name "*.tar.zst" \) | wc -l) | |
| echo "Found $ARCHIVE_COUNT archive(s) to sign" | |
| if [ "$ARCHIVE_COUNT" -eq 0 ]; then | |
| echo "No tar.gz or tar.zst archives found" | |
| exit 1 | |
| fi | |
| - name: Sign artifacts | |
| env: | |
| ZIPSIGN_PRIVATE_KEY: ${{ secrets.ZIPSIGN_PRIVATE_KEY }} | |
| run: | | |
| if [ -z "$ZIPSIGN_PRIVATE_KEY" ]; then | |
| echo "Error: ZIPSIGN_PRIVATE_KEY secret not set" | |
| echo "Please set the private key as a GitHub secret" | |
| exit 1 | |
| fi | |
| # Save private key to temporary file | |
| PRIVATE_KEY_FILE=$(mktemp) | |
| echo "$ZIPSIGN_PRIVATE_KEY" > "$PRIVATE_KEY_FILE" | |
| chmod 600 "$PRIVATE_KEY_FILE" | |
| # Sign each archive | |
| SIGNED_COUNT=0 | |
| for archive in artifacts/*.{tar.gz,tar.zst}; do | |
| if [ -f "$archive" ]; then | |
| echo "Signing: $(basename "$archive")" | |
| # Check if already signed | |
| if zipsign verify tar "$archive" "$PRIVATE_KEY_FILE" >/dev/null 2>&1; then | |
| echo " Already signed, skipping" | |
| else | |
| # Sign the archive | |
| if zipsign sign tar "$archive" "$PRIVATE_KEY_FILE"; then | |
| echo " ✓ Signed successfully" | |
| ((SIGNED_COUNT++)) | |
| else | |
| echo " ✗ Failed to sign" | |
| exit 1 | |
| fi | |
| fi | |
| fi | |
| done | |
| echo "Signed $SIGNED_COUNT archive(s)" | |
| # Clean up private key file | |
| rm -f "$PRIVATE_KEY_FILE" | |
| - name: Verify signatures | |
| env: | |
| ZIPSIGN_PRIVATE_KEY: ${{ secrets.ZIPSIGN_PRIVATE_KEY }} | |
| run: | | |
| # Save private key to temporary file | |
| PRIVATE_KEY_FILE=$(mktemp) | |
| echo "$ZIPSIGN_PRIVATE_KEY" > "$PRIVATE_KEY_FILE" | |
| chmod 600 "$PRIVATE_KEY_FILE" | |
| # Verify each signed archive | |
| FAILED_COUNT=0 | |
| for archive in artifacts/*.{tar.gz,tar.zst}; do | |
| if [ -f "$archive" ]; then | |
| echo "Verifying: $(basename "$archive")" | |
| if zipsign verify tar "$archive" "$PRIVATE_KEY_FILE"; then | |
| echo " ✓ Signature valid" | |
| else | |
| echo " ✗ Signature invalid" | |
| ((FAILED_COUNT++)) | |
| fi | |
| fi | |
| done | |
| # Clean up private key file | |
| rm -f "$PRIVATE_KEY_FILE" | |
| if [ $FAILED_COUNT -gt 0 ]; then | |
| echo "Error: $FAILED_COUNT signature(s) failed verification" | |
| exit 1 | |
| fi | |
| echo "All signatures verified successfully" | |
| - name: Upload signed artifacts to release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # Upload each signed artifact back to the release | |
| # Note: gh release upload will replace existing assets with the same name | |
| for archive in artifacts/*.{tar.gz,tar.zst}; do | |
| if [ -f "$archive" ]; then | |
| echo "Uploading: $(basename "$archive")" | |
| gh release upload "$VERSION" "$archive" --clobber | |
| fi | |
| done | |
| echo "All signed artifacts uploaded" | |
| - name: Generate signature report | |
| if: always() | |
| run: | | |
| echo "# Signature Verification Report" > signature-report.md | |
| echo "" >> signature-report.md | |
| echo "**Release**: ${{ github.ref_name }}" >> signature-report.md | |
| echo "**Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> signature-report.md | |
| echo "**Workflow Run**: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> signature-report.md | |
| echo "" >> signature-report.md | |
| echo "## Signed Artifacts" >> signature-report.md | |
| echo "" >> signature-report.md | |
| echo '```' >> signature-report.md | |
| ls -lh artifacts/ | |
| echo '```' >> signature-report.md | |
| cat signature-report.md | |
| - name: Upload signature report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: signature-report | |
| path: signature-report.md | |
| retention-days: 90 | |
| summary: | |
| name: Generate Summary | |
| runs-on: ubuntu-latest | |
| needs: sign | |
| if: always() | |
| steps: | |
| - name: Download signature report | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: signature-report | |
| path: . | |
| - name: Add job summary | |
| run: | | |
| if [ -f signature-report.md ]; then | |
| cat signature-report.md >> $GITHUB_STEP_SUMMARY | |
| fi |