feat: add build verification and attestation to releases #7
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: | |
| version: | |
| description: 'Release version (e.g., v1.0.0)' | |
| required: false | |
| type: string | |
| permissions: | |
| contents: write | |
| attestations: write | |
| id-token: write | |
| jobs: | |
| build-release: | |
| runs-on: macos-26 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Swift | |
| uses: maartene/setup-swift@main | |
| with: | |
| swift-version: '6.2' | |
| - name: Build Release | |
| run: swift build -c release | |
| - name: Generate SHA256 Checksum | |
| id: checksum | |
| run: | | |
| shasum -a 256 .build/release/container-compose | awk '{print $1}' > .build/release/container-compose.sha256 | |
| echo "sha256=$(cat .build/release/container-compose.sha256)" >> $GITHUB_OUTPUT | |
| echo "Binary SHA256: $(cat .build/release/container-compose.sha256)" | |
| - name: Attest Build Provenance | |
| uses: actions/attest-build-provenance@v1 | |
| with: | |
| subject-path: '.build/release/container-compose' | |
| - name: Generate Verification Instructions | |
| run: | | |
| cat > .build/release/VERIFICATION.md << 'EOF' | |
| # Binary Verification | |
| ## SHA256 Checksum | |
| ``` | |
| ${{ steps.checksum.outputs.sha256 }} container-compose | |
| ``` | |
| ## Verify Download | |
| ```bash | |
| # macOS/Linux | |
| shasum -a 256 ./container-compose | grep ${{ steps.checksum.outputs.sha256 }} | |
| # Should output matching hash | |
| ``` | |
| ## Build Reproducibility | |
| This binary was built with: | |
| - macOS 26.x | |
| - Xcode 26.3 | |
| - Swift 6.2 | |
| - Apple Silicon (arm64) | |
| ## Attestation | |
| This release includes cryptographic attestation via GitHub Actions. | |
| Verify attestation: `gh attestation verify container-compose --owner explicitcontextualunderstanding` | |
| ## Source Code | |
| Tagged commit: ${{ github.sha }} | |
| Compare: https://github.com/${{ github.repository }}/compare/${{ github.ref_name }} | |
| EOF | |
| - name: Create Release with Verification | |
| if: github.event_name == 'push' | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| name: ${{ github.ref_name }} | |
| draft: false | |
| prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }} | |
| files: | | |
| .build/release/container-compose | |
| .build/release/container-compose.sha256 | |
| .build/release/VERIFICATION.md | |
| body: | | |
| ## Verification | |
| **SHA256:** `${{ steps.checksum.outputs.sha256 }}` | |
| Verify your download: | |
| ```bash | |
| shasum -a 256 ./container-compose | grep ${{ steps.checksum.outputs.sha256 }} | |
| ``` | |
| **Build Attestation:** This release includes cryptographic attestation. | |
| ```bash | |
| gh attestation verify container-compose --owner explicitcontextualunderstanding | |
| ``` | |
| See VERIFICATION.md for full details. | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload to Release (workflow_dispatch) | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| # Create release if it doesn't exist | |
| VERSION="${{ github.inputs.version || 'latest' }}" | |
| TAG="v${VERSION#v}" | |
| # Create or get release ID | |
| RELEASE_ID=$(gh api repos/${{ github.repository }}/releases/tags/$TAG --jq '.id' 2>/dev/null || echo "") | |
| if [ -z "$RELEASE_ID" ]; then | |
| RELEASE_ID=$(gh api repos/${{ github.repository }}/releases -X POST \ | |
| --field tag_name="$TAG" \ | |
| --field name="$TAG" \ | |
| --field draft=false \ | |
| --field body="## Verification | |
| **SHA256:** \`${{ steps.checksum.outputs.sha256 }}\` | |
| Verify your download: | |
| \`\`\`bash | |
| shasum -a 256 ./container-compose | grep ${{ steps.checksum.outputs.sha256 }} | |
| \`\`\` | |
| See full verification instructions in VERIFICATION.md" \ | |
| --jq '.id') | |
| fi | |
| # Upload assets | |
| gh api repos/${{ github.repository }}/releases/$RELEASE_ID/assets \ | |
| -F "file=@.build/release/container-compose" \ | |
| -F "name=container-compose" | |
| gh api repos/${{ github.repository }}/releases/$RELEASE_ID/assets \ | |
| -F "file=@.build/release/container-compose.sha256" \ | |
| -F "name=container-compose.sha256" | |
| gh api repos/${{ github.repository }}/releases/$RELEASE_ID/assets \ | |
| -F "file=@.build/release/VERIFICATION.md" \ | |
| -F "name=VERIFICATION.md" | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |