fix: keep tool tokens valid during active long-running jobs #6546
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: backport | |
| # When a PR merged into main carries a "backport release/vX.Y.Z" label, cherry-pick it onto | |
| # the matching release branch and open a PR. The App token (not GITHUB_TOKEN) opens the PR so | |
| # it triggers ci.yml. On conflict it opens a draft PR (conflict markers committed) so nothing | |
| # is silently lost and a human resolves it. | |
| on: | |
| pull_request_target: | |
| # closed: backport labels present at merge time. | |
| # labeled: also catch a backport label added AFTER the PR was already merged (a common | |
| # slip — people forget to label before merging). The `if` below skips still-open | |
| # PRs, so labelling an open PR does nothing until it actually merges. | |
| types: [closed, labeled] | |
| permissions: | |
| contents: read | |
| jobs: | |
| backport: | |
| # Run on merge (closed), or on a backport-* label added afterwards. Ignore unrelated label | |
| # adds so we don't spin up the release bot for every label on a merged PR. | |
| if: >- | |
| github.event.pull_request.merged == true | |
| && github.repository == 'nexu-io/open-design' | |
| && (github.event.action == 'closed' || startsWith(github.event.label.name, 'backport ')) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/create-github-app-token@v2 | |
| id: app | |
| with: | |
| app-id: ${{ secrets.RELEASE_BOT_APP_ID }} | |
| private-key: ${{ secrets.RELEASE_BOT_PRIVATE_KEY }} | |
| - name: Authorize the labeler (labeled events only) | |
| id: authz | |
| # For a backport label added AFTER merge, require the labeler to have write+ permission | |
| # here — don't rely on backport-label-guard.yml winning the race to strip an unauthorized | |
| # label before this job mints the App token and opens the PR. The merge (closed) path is | |
| # already gated by the merger having had write access. Fail closed: any lookup miss skips. | |
| env: | |
| GH_TOKEN: ${{ steps.app.outputs.token }} | |
| REPO: ${{ github.repository }} | |
| ACTION: ${{ github.event.action }} | |
| ACTOR: ${{ github.event.sender.login }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$ACTION" != "labeled" ]; then | |
| echo "ok=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| perm="$(gh api "repos/$REPO/collaborators/$ACTOR/permission" --jq '.permission' 2>/dev/null || echo none)" | |
| case "$perm" in | |
| admin|maintain|write) | |
| echo "ok=true" >> "$GITHUB_OUTPUT" | |
| echo "Authorized labeler: $ACTOR ($perm)";; | |
| *) | |
| echo "ok=false" >> "$GITHUB_OUTPUT" | |
| echo "::warning::$ACTOR ($perm) may not trigger a backport by label; skipping (backport-label-guard removes the label).";; | |
| esac | |
| - uses: actions/checkout@v4 | |
| if: steps.authz.outputs.ok == 'true' | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ steps.app.outputs.token }} | |
| - name: Backport | |
| if: steps.authz.outputs.ok == 'true' | |
| uses: korthout/backport-action@v3 | |
| with: | |
| github_token: ${{ steps.app.outputs.token }} | |
| # A label like "backport release/v0.12.0" -> captures release/v0.12.0 as the target branch. | |
| # Constrained to the release/vX.Y.Z contract so a typo like "backport main" or | |
| # "backport feat/foo" does not match and is ignored (never handed to the release bot). | |
| label_pattern: '^backport (release/v[0-9]+\.[0-9]+\.[0-9]+)$' | |
| merge_commits: skip | |
| pull_title: '[backport ${target_branch}] ${pull_title}' | |
| pull_description: 'Backport of #${pull_number} to `${target_branch}`.\n\n> Clean pick -> merge once CI is green. Conflict -> this is a draft, resolve conflicts then merge.' | |
| # Do not give up on conflicts: commit the conflict markers into the backport branch | |
| # and open a draft PR for a human to resolve. | |
| experimental: '{ "conflict_resolution": "draft_commit_conflicts" }' | |
| # Clean backports are auto-merged after CI passes by backport-automerge.yml | |
| # (triggered by ci.yml completing on the backport-* branch). release/v* has no merge | |
| # queue and no required status check, so GitHub auto-merge / enqueuePullRequest don't | |
| # apply here; that workflow gates on ci.yml's own success instead. |