Skip to content

ci: replace expiring GPR_ACCESS_TOKEN PAT with GITHUB_TOKEN - #1449

Open
Jayanth Reddy Bujula (jbujula) wants to merge 3 commits into
mainfrom
users/jbujula/drop-gpr-pat
Open

Jayanth Reddy Bujula (jbujula) wants to merge 3 commits into
mainfrom
users/jbujula/drop-gpr-pat

Conversation

@jbujula

Copy link
Copy Markdown
Collaborator

Summary

Do not merge until the one-time admin step below is done - this will 401 otherwise.

GPR_ACCESS_TOKEN is a PAT that expires roughly weekly. Each time it lapses, all CI fails restoring @microsoft/powerplatform-cli-wrapper from GitHub Packages:

npm error code E401
npm error 401 Unauthorized - GET https://npm.pkg.github.com/download/@microsoft/powerplatform-cli-wrapper/0.1.135/...
npm error unauthenticated: User cannot be authenticated with the token provided.

It has bitten twice in the last week alone, and is currently red on #1441. The secret was last updated 2026-08-06, consistent with a 7-day expiry.

GITHUB_TOKEN is minted per workflow run and expires with it - nothing to rotate, and no long-lived credential stored in the repo.

Changes

File Change
PullRequest.yml secrets.GPR_ACCESS_TOKEN -> secrets.GITHUB_TOKEN; add permissions: contents: read + packages: read
codeql.yml same swap; add packages: read to the existing permissions block

Adding an explicit permissions: block to PullRequest.yml also drops it from the default (often write-all) token down to least privilege.

Required one-time admin step

GITHUB_TOKEN is scoped to this repo, so the package must grant it read access:

  1. Go to the @microsoft/powerplatform-cli-wrapper package settings
  2. Under Manage Actions access, add microsoft/powerplatform-build-tools with the Read role

This is the mechanism GitHub documents for consuming a package from a different repository. The publishing side already uses GITHUB_TOKEN (see the wrapper's Publish.yml, which runs with permissions: packages: write), so no PAT is involved there either - this just brings the consuming side in line.

Verification

  • Both workflow files parse cleanly, and the resulting job permissions were checked:
    • PullRequest.yml -> {"contents":"read","packages":"read"}
    • codeql.yml -> {"actions":"read","contents":"read","security-events":"write","packages":"read"}
  • CI on this PR is itself the functional test: if the checks go green, GITHUB_TOKEN can restore the package and the PAT is genuinely redundant. If it 401s, the access grant above has not been applied yet - that is expected, not a code problem.

Not covered by this PR

  • dependency-security.yml (in chore: automate dependency security fixes #1441) uses the same PAT. I will apply the identical change there once this approach is confirmed working, to avoid churning that PR twice.
  • The ADO official pipeline (.azure-pipelines/OfficialBuild.yml) authenticates separately via the github.com_npm_tehcrashxor service connection. That is a second credential for the same purpose, named after an individual - worth revisiting separately for bus-factor reasons, but out of scope here.

The GPR_ACCESS_TOKEN secret is a PAT that expires roughly weekly. Every
time it lapses, all CI fails with a 401 restoring
@microsoft/powerplatform-cli-wrapper from GitHub Packages, and someone has
to rotate it by hand.

GITHUB_TOKEN is minted per workflow run and expires with it, so there is
nothing to rotate and no long-lived credential stored in the repo.

Requires a one-time admin action first: grant this repository read access
to the @microsoft/powerplatform-cli-wrapper package under the package's
'Manage Actions access' settings. Until that is done this will 401.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6ac571cd-d84e-4b40-805a-e316a62ed292
@jbujula

Copy link
Copy Markdown
Collaborator Author

CI result confirms the diagnosis - only the access grant is missing

The failure mode changed, which is the useful part:

Token Error
GPR_ACCESS_TOKEN (expired PAT) 401 ... unauthenticated: User cannot be authenticated with the token provided
GITHUB_TOKEN (this PR) 403 ... Permission permission_denied: read_package
npm error code E403
npm error 403 Forbidden - GET https://npm.pkg.github.com/download/@microsoft/powerplatform-cli-wrapper/0.1.135/...
npm error 403 Permission permission_denied: read_package

401 -> 403 means GITHUB_TOKEN authenticated successfully and was recognised; it simply has no read grant on the package. The packages: read permission in this PR is being applied correctly - the missing piece is entirely on the package side.

So the remaining work is the single admin action in the description:

@microsoft/powerplatform-cli-wrapper package -> Manage Actions access -> add microsoft/powerplatform-build-tools with the Read role

Once that is applied, re-run these checks - no code change should be needed. If they go green, GPR_ACCESS_TOKEN can be deleted from the repo secrets and the weekly rotation stops for good.

This PR claimed to remove the expiring PAT but only covered two of the
three workflows that use it. dependency-security.yml, added later by
#1441, was still on GPR_ACCESS_TOKEN:

  .github/workflows/PullRequest.yml:45        (covered)
  .github/workflows/codeql.yml:59             (covered)
  .github/workflows/dependency-security.yml:43  (missed)

That gap is a trap rather than a cosmetic omission: merging this PR and
then deleting the GPR_ACCESS_TOKEN secret -- the whole point of the
change -- would have silently broken the weekly dependency refresh the
next Monday, and only that job would fail.

Applies the same treatment as the other two: job-level `packages: read`
plus GITHUB_TOKEN.

`grep GPR_ACCESS_TOKEN .github/workflows/*.yml` is now empty, so the
secret can be deleted safely once this lands.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6ac571cd-d84e-4b40-805a-e316a62ed292
@jbujula

Copy link
Copy Markdown
Collaborator Author

Pushed 5b1283b — this PR was incomplete, and the gap would have bitten exactly when the change was supposed to pay off.

I originally scoped this to the two workflows I knew about. But three workflows on main use the PAT, not two:

.github/workflows/PullRequest.yml:45          <- covered
.github/workflows/codeql.yml:59               <- covered
.github/workflows/dependency-security.yml:43  <- MISSED

The third arrived later, in #1441, after this PR was opened.

Why that mattered

The point of this PR is to let GPR_ACCESS_TOKEN be deleted. Had it merged as written, deleting the secret would have silently broken the weekly dependency security refresh the following Monday - and only that job, so it would likely have gone unnoticed for a while, on the one workflow whose entire purpose is catching security regressions.

I had deliberately left dependency-security.yml on the PAT earlier, reasoning that switching it before the package grant existed could break it while this PR was still pending. That reasoning only held while the two were separate. Folding it in here makes the swap atomic: all three move together, gated on the same grant.

Change

Same treatment as the other two - job-level packages: read plus secrets.GITHUB_TOKEN.

permissions:
  contents: write
  pull-requests: write
  packages: read          # added

Verification

  • grep GPR_ACCESS_TOKEN .github/workflows/*.yml -> no matches, so the secret is safe to delete once this lands.
  • All three workflows parse, with resolved permissions:
    • dependency-security.yml -> {contents: write, pull-requests: write, packages: read}
    • PullRequest.yml -> {contents: read, packages: read}
    • codeql.yml -> {actions: read, contents: read, security-events: write, packages: read}

Still gated on the package grant

I re-ran CI today after updating this branch. It still fails with:

npm error 403 Forbidden - GET https://npm.pkg.github.com/download/@microsoft/powerplatform-cli-wrapper/0.1.135/...
npm error 403 Permission permission_denied: read_package

That remains the expected result and is still the useful signal: 403, not 401. GITHUB_TOKEN authenticates correctly and is only missing the package-side grant. The remaining step is admin-only:

@microsoft/powerplatform-cli-wrapper package -> Manage Actions access -> add microsoft/powerplatform-build-tools with Read.

Once that is applied, re-run these checks; they should go green and this can merge. Order matters: merge this before deleting the secret, not after.

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