name: 🚀 Release # Can be triggered: # 1. Automatically after sign.yml completes on main # 2. Manually, pointing at specific build/sign runs to pull artifacts from on: workflow_run: workflows: ["🔏 Sign PDFs"] types: [completed] branches: [main] workflow_dispatch: inputs: sign_run_id: description: 'sign.yml run ID to pull signatures from' required: true type: string build_run_id: description: 'build.yml run ID to pull PDFs from (leave blank to use pdfs-signed from sign run)' required: false type: string prerelease: description: 'Mark as pre-release?' required: false default: false type: boolean permissions: contents: write # create releases and tags actions: read # download artifacts from other runs jobs: release: name: Publish GitHub Release if: > github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-latest steps: - name: 🛠️ Checkout (for tags and pgp/) uses: actions/checkout@v4 with: fetch-depth: 0 sparse-checkout: pgp # ------------------------------------------------------------------ # # Resolve which run IDs to pull artifacts from # ------------------------------------------------------------------ # - name: 🔍 Resolve run IDs id: runs run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then SIGN_RUN="${{ inputs.sign_run_id }}" BUILD_RUN="${{ inputs.build_run_id }}" else SIGN_RUN="${{ github.event.workflow_run.id }}" BUILD_RUN="" fi echo "sign_run=$SIGN_RUN" >> $GITHUB_OUTPUT echo "build_run=$BUILD_RUN" >> $GITHUB_OUTPUT echo "Sign run: $SIGN_RUN" echo "Build run: ${BUILD_RUN:-'(using pdfs-signed from sign run)'}" # ------------------------------------------------------------------ # # Download artifacts # ------------------------------------------------------------------ # - name: 📥 Download signatures artifact uses: actions/download-artifact@v4 with: name: signatures path: release/ run-id: ${{ steps.runs.outputs.sign_run }} github-token: ${{ secrets.GITHUB_TOKEN }} - name: 📥 Download PDFs (from sign run) uses: actions/download-artifact@v4 with: name: pdfs-signed path: release/ run-id: ${{ steps.runs.outputs.sign_run }} github-token: ${{ secrets.GITHUB_TOKEN }} - name: 📋 List release assets run: ls -lh release/ # ------------------------------------------------------------------ # # Read hashes for the release body # ------------------------------------------------------------------ # - name: "#️⃣ Read hashes" id: hashes run: | read_hash() { cat "release/$1" 2>/dev/null || echo "(not built)"; } echo "light_sha256=$(read_hash thgtoa.pdf.sha256)" >> $GITHUB_OUTPUT echo "dark_sha256=$(read_hash thgtoa-dark.pdf.sha256)" >> $GITHUB_OUTPUT echo "light_b2=$(read_hash thgtoa.pdf.b2)" >> $GITHUB_OUTPUT echo "dark_b2=$(read_hash thgtoa-dark.pdf.b2)" >> $GITHUB_OUTPUT # ------------------------------------------------------------------ # # VirusTotal — upload whichever PDFs are present # ------------------------------------------------------------------ # - name: 🦠 Upload PDFs to VirusTotal id: vt uses: crazy-max/ghaction-virustotal@v5 with: vt_api_key: ${{ secrets.VT_API_KEY }} files: | release/thgtoa.pdf release/thgtoa-dark.pdf - name: 🔗 Build VT report URLs id: vt_urls run: | light_hash=$(cat release/thgtoa.pdf.sha256 2>/dev/null || echo "") dark_hash=$(cat release/thgtoa-dark.pdf.sha256 2>/dev/null || echo "") if [ -n "$light_hash" ]; then echo "light_vt=https://www.virustotal.com/gui/file/${light_hash}" >> $GITHUB_OUTPUT else echo "light_vt=(not built)" >> $GITHUB_OUTPUT fi if [ -n "$dark_hash" ]; then echo "dark_vt=https://www.virustotal.com/gui/file/${dark_hash}" >> $GITHUB_OUTPUT else echo "dark_vt=(not built)" >> $GITHUB_OUTPUT fi # ------------------------------------------------------------------ # # Tag + Release — auto-increment vX.Y.Z from latest semver tag # ------------------------------------------------------------------ # - name: 🏷️ Generate release tag id: tag run: | git fetch --tags --quiet LATEST=$(git tag --list 'v*' --sort=-version:refname \ | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \ | head -1) LATEST=${LATEST:-v0.0.0} MAJOR=$(echo "$LATEST" | cut -d. -f1 | tr -d 'v') MINOR=$(echo "$LATEST" | cut -d. -f2) PATCH=$(echo "$LATEST" | cut -d. -f3) PATCH=$((PATCH + 1)) TAG="v${MAJOR}.${MINOR}.${PATCH}" echo "Previous tag: $LATEST → New tag: $TAG" echo "tag=$TAG" >> $GITHUB_OUTPUT echo "name=$TAG" >> $GITHUB_OUTPUT - name: 🚀 Create GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ steps.tag.outputs.tag }} name: ${{ steps.tag.outputs.name }} prerelease: ${{ inputs.prerelease || false }} draft: false fail_on_unmatched_files: false body: | ## 📖 The Hitchhiker's Guide to Online Anonymity Built from [`${{ github.sha }}`](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}) on `${{ github.ref_name }}`. --- ### 📄 Release assets | File | Description | |------|-------------| | `thgtoa.pdf` | Light mode PDF | | `thgtoa-dark.pdf` | Dark mode PDF (hacker theme) | | `sha256sums.txt` | SHA-256 checksums (both files) | | `b2sums.txt` | BLAKE2b checksums (both files) | | `thgtoa.pdf.sha256` | SHA-256 — light PDF | | `thgtoa-dark.pdf.sha256` | SHA-256 — dark PDF | | `thgtoa.pdf.b2` | BLAKE2b — light PDF | | `thgtoa-dark.pdf.b2` | BLAKE2b — dark PDF | | `*.sig` | GPG detached signatures (ASCII armor) | --- ### #️⃣ Hashes **thgtoa.pdf** (light) ``` SHA-256 ${{ steps.hashes.outputs.light_sha256 }} BLAKE2b ${{ steps.hashes.outputs.light_b2 }} ``` **thgtoa-dark.pdf** (dark) ``` SHA-256 ${{ steps.hashes.outputs.dark_sha256 }} BLAKE2b ${{ steps.hashes.outputs.dark_b2 }} ``` --- ### 🔏 Verifying GPG signatures ```bash # Import the release signing key gpg --import pgp/anonymousplanet-release.asc # Verify PDFs gpg --verify thgtoa.pdf.sig thgtoa.pdf gpg --verify thgtoa-dark.pdf.sig thgtoa-dark.pdf # Verify hash files gpg --verify sha256sums.txt.sig sha256sums.txt gpg --verify b2sums.txt.sig b2sums.txt ``` --- ### 🦠 VirusTotal scans | File | Report | |------|--------| | `thgtoa.pdf` | ${{ steps.vt_urls.outputs.light_vt }} | | `thgtoa-dark.pdf` | ${{ steps.vt_urls.outputs.dark_vt }} | files: | release/thgtoa.pdf release/thgtoa-dark.pdf release/sha256sums.txt release/b2sums.txt release/thgtoa.pdf.sha256 release/thgtoa-dark.pdf.sha256 release/thgtoa.pdf.b2 release/thgtoa-dark.pdf.b2 release/thgtoa.pdf.sig release/thgtoa-dark.pdf.sig release/sha256sums.txt.sig release/b2sums.txt.sig