diff --git a/.github/workflows/desktop-release-candidate.yml b/.github/workflows/desktop-release-candidate.yml index 61ccc800af..9533e0c2a6 100644 --- a/.github/workflows/desktop-release-candidate.yml +++ b/.github/workflows/desktop-release-candidate.yml @@ -3,6 +3,12 @@ name: Desktop Release Candidate on: pull_request: branches: [main] + workflow_dispatch: + inputs: + version: + description: Existing candidate version to validate (version-bump/) + required: true + type: string permissions: contents: read @@ -12,17 +18,38 @@ jobs: validate: name: Desktop Release Candidate runs-on: ubuntu-latest + timeout-minutes: 10 steps: + - name: Authorize manual candidate validation + if: github.event_name == 'workflow_dispatch' + env: + GH_TOKEN: ${{ github.token }} + DISPATCH_REF: ${{ github.ref }} + TRIGGERING_ACTOR: ${{ github.triggering_actor }} + run: | + set -euo pipefail + if [[ "$DISPATCH_REF" != refs/heads/main ]]; then + echo "::error::Dispatch candidate validation from main." + exit 1 + fi + # Re-runs retain the original actor; authorize the re-runner too. + for actor in "$GITHUB_ACTOR" "$TRIGGERING_ACTOR"; do + permission=$(gh api "repos/$GITHUB_REPOSITORY/collaborators/$actor/permission" --jq '.permission') + if [[ "$permission" != admin ]]; then + echo "::error::Manual candidate validation requires repository admin permission." + exit 1 + fi + done - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/heads/version-bump/{0}', inputs.version) || github.event.pull_request.head.sha }} fetch-depth: 0 persist-credentials: false - name: Validate immutable desktop candidate - if: startsWith(github.event.pull_request.head.ref, 'version-bump/') + if: github.event_name == 'workflow_dispatch' || startsWith(github.event.pull_request.head.ref, 'version-bump/') env: GH_TOKEN: ${{ github.token }} - VERSION: ${{ github.event.pull_request.head.ref }} + VERSION: ${{ github.event_name == 'workflow_dispatch' && inputs.version || github.event.pull_request.head.ref }} run: | VERSION="${VERSION#version-bump/}" scripts/desktop_release.py validate --candidate HEAD --version "$VERSION" --repo "$GITHUB_REPOSITORY" diff --git a/RELEASING.md b/RELEASING.md index 4279b80ec3..e50ead2c08 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -51,6 +51,20 @@ or mobile GitHub Release. ### Desktop +Repository admins can manually validate an existing candidate with: + +```sh +gh workflow run desktop-release-candidate.yml --repo block/buzz --ref main -f version=0.5.3 +``` + +This checks out `version-bump/0.5.3` and runs the same immutable-candidate +validator as the PR check. Dispatch from `main`; both the original caller and +anyone rerunning the workflow must currently have repository admin permission. +GitHub allows users with write access to dispatch workflows, but this workflow +fails their manual runs before checkout. Permission lookup failures also stop +the run. Manual validation does not create a candidate, publish a release, or +replace the required checks on the candidate PR. + 1. Run `just release-desktop ` from a clean, up-to-date `main` checkout. The script creates one deterministic candidate commit and records both its frozen base and the verified prior release ledger in candidate metadata.