Summary
When the Sync backport changelog to main workflow fails after pushing the working branch but before opening the PR (e.g. a transient gh pr create error), there is currently no way to retry without pushing a new commit to the backport branch. Add a /sync-changelog comment command on the originating backport PR to re-trigger the workflow and create the sync PR targeting main.
Background
The existing workflow (sync-backport-changelog.yml) triggers on push to backport-* branches. When gh pr create fails after the working branch (changelog/pr-<N>) has already been pushed, the failure comment includes a compare link but the user must push a dummy commit to re-trigger — there is no self-service retry path.
Deliverables
sync-backport-changelog.yml
Add issue_comment: types: [created] to the on: block and a new retry-sync job:
Trigger condition (job-level if):
- Comment is on a PR (
github.event.issue.pull_request != null)
- Comment body contains
/sync-changelog
- Actor has
write or admin permission on the repository (see Security below)
Behaviour:
- Verify the commenting actor has write permission — abort if not (see Security below)
- Fetch the PR's
merge_commit_sha via the GitHub API; exit silently if the PR is not merged
- Derive
before as the first parent of the merge commit (parents[0].sha)
- Check out the repository at full depth (
fetch-depth: 0)
- Run the same
collect → setup-go → mage → create → comment steps as the existing sync-changelog job, passing github.event.issue.number directly as the backport PR number
backport_create_sync_pr.py
Change the git push call to use --force-with-lease so that a pre-existing working branch (left over from the previous failed attempt) is overwritten cleanly:
# before
_git("push", "origin", working_branch)
# after
_git("push", "--force-with-lease", "origin", working_branch)
backport_collect_entries.py
No changes required. The existing _sync_pr_exists check (which uses --state all) correctly returns False when the working branch was pushed but no PR was created, allowing the retry to proceed.
Security
The issue_comment event runs in the default-branch context with contents: write and pull-requests: write. On a public repository, any GitHub user can post a comment, so the existing guards (PR comment / PR merged / base is main) are not sufficient — an attacker could craft a comment that passes all of them and trigger the workflow with arbitrary inputs.
The retry-sync job must check the commenting actor's permission as its first step, before any other work:
- name: Check actor write permission
uses: actions/github-script@v7
with:
script: |
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: context.actor,
});
if (!['write', 'admin'].includes(data.permission)) {
core.setFailed(`@${context.actor} does not have write access`);
}
context.actor is the person who posted the comment, which is the correct principal to check. A job-level if on github.event.comment.user.login == 'github-actions[bot]' is not a substitute: it would match the bot's own comments, not the collaborator performing the retry.
Note: this same pattern is required for any issue_comment-triggered workflow that carries write permissions. See also the discussion in #19214.
Acceptance criteria
Related
Summary
When the
Sync backport changelog to mainworkflow fails after pushing the working branch but before opening the PR (e.g. a transientgh pr createerror), there is currently no way to retry without pushing a new commit to the backport branch. Add a/sync-changelogcomment command on the originating backport PR to re-trigger the workflow and create the sync PR targetingmain.Background
The existing workflow (
sync-backport-changelog.yml) triggers onpushtobackport-*branches. Whengh pr createfails after the working branch (changelog/pr-<N>) has already been pushed, the failure comment includes a compare link but the user must push a dummy commit to re-trigger — there is no self-service retry path.Deliverables
sync-backport-changelog.ymlAdd
issue_comment: types: [created]to theon:block and a newretry-syncjob:Trigger condition (job-level
if):github.event.issue.pull_request != null)/sync-changelogwriteoradminpermission on the repository (see Security below)Behaviour:
merge_commit_shavia the GitHub API; exit silently if the PR is not mergedbeforeas the first parent of the merge commit (parents[0].sha)fetch-depth: 0)collect → setup-go → mage → create → commentsteps as the existingsync-changelogjob, passinggithub.event.issue.numberdirectly as the backport PR numberbackport_create_sync_pr.pyChange the
git pushcall to use--force-with-leaseso that a pre-existing working branch (left over from the previous failed attempt) is overwritten cleanly:backport_collect_entries.pyNo changes required. The existing
_sync_pr_existscheck (which uses--state all) correctly returnsFalsewhen the working branch was pushed but no PR was created, allowing the retry to proceed.Security
The
issue_commentevent runs in the default-branch context withcontents: writeandpull-requests: write. On a public repository, any GitHub user can post a comment, so the existing guards (PR comment / PR merged / base ismain) are not sufficient — an attacker could craft a comment that passes all of them and trigger the workflow with arbitrary inputs.The
retry-syncjob must check the commenting actor's permission as its first step, before any other work:context.actoris the person who posted the comment, which is the correct principal to check. A job-levelifongithub.event.comment.user.login == 'github-actions[bot]'is not a substitute: it would match the bot's own comments, not the collaborator performing the retry.Acceptance criteria
/sync-changelogon a merged backport PR triggers the retry workflowmainand posts a success comment with the PR URLskippedcommentgit push --force-with-leaseis used so a pre-existing working branch does not block the retryRelated
sync-backport-changelogworkflow this builds onissue_commentsecurity pattern (actor permission check)