Skip to content

Migrate Copilot PAT rotation to shared pat_pool import - #743

Merged
JanKrivanek merged 1 commit into
mainfrom
dev/jankrivanek/pat-pool-import
Jun 10, 2026
Merged

Migrate Copilot PAT rotation to shared pat_pool import#743
JanKrivanek merged 1 commit into
mainfrom
dev/jankrivanek/pat-pool-import

Conversation

@JanKrivanek

@JanKrivanek JanKrivanek commented Jun 9, 2026

Copy link
Copy Markdown
Member

What & why

Follow-up to #736 (now merged). Migrates the Copilot PAT rotation from the per-workflow select-copilot-pat action + custom job to the shared workflow import pattern adopted by dotnet/runtime#127946, so the dotnet org repos share one consistent mechanism.

Changes

  • Add .github/workflows/shared/pat_pool.md — a gh aw import that defines a pat_pool job (inline bash, no separate action) exposing a pat_number output, with an import-schema mapping COPILOT_PAT_0..7 to this repo's pool secrets (COPILOT_GITHUB_TOKEN, COPILOT_GITHUB_TOKEN_2..8).
  • Add .github/workflows/shared/pat_pool.README.md — documents the pattern.
  • Convert all 8 agentic workflows to imports: - shared/pat_pool.md + engine.env case(needs.pat_pool.outputs.pat_number ...).
  • Delete .github/actions/select-copilot-pat — the bash now lives inline in the import.
  • Add .github/workflows/validate-pat-pool.yml — a daily standalone workflow that validates each pool PAT with a Copilot CLI request and summarizes pool health (mirrors the runtime PR).

Wiring note (adaptation from runtime)

Consuming workflows declare on.needs: [pat_pool] instead of runtime's needs: [pre_activation] + on.permissions: {} workaround. Reasons:

  1. Ordering / validation: on.needs wires pat_pool ahead of the pre_activation and activation jobs, so the selected PAT is validated by the activation job's secret check and used by the agent. (Relying only on the engine.env reference makes the compiler attach pat_pool after activation, so activation would validate the default token instead of the selected one.)
  2. roles: all compatibility: issue-triage uses roles: all, which produces no pre_activation job — so runtime's on.permissions: {} workaround has nothing to attach to and fails to compile. on.needs: [pat_pool] generates the dependency correctly.

The pat_pool job declares no needs: of its own, so on.needs can pull it in front of pre_activation without a dependency cycle. See shared/pat_pool.README.md → "Design Note" for details.

Validation ✅

Verified end-to-end on this branch with a temporary test-pat-rotation workflow (now removed). A pull_request-triggered run:

  • pat_pool logged Pool size: 3 · Selected PAT number 2 (index: 2) — i.e. it picked a non-default pool token (COPILOT_GITHUB_TOKEN_3).
  • the agent job logged Agent job sees pat_number = '2' — the rotated number reached the agent (the verify step exit 1s if it is empty).

Security review (compilation manifest)

  • Secrets: none added/removed. Same pool already in use (COPILOT_GITHUB_TOKEN, COPILOT_GITHUB_TOKEN_2..8). The pat_pool job reads them only to pick a non-empty number (never the secret value); the secret materializes later via the engine.env case() mapping. Fork PRs receive no secrets. validate-pat-pool.yml reads each PAT only to make a Say OK Copilot probe and never writes it anywhere.
  • Actions: no new third-party actions. The select-copilot-pat local action is removed; its logic is now inline bash in pat_pool.md. validate-pat-pool.yml uses github/gh-aw-actions/setup@v0.77.5 (the same first-party setup action the compiled workflows pin).
  • Redirects/domains: unchanged.

Note

Draft for review. The rotation is validated; the temporary test workflow has been removed. Mark ready when you're happy with it.

Adopt the shared workflow import pattern from dotnet/runtime PR #127946,
replacing the per-workflow select-copilot-pat action + custom job (shipped in
#736) with a reusable shared/pat_pool.md import.

What changed:
- Add .github/workflows/shared/pat_pool.md: an import that defines a `pat_pool`
  job (inline bash, no separate action) exposing a `pat_number` output, plus an
  import-schema mapping COPILOT_PAT_0..7 to this repo's pool secrets
  (COPILOT_GITHUB_TOKEN, COPILOT_GITHUB_TOKEN_2..8).
- Add .github/workflows/shared/pat_pool.README.md documenting the pattern.
- Convert all 8 agentic workflows to `imports: - shared/pat_pool.md` +
  `engine.env` `case(needs.pat_pool.outputs.pat_number ...)`.
- Delete the now-unused .github/actions/select-copilot-pat action.
- Add .github/workflows/validate-pat-pool.yml: a daily standalone workflow that
  validates each pool PAT with a Copilot CLI request and summarizes pool health.

Wiring note (adaptation from runtime): consuming workflows declare
`on.needs: [pat_pool]` instead of runtime's `needs: [pre_activation]` +
`on.permissions: {}`. This wires pat_pool ahead of the pre_activation and
activation jobs so the selected PAT is validated by the activation job and used
by the agent, and it works for `roles: all` workflows (issue-triage), which do
not produce a pre_activation job for the runtime workaround to attach to.

Compiled with gh-aw v0.77.5. Verified end-to-end with a temporary
test-pat-rotation workflow (since removed): a run selected token #2 of the
3-token pool and the agent job observed pat_number='2', confirming the rotated
PAT reaches the agent.
@JanKrivanek
JanKrivanek force-pushed the dev/jankrivanek/pat-pool-import branch from 286d5f5 to 3dfa153 Compare June 9, 2026 19:24
@JanKrivanek
JanKrivanek marked this pull request as ready for review June 10, 2026 08:19
@JanKrivanek
JanKrivanek requested a review from ViktorHofer as a code owner June 10, 2026 08:19
Copilot AI review requested due to automatic review settings June 10, 2026 08:19
@JanKrivanek
JanKrivanek enabled auto-merge (squash) June 10, 2026 08:19
@JanKrivanek
JanKrivanek merged commit 78f3f75 into main Jun 10, 2026
36 checks passed
@JanKrivanek
JanKrivanek deleted the dev/jankrivanek/pat-pool-import branch June 10, 2026 08:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates Copilot PAT rotation across this repo’s agentic workflows from a per-workflow local action/job to a shared gh aw workflow import (shared/pat_pool.md), aligning with the shared pattern used across dotnet org repos. It also adds a scheduled workflow to proactively validate the health of the PAT pool.

Changes:

  • Added a shared workflow import (.github/workflows/shared/pat_pool.md) plus documentation (pat_pool.README.md) to select a random non-empty PAT slot and expose pat_number.
  • Updated agentic workflows to import pat_pool and use needs.pat_pool.outputs.pat_number in engine.env to rotate COPILOT_GITHUB_TOKEN.
  • Removed the local .github/actions/select-copilot-pat action and added a new daily validate-pat-pool.yml workflow to validate each PAT in the pool.
Show a summary per file
File Description
.github/workflows/validate-pat-pool.yml New daily/manual workflow to validate each PAT in the pool via a Copilot CLI probe and produce a summary.
.github/workflows/shared/pat_pool.md New shared import defining the pat_pool job that selects a PAT slot and outputs pat_number.
.github/workflows/shared/pat_pool.README.md New documentation for onboarding, usage, and security/design notes for the shared PAT pool import.
.github/workflows/pr-malicious-scan.agent.md Switched from local select_copilot_pat job to importing shared/pat_pool.md + on.needs: [pat_pool].
.github/workflows/pr-malicious-scan.agent.lock.yml Recompiled lock workflow reflecting the new pat_pool job dependency and token mapping.
.github/workflows/markdown-linter.md Switched to imports: shared/pat_pool.md + on.needs: [pat_pool] and updated engine.env mapping.
.github/workflows/markdown-linter.lock.yml Recompiled lock workflow reflecting pat_pool dependency and updated secret mapping.
.github/workflows/issue-triage.md Switched to importing shared/pat_pool.md and updated engine.env mapping to use needs.pat_pool.
.github/workflows/issue-triage.lock.yml Recompiled lock workflow reflecting pat_pool dependency and updated secret mapping.
.github/workflows/issue-investigate.md Switched to importing shared/pat_pool.md and updated engine.env mapping to use needs.pat_pool.
.github/workflows/issue-investigate.lock.yml Recompiled lock workflow reflecting pat_pool dependency and updated secret mapping.
.github/workflows/devops-health-investigate.md Updated to use imported pat_pool and updated engine.env mapping; added import alongside existing devops imports.
.github/workflows/devops-health-investigate.lock.yml Recompiled lock workflow reflecting pat_pool dependency and updated secret mapping.
.github/workflows/devops-health-groom.md Updated to use imported pat_pool and updated engine.env mapping; added import alongside existing devops imports.
.github/workflows/devops-health-groom.lock.yml Recompiled lock workflow reflecting pat_pool dependency and updated secret mapping.
.github/workflows/devops-health-check.md Updated to use imported pat_pool and updated engine.env mapping; added import alongside existing devops imports.
.github/workflows/devops-health-check.lock.yml Recompiled lock workflow reflecting pat_pool dependency and updated secret mapping.
.github/workflows/close-stale-prs.agent.md Switched to importing shared/pat_pool.md + on.needs: [pat_pool] and updated engine.env mapping.
.github/workflows/close-stale-prs.agent.lock.yml Recompiled lock workflow reflecting pat_pool dependency and updated secret mapping.
.github/actions/select-copilot-pat/README.md Removed (rotation logic now lives in the shared import).
.github/actions/select-copilot-pat/action.yml Removed (rotation logic now lives in the shared import).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 21/21 changed files
  • Comments generated: 4


## Workflow Output Attribution

Team members' PATs are _only_ used for the Copilot requests from within the agentic portion of the workflow. All outputs from the workflow use the `github-actions[bot]` account token. Issues, PRs, comments, and all other content generated by the workflow will be attributed to `github-actions[bot]`--not the team member's account or token.
# Unspecified inputs default to the repository's COPILOT_GITHUB_TOKEN[_#] secrets
```

The secrets passed via `with:` must match the secrets referenced in the consuming workflow's `case` expression that overrides `COPILOT_GITHUB_TOKEN`--both sides need to agree on which secret backs each `COPILOT_PAT_#` slot. Update the `case` expression accordingly:
1. **Secrets adhere to existing trust boundaries.** The pool of PAT secrets is
provided to a dedicated step within the `pat_pool` job. That job runs
before the activation gate and contains only the trusted token-selection
step--no untrusted context or input is within scope. The
Comment on lines +24 to +27
- name: Setup gh-aw scripts
uses: github/gh-aw-actions/setup@v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
JanKrivanek added a commit to dotnet/msbuild that referenced this pull request Jun 10, 2026
Add a Copilot PAT pool so the agentic workflows select a random PAT from a
numbered pool of secrets instead of all sharing a single token, avoiding
rate-limiting. Uses the shared-import pattern from dotnet/runtime#127946 (also
adopted in dotnet/skills#743).

- Add .github/workflows/shared/pat_pool.md: a gh aw import that defines a
  pat_pool job (inline bash, no extra action) exposing a pat_number output,
  with an import-schema mapping COPILOT_PAT_0..7 to the repo's pool secrets
  (COPILOT_GITHUB_TOKEN, COPILOT_GITHUB_TOKEN_2..8).
- Add .github/workflows/shared/pat_pool.README.md documenting the pattern.
- Apply the rotation to all 5 agentic workflows (close-stale-prs,
  flaky-test-detector, flaky-test-fixer, review, review-on-open): each declares
  on.needs:[pat_pool], imports shared/pat_pool.md, and overrides
  engine.env.COPILOT_GITHUB_TOKEN with a case(needs.pat_pool.outputs.pat_number
  ...) expression. on.needs wires pat_pool ahead of the activation gate so the
  selected PAT is validated by the activation job and used by the agent (and it
  works with the roles:-gated review workflows).
- Add .github/workflows/validate-pat-pool.yml: a daily standalone workflow that
  validates each pool PAT via a Copilot CLI probe and summarizes pool health.

Compiled with gh-aw v0.77.5. The mechanism was validated with a temporary
test workflow (removed): a run selected a pool token and the agent job observed
the non-empty pat_number, confirming the rotated PAT reaches the agent.
JanKrivanek added a commit to dotnet/msbuild that referenced this pull request Jun 10, 2026
## Copilot PAT rotation for agentic workflows

Introduces a Copilot **PAT pool** so the agentic workflows select a
random PAT from a numbered pool of secrets instead of all sharing a
single token, avoiding rate-limiting. Uses the shared-import pattern
from
[dotnet/runtime#127946](dotnet/runtime#127946)
(also adopted in
[dotnet/skills#743](dotnet/skills#743)).

### Changes
- **`shared/pat_pool.md`** — a `gh aw` import defining a `pat_pool` job
(inline bash, no extra action) that exposes a `pat_number` output, with
an `import-schema` mapping `COPILOT_PAT_0..7` to this repo's pool
secrets (`COPILOT_GITHUB_TOKEN`, `COPILOT_GITHUB_TOKEN_2..8`).
- **`shared/pat_pool.README.md`** — documents the pattern.
- **All 5 agentic workflows** (`close-stale-prs`, `flaky-test-detector`,
`flaky-test-fixer`, `review`, `review-on-open`) now declare `on.needs:
[pat_pool]`, import `shared/pat_pool.md`, and override
`engine.env.COPILOT_GITHUB_TOKEN` with a
`case(needs.pat_pool.outputs.pat_number ...)` expression. `on.needs`
wires `pat_pool` ahead of the activation gate so the selected PAT is
validated by the activation job and used by the agent (and it works with
the `roles:`-gated review workflows).
- **`validate-pat-pool.yml`** — a daily standalone workflow that
validates each pool PAT via a Copilot CLI probe and summarizes pool
health.

### Notes
- Defines 8 pool slots but only selects from **non-empty** secrets, so
it works today with just `COPILOT_GITHUB_TOKEN` configured and is
forward-compatible as more `COPILOT_GITHUB_TOKEN_#` secrets are added.
- Compiled with gh-aw **v0.77.5**. Action `uses:` lines keep the repo's
existing pins (`actions/checkout` v6.0.3, `gh-aw-actions/setup` v0.78.3)
so the lock diffs show only the PAT-rotation wiring.

### Validation ✅
Validated on this branch with a temporary `test-pat-rotation` workflow
(since removed). A pull_request-triggered run:
- `pat_pool` logged `Pool size: 1 · Selected PAT number 0 (index: 0)`,
- the **agent** job logged `Agent job sees pat_number = '0'` — i.e. the
rotated number reached the agent (the verify step `exit 1`s if it is
empty).

> [!NOTE]
> Draft for review. The rotation is validated end-to-end; the temporary
test workflow has been removed.
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.

3 participants