Skip to content

backmerge.yml is broken after the org migration: RELEASE_PLZ_TOKEN rejected by QAtlasHub PAT-lifetime policy #426

Description

@sotashimozono

What happened

The main → next back-merge did not run on the 0.8.7 promotion.
Run 32567839391 failed at
gh pr create:

GraphQL: The 'QAtlasHub' organization forbids access via a fine-grained personal access
tokens if the token's lifetime is greater than 366 days. Please adjust your token's
lifetime at https://github.com/settings/personal-access-tokens/14727750

.github/workflows/backmerge.yml:38 passes GH_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN }}.
The PAT was minted with a lifetime longer than 366 days, which was fine under the personal
account and is refused by the QAtlasHub org policy. Org-migration fallout, same family
as #392, but a separate secret and a separate fix.

Blast radius — small, and it is not the release path

RELEASE_PLZ_TOKEN appears in exactly one workflow:

$ grep -rn RELEASE_PLZ_TOKEN .github/workflows/
.github/workflows/backmerge.yml:14   # (comment)
.github/workflows/backmerge.yml:38   GH_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN }}

release-plz.yml publishes over OIDC (no token) and uses secrets.GITHUB_TOKEN for
the GitHub Release step, so tagging and publishing are unaffected by this. (They are
blocked by #392 for an unrelated reason.)

Nothing was lost on the 0.8.7 promotion either: git diff next main was empty — only the
merge commit faa3958 was missing from next. Opened by hand as #425.

Fix — pick one

  1. Re-mint the PAT with a lifetime ≤ 366 days and update the RELEASE_PLZ_TOKEN repo
    secret. Smallest change, keeps the current behaviour. Needs re-minting again within a
    year, and this failure mode returns silently when it lapses.
  2. A GitHub App installation token (actions/create-github-app-token). No expiry
    treadmill and org-policy-clean, but it means creating and installing an App.
  3. secrets.GITHUB_TOKEN. Free, but a PR opened with it does not trigger
    workflows, so the back-merge PR would never get the test checks that next requires
    and could not be merged. Not viable as-is.

(1) or (2). I would take (2) if this is meant to keep working unattended.

Worth fixing regardless of which

The job failed with a raw GraphQL error and the notice steps above it never ran, so from
the Actions list it just reads backmerge / failure. An explicit check — or trapping the
gh pr create failure and emitting ::error::back-merge PR could not be opened: <reason>; open it by hand from main → next — would make the next occurrence self-describing instead
of needing a log dive.

Activity

  1. sotashimozono commented on Aug 26, 2026

    @sotashimozono
    MemberAuthor

    The "worth fixing regardless" half is in #532: gh pr create is trapped and its stderr classified, so the PAT-lifetime refusal, an expired token, a missing scope and a no-diff case each emit an actionable ::error:: in the run summary — with a final line saying how far behind next now is, which is the cost the old summary never showed.

    The token itself still needs you, and this issue's own analysis of the options stands:

    1. Re-mint RELEASE_PLZ_TOKEN with a lifetime ≤ 366 days (contents: write, pull-requests: write on QAtlasHub/doiget) and update the repo secret. Smallest change; it returns on expiry — though the failure now says so instead of dumping GraphQL.
    2. A GitHub App installation token (actions/create-github-app-token). No expiry treadmill, org-policy clean; needs an App created and installed.

    This issue recommends (2) if the back-merge is meant to keep working unattended, and I agree — the org refuses PATs over 366 days and every PAT expires, so (1) schedules this failure rather than fixing it. The error text names the App option for that reason.

    Leaving open until the secret is sorted; #532 is Refs, not Closes.

  2. sotashimozono commented on Sep 1, 2026

    @sotashimozono
    MemberAuthor

    Fourth consecutive failure, and this time it blocked the 0.8.13 promotion.

    Run 33485872147, fired by the #580 merge to main at 08:12 UTC today:

    GraphQL: The 'QAtlasHub' organization forbids access via a fine-grained
    personal access tokens if the token's lifetime is greater than 366 days.
    Please adjust your token's lifetime at the following URL:
    https://github.com/settings/personal-access-tokens/14727750 (repository)
    

    Failure history: 2026-08-27, 2026-08-29, and 2026-09-01. Every one is the same cause, so the token has never satisfied the org policy since the migration — this is not an expiry that crept up.

    The back-merge for 0.8.13 was opened by hand as #591. Content-wise it is empty (main is exactly one commit ahead of next — the Merge pull request #580 commit itself, no file differences), so nothing regressed on the beta lane this cycle. That is luck, not design: the cut landed on next before the promotion, so both branches carry 0.8.13. A normal cycle would leave next genuinely behind.

    Worth noting the workflow handles this well — it traps the GraphQL error, classifies it, and prints the remedy rather than dying with a raw stack:

    Re-mint the fine-grained PAT with lifetime <= 366 days (contents + pull-requests: write) and update the RELEASE_PLZ_TOKEN repo secret. To stop this recurring on every expiry, move to a GitHub App installation token (actions/create-github-app-token).

    The diagnosis is not the problem. The token is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions