From afcf25ac895d396c645c1c08861213b0a0421112 Mon Sep 17 00:00:00 2001 From: RJ Hollberg Date: Sun, 13 Sep 2026 06:46:10 -0600 Subject: [PATCH] fix: remove COPILOT_PAT, use the native copilot-requests: write permission instead Copilot CLI in GitHub Actions no longer needs a personal access token: a workflow just needs the copilot-requests: write permission and authenticates with its own built-in GITHUB_TOKEN. draft-release.yml now declares that permission and no longer passes copilot-pat at all. Removes the whole PAT lifecycle this repo used to manage: the CopilotToken prompt and COPILOT_PAT secret-set in New-Repo.ps1, and every doc/skill reference to creating, storing, or reading it. Caveat carried into the docs: the billing story for this native flow is described in terms of organization-owned repos (a Copilot policy toggle). Whether the same free path applies identically to a personal-account repo is not yet confirmed by a real run. --- .claude/skills/release/SKILL.md | 6 +++--- .github/workflows/draft-release.yml | 2 +- docs/ReleaseProcess.md | 31 +++++++++++++---------------- scripts/New-Repo.ps1 | 22 ++++---------------- scripts/README.md | 4 ++-- 5 files changed, 24 insertions(+), 41 deletions(-) diff --git a/.claude/skills/release/SKILL.md b/.claude/skills/release/SKILL.md index b2129f9..5b1f26c 100644 --- a/.claude/skills/release/SKILL.md +++ b/.claude/skills/release/SKILL.md @@ -44,9 +44,9 @@ Re-running replaces the draft for that version rather than adding a second, so a failed or wrong attempt costs nothing. If the notes open with an HTML comment instead of a paragraph, the summary -model was unavailable — `COPILOT_PAT` missing or expired, or the service -down. The draft is still good: write the paragraph by hand at review, or -delete the draft and re-run later. +model was unavailable — the account's Copilot entitlement, or the service +itself, down. The draft is still good: write the paragraph by hand at +review, or delete the draft and re-run later. ## Review diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index 29718bd..f8a1108 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -32,6 +32,7 @@ jobs: permissions: contents: write # Needed to create the release actions: read # Needed to read artifacts from the CI run + copilot-requests: write # Needed for the release-notes summary steps: - name: Checkout repo @@ -43,4 +44,3 @@ jobs: uses: TaffarelJr/.actions/draft-release@v1 with: version: ${{ inputs.version }} - copilot-pat: ${{ secrets.COPILOT_PAT }} diff --git a/docs/ReleaseProcess.md b/docs/ReleaseProcess.md index 062e1f4..426665f 100644 --- a/docs/ReleaseProcess.md +++ b/docs/ReleaseProcess.md @@ -16,7 +16,7 @@ how binaries are built, and how a release is cut and published. - [3. Publish](#3-publish) - [Release Notes vs. Changelog](#release-notes-vs-changelog) - [Writing the Summary](#writing-the-summary) - - [Getting the token](#getting-the-token) + - [Authentication](#authentication) - [What Each Layer Owns](#what-each-layer-owns) ## Principles @@ -266,9 +266,10 @@ which changes the history it is trying to describe. ### Writing the Summary The workflow always asks a model to draft the opening paragraph -from the generated changelog, using the `COPILOT_PAT` secret. +from the generated changelog, using the workflow's own `copilot-requests: write` +permission — no token to create or store. -It is never required. A missing or expired token, a service outage, +It is never required. A missing permission, a service outage, a network error — all land in the same place: the summary stays a placeholder and the release is still drafted. A missing paragraph is not worth failing a release over. @@ -278,23 +279,20 @@ simply has no opening paragraph, rather than a visible `TODO`. Replace the whole comment with a paragraph or two to fill it in, or delete the draft and re-run once the service is back. -#### Getting the token +#### Authentication The summary runs through the [`actions/ai-inference`][aiAction] action, which drives the Copilot CLI. -That authenticates an *account* holding a Copilot entitlement, -so it needs a personal access token — the built-in `GITHUB_TOKEN` will not do. +As of the built-in `GITHUB_TOKEN` support GitHub added for Actions, +that needs nothing beyond the `copilot-requests: write` permission +already declared on `draft-release.yml` — there is no secret to create, +store, or rotate. -1. `Settings` → `Developer settings` → `Personal access tokens` -2. Generate a **fine-grained** token with no repository access, - because it authenticates the account rather than a repo -3. [Add it as the `COPILOT_PAT` secret][actionsSecrets] - -A personal account cannot share an Actions secret across repos — -that is an organization feature — so the secret is per-repo. -`New-Repo.ps1` sets it when creating a repo, -reading the value from the `COPILOT_PAT` environment variable -so there is nothing to paste in. +This still depends on the repo's owner having an active Copilot +entitlement. On an organization-owned repo, that also needs the +"Allow use of Copilot CLI billed to the organization" policy enabled; +the equivalent for a personal-account repo has not been exercised here +yet, so treat that combination as unverified until a real run confirms it. ## What Each Layer Owns @@ -331,7 +329,6 @@ Everything else works without modification. [actionsRepo]: https://github.com/TaffarelJr/.actions -[actionsSecrets]: https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions [aiAction]: https://github.com/actions/ai-inference diff --git a/scripts/New-Repo.ps1 b/scripts/New-Repo.ps1 index a54687a..7d43b29 100644 --- a/scripts/New-Repo.ps1 +++ b/scripts/New-Repo.ps1 @@ -31,10 +31,10 @@ Every value is prompted for - there are no command-line parameters to supply instead, so a template layer can always add its own prompt but can - never add a parameter to this inherited script. The three secret tokens + never add a parameter to this inherited script. The two secret tokens are the one exception: each is read from its environment variable first - (CODECOV_TOKEN, COPILOT_PAT, TEMPLATE_SYNC_PAT), so setting one up is a - one-time task rather than something typed in on every run. + (CODECOV_TOKEN, TEMPLATE_SYNC_PAT), so setting one up is a one-time task + rather than something typed in on every run. Idempotent & resumable: re-running verifies what's already done and only fills gaps. It never overwrites post-scaffold changes. @@ -42,7 +42,7 @@ .EXAMPLE ./scripts/New-Repo.ps1 Prompts for everything - Kind, Name, Visibility, Description, Homepage, - Topics, and the three tokens (skipped for any already set as an + Topics, and the two tokens (skipped for any already set as an environment variable). #> @@ -155,13 +155,6 @@ try { -Hint "Codecov token at https://app.codecov.io/account/gh/$owner/org-upload-token" ` -Secret - $CopilotToken = Resolve-Input -Name CopilotToken ` - -Prompt 'COPILOT_PAT value (blank to skip)' ` - -EnvVar 'COPILOT_PAT' ` - -Hint 'Copilot PAT at https://github.com/settings/personal-access-tokens', ` - 'Drafts the release-notes summary; without it the notes get a placeholder' ` - -Secret - $TemplateSyncToken = Resolve-Input -Name TemplateSyncToken ` -Prompt 'TEMPLATE_SYNC_PAT value (blank to skip)' ` -EnvVar 'TEMPLATE_SYNC_PAT' ` @@ -204,13 +197,6 @@ try { Set-RepoVariable -OwnerRepo $ownerRepo -Name TEMPLATE_SYNC_STRATEGY ` -Value $(if ($Kind -eq 'Code') { 'merge' } else { 'rebase' }) - if ($CopilotToken) { - Set-RepoSecret -OwnerRepo $ownerRepo -Name COPILOT_PAT -Token $CopilotToken - } - else { - Write-Skip 'COPILOT_PAT not provided - release summaries stay manual' - } - # Sync still runs without this, but a PR opened with the default token cannot # trigger CI, so a required status check would never report and the PR would # never become mergeable. diff --git a/scripts/README.md b/scripts/README.md index f85127d..b952fc1 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -29,9 +29,9 @@ with a default where one makes sense (press ENTER to take it), and a confirmation before anything is created. A bad answer is explained and asked again. -The one exception is the three secret tokens. +The one exception is the two secret tokens. Each is read from the **environment variable of the same name** first — -`CODECOV_TOKEN`, `COPILOT_PAT`, `TEMPLATE_SYNC_PAT` — +`CODECOV_TOKEN`, `TEMPLATE_SYNC_PAT` — and only prompted for when that is unset. Set them once as user environment variables and they are never asked for again. Leave one blank to skip it; the run says what that costs.