name: CI - Merge Queue # Runs when a PR is queued to merge. GitHub builds the merge candidate on top of # the current tip of main, so these checks validate against main's real state at # merge time rather than the PR's (possibly stale) base. This is what closes the # upgrade-command base-drift race: a command generated against an old version, # then left behind when main bumps, is caught here even if the PR-level guard # passed on a stale base. on: merge_group: permissions: contents: read pull-requests: read jobs: # merge_group carries no PR labels, so resolve them from the queued PR (its # number is in the merge-queue ref) and pass the version-mutation bypass to the # guard as an input, which skips only the version-directory step. The job # always runs and reports a real success/failure, so the required check never # resolves to a skipped state and a label-lookup failure fails closed. The # timestamp / append-only check has no bypass and always runs: violating it # rewinds the upgrade cursor. upgrade-mutation-guard: timeout-minutes: 5 runs-on: ubuntu-latest steps: - name: Checkout merge candidate uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 2 - name: Resolve version-mutation bypass label from the queued PR id: labels env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} HEAD_REF: ${{ github.event.merge_group.head_ref }} run: | set -euo pipefail PR_NUMBER=$(echo "$HEAD_REF" | sed -n -E 's|.*/pr-([0-9]+)-[0-9a-f]+$|\1|p') skip=false if [ -n "$PR_NUMBER" ]; then LABELS=$(gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --json labels --jq '.labels[].name') echo "Queued PR #$PR_NUMBER labels:" echo "$LABELS" if echo "$LABELS" | grep -qxF 'ci:allow-previous-version-upgrade-mutation'; then skip=true fi else echo "Could not parse a PR number from '$HEAD_REF'; enforcing strictly." fi echo "skip=$skip" >> "$GITHUB_OUTPUT" - name: Validate upgrade command mutations against main uses: ./.github/actions/upgrade-mutation-guard with: base_sha: ${{ github.event.merge_group.base_sha }} allow_previous_version_mutation: ${{ steps.labels.outputs.skip }}