name: Publish server key release on: push: branches: [main] workflow_dispatch: permissions: contents: read concurrency: group: production-key-release cancel-in-progress: false jobs: verify: # Repository Actions variables, not production environment variables: this # job deliberately has no production environment or production secrets. # The workflow/verifier themselves must be protected against modification. if: github.ref == 'refs/heads/main' && vars.ENABLE_WORKER_DEPLOY == 'true' runs-on: ubuntu-latest timeout-minutes: 5 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.sha }} persist-credentials: false - name: Check exact checkout and optional pinned GPG commit signature run: node scripts/verify-commit-signature.mjs env: REQUIRE_GPG_SIGNATURE: ${{ vars.REQUIRE_GPG_SIGNATURE }} GPG_ALLOWED_PRIMARY_FINGERPRINTS: ${{ vars.GPG_ALLOWED_PRIMARY_FINGERPRINTS }} GPG_PUBLIC_KEYS: ${{ vars.GPG_PUBLIC_KEYS }} deploy: needs: verify # Deliberate opt-in prevents accidental deployment when this PR is merged. # Both push and workflow_dispatch must pass the same verification job. if: github.ref == 'refs/heads/main' && vars.ENABLE_WORKER_DEPLOY == 'true' runs-on: ubuntu-latest timeout-minutes: 15 environment: production outputs: attempted: ${{ steps.deploy.outputs.attempted }} deployment_outcome: ${{ steps.deploy.outcome }} verification_outcome: ${{ steps.remote.outcome }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.sha }} persist-credentials: false - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '22' cache: npm - run: npm ci - name: Install shell test interpreters run: | if ! command -v busybox >/dev/null || ! command -v shellcheck >/dev/null || ! command -v gpg >/dev/null; then sudo apt-get update sudo apt-get install -y busybox-static shellcheck gnupg fi busybox sh -c 'echo "BusyBox shell ready"' shellcheck --version gpg --version - run: npm test env: BROWSER_TESTS: '1' - name: Build production release (empty keys fail unless explicitly allowed) run: npm run build - run: node scripts/verify-release.mjs - name: Deploy the validated production bundle id: deploy run: | echo 'attempted=true' >> "$GITHUB_OUTPUT" npx wrangler deploy --config cf-worker/wrangler.toml env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - name: Verify published revision and public key payload id: remote run: node scripts/verify-release.mjs --remote notify: needs: [verify, deploy] # Runs only after Wrangler was attempted, including deployment/remote-check # failure. Gist edits alone do not trigger this workflow or an email. if: always() && needs.verify.result == 'success' && needs.deploy.outputs.attempted == 'true' runs-on: ubuntu-latest timeout-minutes: 3 environment: production steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.sha }} persist-credentials: false - name: Send optional deployment email-provider webhook run: node scripts/notify-deployment.mjs env: ENABLE_MAIL_NOTIFICATION: ${{ vars.ENABLE_MAIL_NOTIFICATION }} MAIL_NOTIFICATION_WEBHOOK: ${{ secrets.MAIL_NOTIFICATION_WEBHOOK }} MAIL_NOTIFICATION_TO: ${{ vars.MAIL_NOTIFICATION_TO }} DEPLOYMENT_STATUS: ${{ needs.deploy.result }} DEPLOYMENT_PHASE: ${{ needs.deploy.outputs.deployment_outcome != 'success' && 'deployment' || needs.deploy.outputs.verification_outcome != 'success' && 'remote-verification' || 'complete' }}