diff --git a/.backportrc.json b/.backportrc.json index e8f9fe059..58c70abd3 100644 --- a/.backportrc.json +++ b/.backportrc.json @@ -15,7 +15,7 @@ "^v9.6.0$": "main", "^v(\\d+).(\\d+).\\d+(?:-(?:alpha|beta|rc)\\d+)?$": "$1.$2" }, - "copySourcePRLabels": "^(?!backport$)(?!v\\d).*$", + "copySourcePRLabels": "^(?!backport(?:-pending)?$)(?!auto-backport$)(?!v\\d).*$", "sourcePRLabels": [ "backport-pending" ] diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index ff2f36f5f..65287d554 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -139,11 +139,13 @@ jobs: steps.backport.outcome == 'success' && contains(github.event.pull_request.labels.*.name, 'auto-backport') env: + # github-actions[bot] token: used to APPROVE the backport PRs (a distinct + # identity from the ephemeral-token author, so the approval counts). GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # 'true' only when the ephemeral token was minted (Token Policy registered), - # i.e. the backport PRs were authored by the ephemeral-token app identity and - # can therefore be approved by github-actions[bot]. - EPHEMERAL_AUTHORED: ${{ steps.ephemeral_token.outputs.token != '' }} + # The ephemeral App token (elastic-vault-github-plugin-prod[bot]) that authored + # the backport PRs, when it was minted (Token Policy registered). Empty on the + # fallback path. Used to ARM auto-merge — see the note below. + EPHEMERAL_TOKEN: ${{ steps.ephemeral_token.outputs.token }} REPO: ${{ github.repository }} run: | # Extract created PR numbers from the backport info log. @@ -153,10 +155,25 @@ jobs: echo "No backport PRs found in log. Skipping approval." exit 0 fi + + # Choose the token that ARMS auto-merge. GitHub attributes a deferred auto-merge + # to whichever identity enabled it, and merges attributed to github-actions[bot] + # (i.e. GITHUB_TOKEN) do NOT trigger further workflows — GitHub's recursion guard. + # If we armed auto-merge with GITHUB_TOKEN, the merge would never fire the + # remove-backport-pending job, so backport-pending would stay stuck on the source + # PR (it had to be cleared by hand). Arming with the ephemeral App identity makes + # the eventual merge trigger that job normally. This is the same reason we don't + # arm auto-merge with GITHUB_TOKEN: events attributed to github-actions[bot] won't + # start this workflow on merge. Falls back to GITHUB_TOKEN when the ephemeral token is + # unavailable (Token Policy not registered) — in that degraded case cleanup still + # needs doing manually, but backports at least open and can be merged by a human. + MERGE_TOKEN="${EPHEMERAL_TOKEN:-$GH_TOKEN}" + for pr in $PR_NUMBERS; do - if [ "$EPHEMERAL_AUTHORED" = "true" ]; then + if [ -n "$EPHEMERAL_TOKEN" ]; then # Authored by the ephemeral-token identity, so this github-actions[bot] - # approval is from a distinct identity and satisfies the required review. + # approval (via the step-level GH_TOKEN) is from a distinct identity and + # satisfies the required review. echo "Approving backport PR #$pr as github-actions[bot]" gh pr review "$pr" --repo "$REPO" --approve \ --body "Automated approval: clean backport of an already-reviewed change. Auto-merge is armed and will merge once the required CI checks are green." || \ @@ -165,12 +182,12 @@ jobs: echo "::warning::Ephemeral token was unavailable (is the backport Token Policy registered in elastic/catalog-info?); #$pr was authored by github-actions[bot], so it cannot be auto-approved and needs a manual approval. Auto-merge is still armed and will merge once approved and CI is green." fi - # Arm auto-merge (squash). This does NOT merge immediately: GitHub merges only - # once every required status check (including buildkite/ml-cpp-pr-builds) is - # green and the review requirement is satisfied. If CI never runs or fails, the - # PR simply stays open — fail-safe. + # Arm auto-merge (squash) as MERGE_TOKEN. This does NOT merge immediately: + # GitHub merges only once every required status check (including + # buildkite/ml-cpp-pr-builds) is green and the review requirement is satisfied. + # If CI never runs or fails, the PR simply stays open — fail-safe. echo "Enabling auto-merge (squash) on backport PR #$pr" - gh pr merge "$pr" --repo "$REPO" --auto --squash || \ + GH_TOKEN="$MERGE_TOKEN" gh pr merge "$pr" --repo "$REPO" --auto --squash || \ echo "::warning::Could not enable auto-merge on #$pr" done