Skip to content

Restore the Actions bot as the release PR author - #4397

Merged
TaprootFreak merged 1 commit into
developfrom
fix/release-pr-bot-identity
Jul 27, 2026
Merged

Restore the Actions bot as the release PR author#4397
TaprootFreak merged 1 commit into
developfrom
fix/release-pr-bot-identity

Conversation

@TaprootFreak

Copy link
Copy Markdown
Collaborator

Why

Since PR #4380, every release PR (develop -> main) has been authored by a person instead of the
Actions bot. That PR switched the gh pr create step from the workflow's own GITHUB_TOKEN to a
personal access token and lowered the job permission to pull-requests: read.

Two consequences: an automated PR carries a human's name, and the automation depends on one
account's credential lifetime — when that token expires, release PRs stop appearing with no signal.

What

Reverts both lines in auto-release-pr.yaml. The permission must go back to write, since
GITHUB_TOKEN needs it to open a PR (gh pr list in the earlier step is covered by it). The
executable configuration is now identical to its state before #4380; only comments differ.

The guards #4380 removed from api-pr.yaml stay removed — see below.

The cost, documented at the call site

This is a real trade-off and it is written into the workflow rather than quietly taken back. A PR
opened with GITHUB_TOKEN does not start a pull_request workflow run for its opened activity,
so the release PR opens without API PR CI, CodeQL Advanced, PR Review Bot, and API
Migration Check
(for non-seed migration/** changes).

Later pushes to develop do start synchronize runs. So:

  • a release PR merged before any such push gets no pull_request run at all;
  • one that stays open across further merges does get them.

This was measured against the bot-authored release PRs from before the PAT switch, not inferred:

Release PR opened with first pull_request run
merged unchanged GITHUB_TOKEN none, ever
stayed open GITHUB_TOKEN 1h25m after creation, at the next merge (synchronize)
current PAT 4s after creation (opened)

Restoring the head_ref != 'develop' guards in api-pr.yaml would suppress even the synchronize
runs, which are the only release-PR CI left. So they stay as #4380 left them.

Review note

A green release PR does not mean CI ran with main as the target. The checks displayed on it
may come solely from the push runs on develop for the same head commit. This is now stated in the
workflow comment, but it is worth knowing before approving a release.

If the team would rather keep bot authorship and opened-event CI, the way to get both is a GitHub
App token (actions/create-github-app-token) instead of either a PAT or GITHUB_TOKEN. That needs
an app registration plus APP_ID / APP_PRIVATE_KEY secrets, so it is out of scope here.

secrets.RELEASE_PR_TOKEN is no longer referenced anywhere in the tree; the repository secret and
the underlying PAT can be revoked once this lands.

PR #4380 switched the `gh pr create` step in the Auto Release PR workflow from the
workflow's own GITHUB_TOKEN to a personal access token, and lowered the job
permission to `pull-requests: read`. Since then every release PR has carried a
person's name as its author instead of the Actions bot, and the automation has
depended on one account's credential lifetime.

Revert both lines in this workflow. The permission has to go back to `write`
because GITHUB_TOKEN needs it to open a PR; `gh pr list` in the earlier step is
covered by it.

The behavioural cost is documented at the call site rather than silently taken
back: a PR opened with GITHUB_TOKEN does not start a `pull_request` workflow run
for its `opened` activity, so the release PR opens without API PR CI, CodeQL
Advanced, PR Review Bot, and API Migration Check. Later pushes to `develop` do
start `synchronize` runs, so a release PR merged before any such push gets no
`pull_request` run at all, while one that stays open across further merges does.
This was measured on the bot-authored release PRs from before the PAT switch, not
inferred: one merged unchanged had no `pull_request` run, another got its runs
only once a later merge moved the head, and the PAT-created one got them four
seconds after creation.

The practical consequence for reviewers is in the comment too: a green release PR
does not imply CI ran with `main` as the target.

The guards PR #4380 removed from api-pr.yaml stay removed — restoring them would
also suppress the `synchronize` runs, which are the only release-PR CI left.
@TaprootFreak

Copy link
Copy Markdown
Collaborator Author

Pre-review completed in 4 rounds before this PR was opened, two independent reviewers per round
(conformance, and logic/correctness/security), each on its own working copy. All findings concerned
the accuracy of the explanatory comment; the two-line configuration change was unchanged from
round 1.

Round 1 — 1 MEDIUM. The comment claimed that GITHUB_TOKEN-triggered events start no workflow
runs at all. Measuring the repository's own release PRs showed that is too absolute: the opened
activity produces no run, but later pushes to develop produce synchronize runs that do fire.
Rewritten accordingly.

Round 2 — 1 LOW. The list of suppressed workflows omitted API Migration Check, which also
triggers on pull_request — the one that matters most for a release carrying migrations. Added.

Round 3 — 3 LOW. "raises no opened event" overstated the evidence (runs were measured, not
events); "the single-commit case, which is the common one" conflated immediate merge with a single
commit and asserted a frequency that was not verifiable; migration/** ignored that API Migration
Check excludes migration/seed/**. All three tightened.

Round 4 — 0 findings from both reviewers.

Independently confirmed across rounds: the executable configuration is identical to its state before
#4380 (only comments differ); pull-requests: write is the minimum for gh pr create and subsumes
the gh pr list step; contents: read suffices for checkout with fetch-depth: 0 and
git fetch origin main; the four named workflows are exactly the local pull_request triggers; no
RELEASE_PR_TOKEN reference remains in the tree; and no failure mode was found where the workflow
silently stops creating release PRs.

CI: 11/11 green.

@TaprootFreak
TaprootFreak marked this pull request as ready for review July 27, 2026 07:43
@TaprootFreak
TaprootFreak merged commit f6ca9d1 into develop Jul 27, 2026
11 checks passed
@TaprootFreak
TaprootFreak deleted the fix/release-pr-bot-identity branch July 27, 2026 08:03
TaprootFreak added a commit that referenced this pull request Jul 27, 2026
The comment added in #4397 was wrong. It claimed a PR opened with GITHUB_TOKEN
starts no `pull_request` workflow run at all, so the release PR would open with
no CI. Checking the Actions history properly shows something different, and the
practical advice that followed from it was misleading.

What actually happens, verified against run attempt data:

- The runs for the `opened` activity are created, but held. Attempt 1 completes
  as `action_required` with zero jobs, and a manual approval starts attempt 2,
  which is the one that executes. This follows from the repository's Actions
  approval policy (`all_external_contributors`), not from the token as such.
- Only those runs are held. Later `synchronize` runs from human pushes to
  `develop` execute on attempt 1, and the PAT-authored release PRs did too.
- While a release PR sits unapproved, `develop` push runs for the same head
  commit do execute and show up green next to the empty PR run records.

So a freshly opened release PR shows a mix of pending, jobless entries and real
push results. The comment now says that, and tells a reviewer what to do about
it: approve the held runs, then confirm that what they are reading belongs to
the `pull_request` runs for the current head.

Only comments change; the executable configuration is byte-identical.

Two earlier attempts at this note were also wrong, in the opposite direction
each time. The wording is deliberately narrow now: it names the policy rather
than the token, scopes the gate to the `opened` activity, and keeps the
same-head push warning from the original note, which was the one part of it that
was true.
@TaprootFreak

Copy link
Copy Markdown
Collaborator Author

Correction to this PR's description and to the comment it added: the claim that a PR opened with
GITHUB_TOKEN starts no pull_request workflow run is wrong, and the table above is an
artifact of two measurement mistakes. #4403 fixes the comment.

What the table got wrong. Runs were attributed to PRs via a run's pull_requests[] field,
which is resolved at query time and reports currently-open PRs — so old develop runs all appeared
to belong to the newest release PR. Compounding that, a long-lived release PR's head_sha moves as
its base advances, so filtering on the current head missed the runs from when the PR was opened.
The "1h25m later" figure came from those two effects together; the actual gap was 3 seconds.

What is actually true, verified against run attempt data (a run's top-level conclusion
reflects its latest attempt and hides an earlier action_required):

  • The opened runs on a bot-created release PR are created, but held: attempt 1 completes as
    action_required with zero jobs, and a manual approval starts attempt 2, which executes.
    On Release: develop -> main #4399 that was 08:04:32 held → 08:10:37 approved.
  • The cause is this repository's Actions approval policy (all_external_contributors), which gates
    github-actions[bot] — not the token as such.
  • Only the opened runs are held. Later synchronize runs from human pushes to develop execute
    on attempt 1, as did everything on the PAT-authored release PRs.

What this PR got right and the first correction attempt then wrongly dropped: while a release PR
sits unapproved, develop push runs for the same head commit do execute and show green next to the
empty PR run records. That warning is restored in #4403.

The configuration change in this PR — bot identity as the release PR author — is unaffected and
works: #4399 was created by github-actions[bot].

TaprootFreak added a commit that referenced this pull request Jul 27, 2026
The comment added in #4397 was wrong. It claimed a PR opened with GITHUB_TOKEN
starts no `pull_request` workflow run at all, so the release PR would open with
no CI. Checking the Actions history properly shows something different, and the
practical advice that followed from it was misleading.

What actually happens, verified against run attempt data:

- The runs for the `opened` activity are created, but held. Attempt 1 completes
  as `action_required` with zero jobs, and a manual approval starts attempt 2,
  which is the one that executes. This follows from the repository's Actions
  approval policy (`all_external_contributors`), not from the token as such.
- Only those runs are held. Later `synchronize` runs from human pushes to
  `develop` execute on attempt 1, and the PAT-authored release PRs did too.
- While a release PR sits unapproved, `develop` push runs for the same head
  commit do execute and show up green next to the empty PR run records.

So a freshly opened release PR shows a mix of pending, jobless entries and real
push results. The comment now says that, and tells a reviewer what to do about
it: approve the held runs, then confirm that what they are reading belongs to
the `pull_request` runs for the current head.

Only comments change; the executable configuration is byte-identical.

Two earlier attempts at this note were also wrong, in the opposite direction
each time. The wording is deliberately narrow now: it names the policy rather
than the token, scopes the gate to the `opened` activity, and keeps the
same-head push warning from the original note, which was the one part of it that
was true.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant