Fix Copilot PAT rotation for gh-aw v0.77.5 runtime (#736)

* Fix Copilot PAT rotation for gh-aw v0.77.5 runtime

The PAT-rotation stop-gap wired the rotated token into engine.env via needs.pre_activation.outputs.copilot_pat_number. Because the compiled agent job depends only on 'activation' (not the built-in 'pre_activation'), that needs reference evaluated to an empty string in the agent job, so the case() fell through to the default COPILOT_GITHUB_TOKEN and rotation never reached the agent. gh-aw v0.77.5 surfaces this as a compiler warning.

Replace the pre_activation step-injection with a 'select_copilot_pat' custom job wired via on.needs. As a user-defined job referenced in engine.env, the compiler makes it a direct dependency of the agent job, so needs.select_copilot_pat.outputs.copilot_pat_number resolves correctly in both the activation and agent jobs. Same action, same secret pool, same case() expression. Recompiled all workflows with gh-aw v0.77.5.

* Add temporary test-pat-rotation workflow to validate rotation

Non-destructive pull_request-triggered workflow that selects a pool token and asserts, in the agent job, that needs.select_copilot_pat.outputs.copilot_pat_number is non-empty (the exact value that was silently empty with the old pre_activation wiring). To be removed after validation.

* Work around gh-aw v0.77.5 invalid-YAML rendering of top-level if

gh-aw v0.77.5 emits the top-level frontmatter `if:` on the built-in
pre_activation job WITHOUT a ${{ }} wrapper. When the condition starts with
`!` (the fork guards), the emitted `if: !(...)` is invalid YAML (a leading `!`
starts a YAML tag), which GitHub rejects as a workflow-file startup failure.
v0.68.3 wrapped it (valid); v0.77.5 does not. Confirmed independent of the
PAT-rotation change via a minimal probe.

Wrap the fork-guard conditions in parentheses so the emitted scalar starts
with `(` instead of `!` (semantically identical). Affects close-stale-prs,
devops-health-check, devops-health-groom, markdown-linter, pr-malicious-scan.

* Update select-copilot-pat README for the custom-job + on.needs pattern

* Remove temporary test-pat-rotation workflow (rotation validated)
This commit is contained in:
Jan Krivanek
2026-06-09 19:58:25 +02:00
committed by GitHub
parent 7bd6628e91
commit cc0621e2ac
20 changed files with 4047 additions and 1665 deletions
+78 -38
View File
@@ -51,58 +51,97 @@ Up to 10 `SECRET_#` environment variables can be passed to the action, numbered
```yml
on:
# Add the pre-activation step of selecting a random PAT from the supplied secrets
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
# ... your workflow's real triggers go here (schedule, issues, workflow_dispatch, etc.) ...
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression
SECRET_0: ${{ secrets.COPILOT_PAT_0 }}
SECRET_1: ${{ secrets.COPILOT_PAT_1 }}
SECRET_2: ${{ secrets.COPILOT_PAT_2 }}
SECRET_3: ${{ secrets.COPILOT_PAT_3 }}
SECRET_4: ${{ secrets.COPILOT_PAT_4 }}
SECRET_5: ${{ secrets.COPILOT_PAT_5 }}
SECRET_6: ${{ secrets.COPILOT_PAT_6 }}
SECRET_7: ${{ secrets.COPILOT_PAT_7 }}
SECRET_8: ${{ secrets.COPILOT_PAT_8 }}
SECRET_9: ${{ secrets.COPILOT_PAT_9 }}
# Run the `select_copilot_pat` custom job (defined under `jobs:` below) before
# the activation gate, so its `copilot_pat_number` output is available to the
# activation and agent jobs that consume it in `engine: env`.
needs: [select_copilot_pat]
# Add the pre-activation output of the randomly selected PAT
# Custom job that randomly selects one PAT number from the pool of secrets.
# It MUST be a user-defined (non-built-in) job: because it is referenced in
# `engine: env`, the compiler wires it as a *direct* dependency of the agent
# job, so `needs.select_copilot_pat.outputs.*` resolves at runtime in BOTH the
# activation and agent jobs. (Referencing the built-in `pre_activation` job here
# does NOT work: the agent job only depends on `activation`, so
# `needs.pre_activation.*` evaluates to an empty string in the agent job and the
# rotation silently falls back to the default token.)
jobs:
pre-activation:
select_copilot_pat:
runs-on: ubuntu-slim
permissions:
contents: read
# Optional: mirror your workflow's top-level `if:` here so PAT selection is
# gated the same way (e.g. skip scheduled runs on forks). If that condition
# starts with `!`, wrap it in parentheses — see the note after this block.
outputs:
copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
# Override the COPILOT_GITHUB_TOKEN expression used in the activation job
# Consume the PAT number from the pre-activation step and select the corresponding secret
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression
SECRET_0: ${{ secrets.COPILOT_PAT_0 }}
SECRET_1: ${{ secrets.COPILOT_PAT_1 }}
SECRET_2: ${{ secrets.COPILOT_PAT_2 }}
SECRET_3: ${{ secrets.COPILOT_PAT_3 }}
SECRET_4: ${{ secrets.COPILOT_PAT_4 }}
SECRET_5: ${{ secrets.COPILOT_PAT_5 }}
SECRET_6: ${{ secrets.COPILOT_PAT_6 }}
SECRET_7: ${{ secrets.COPILOT_PAT_7 }}
SECRET_8: ${{ secrets.COPILOT_PAT_8 }}
SECRET_9: ${{ secrets.COPILOT_PAT_9 }}
# Override the COPILOT_GITHUB_TOKEN expression used by the Copilot engine.
# Consume the PAT number from the select_copilot_pat job and select the corresponding secret.
engine:
id: copilot
env:
# We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow
# If none of the `COPILOT_PAT_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used
COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_PAT_0, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_PAT_1, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_PAT_2, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_PAT_3, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_PAT_4, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_PAT_5, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_PAT_6, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_PAT_7, needs.pre_activation.outputs.copilot_pat_number == '8', secrets.COPILOT_PAT_8, needs.pre_activation.outputs.copilot_pat_number == '9', secrets.COPILOT_PAT_9, secrets.COPILOT_GITHUB_TOKEN) }}
COPILOT_GITHUB_TOKEN: ${{ case(needs.select_copilot_pat.outputs.copilot_pat_number == '0', secrets.COPILOT_PAT_0, needs.select_copilot_pat.outputs.copilot_pat_number == '1', secrets.COPILOT_PAT_1, needs.select_copilot_pat.outputs.copilot_pat_number == '2', secrets.COPILOT_PAT_2, needs.select_copilot_pat.outputs.copilot_pat_number == '3', secrets.COPILOT_PAT_3, needs.select_copilot_pat.outputs.copilot_pat_number == '4', secrets.COPILOT_PAT_4, needs.select_copilot_pat.outputs.copilot_pat_number == '5', secrets.COPILOT_PAT_5, needs.select_copilot_pat.outputs.copilot_pat_number == '6', secrets.COPILOT_PAT_6, needs.select_copilot_pat.outputs.copilot_pat_number == '7', secrets.COPILOT_PAT_7, needs.select_copilot_pat.outputs.copilot_pat_number == '8', secrets.COPILOT_PAT_8, needs.select_copilot_pat.outputs.copilot_pat_number == '9', secrets.COPILOT_PAT_9, secrets.COPILOT_GITHUB_TOKEN) }}
```
> **Why a custom job and `on.needs` (not `pre_activation`)?** The agent job that
> runs the engine only depends on the built-in `activation` job. GitHub Actions'
> `needs` context exposes **only direct dependencies**, so a
> `needs.pre_activation.*` reference inside `engine: env` evaluates to an empty
> string in the agent job — the `case()` silently falls back to the default
> `COPILOT_GITHUB_TOKEN` and rotation never reaches the agent. Declaring a
> user-defined `select_copilot_pat` job and referencing it in `engine: env`
> makes the compiler add it as a **direct** dependency of the agent job, so the
> value resolves correctly. `on.needs` makes it run before the activation gate.
> **gh-aw note (fork guards / `if:` starting with `!`).** gh-aw renders the
> top-level frontmatter `if:` onto the built-in `pre_activation` job **without** a
> `${{ }}` wrapper. A YAML scalar that starts with `!` is parsed as a tag, so an
> emitted `if: !(...)` is invalid YAML and GitHub rejects the workflow with a
> startup failure. If your top-level `if:` (or the optional `if:` you add to
> `select_copilot_pat`) starts with `!`, wrap it in parentheses so the emitted
> scalar starts with `(`, e.g.
> `if: ${{ (!(github.event_name == 'schedule' && github.event.repository.fork)) }}`.
## Design / Security
There are several details of this implementation that keep our workflows and repositories safe.
1. **Secrets adhere to existing trust boundaries.** The pool of PAT secrets is
provided to the `select-copilot-pat` action within the `pre_activation`
job, which is a deterministic and trusted portion of the workflow. No
untrusted context or input is within scope during this job. The action step
runs within that job, and the secrets do not get passed across contexts. The
provided to the `select-copilot-pat` action within the `select_copilot_pat`
job, which is a deterministic and trusted portion of the workflow (declared
as an `on.needs` dependency so it runs before activation). No untrusted
context or input is within scope during this job, and on fork pull requests
the pool secrets are simply unavailable. The action step runs within that
job, and the secrets do not get passed across contexts. The
`select-copilot-pat` action only references the secret values to determine
which values are non-empty, filtering the secret numbers to those with
values.
@@ -112,10 +151,11 @@ There are several details of this implementation that keep our workflows and rep
returned secret number to provide the corresponding PAT to the agent job.
1. **The implementation uses existing extensibility hooks in Agentic
Workflows.** Everything is supported by `gh aw compile` in this approach,
and no hand-editing of the compiled output is required. The `pre_activation`
job is designed for this type of extensibility, and the
[secret override][secret-override] capability was added to support using a
secret with a name different from the default `COPILOT_GITHUB_TOKEN`.
and no hand-editing of the compiled output is required. Custom jobs,
`on.needs` (which sequences a custom job before the activation gate), and the
[secret override][secret-override] capability (which supports using a secret
with a name different from the default `COPILOT_GITHUB_TOKEN`) are all
first-class features.
Each of the references below contributed to the design and implementation to ensure a secure and reliable design.
-5
View File
@@ -25,11 +25,6 @@
"version": "v7.0.1",
"sha": "043fb46d1a93c77aae656e7c1c64a875d1fc6a0a"
},
"github/gh-aw-actions/setup@v0.68.3": {
"repo": "github/gh-aw-actions/setup",
"version": "v0.68.3",
"sha": "ba90f2186d7ad780ec640f364005fa24e797b360"
},
"github/gh-aw/actions/setup@v0.71.5": {
"repo": "github/gh-aw/actions/setup",
"version": "v0.71.5",
+32 -31
View File
@@ -1,32 +1,33 @@
version: 2
updates:
- package-ecosystem: nuget
directories:
- "/eng/skill-validator/src"
- "/eng/skill-validator/tests"
schedule:
interval: weekly
open-pull-requests-limit: 10
groups:
microsoft-and-system:
patterns:
- "Microsoft.*"
- "System.*"
all-other-nuget:
patterns:
- "*"
exclude-patterns:
- "Microsoft.*"
- "System.*"
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
groups:
github-actions-dependencies:
patterns:
- "*"
exclude-paths:
- "**/*.lock.yml"
- directories:
- /eng/skill-validator/src
- /eng/skill-validator/tests
groups:
all-other-nuget:
exclude-patterns:
- Microsoft.*
- System.*
patterns:
- "*"
microsoft-and-system:
patterns:
- Microsoft.*
- System.*
open-pull-requests-limit: 10
package-ecosystem: nuget
schedule:
interval: weekly
- directory: /
exclude-paths:
- "**/*.lock.yml"
groups:
github-actions-dependencies:
patterns:
- "*"
ignore:
- dependency-name: "github/gh-aw-actions/**" # Managed by gh aw compile. Version-locked to the gh-aw compiler; do not bump.
open-pull-requests-limit: 5
package-ecosystem: github-actions
schedule:
interval: weekly
version: 2
+295 -29
View File
@@ -12,7 +12,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
# This file was automatically generated by pkg/workflow/maintenance_workflow.go (v0.68.3). DO NOT EDIT.
# This file was automatically generated by pkg/workflow/maintenance_workflow.go (v0.77.5). DO NOT EDIT.
#
# To regenerate this workflow, run:
# gh aw compile
@@ -50,8 +50,12 @@ on:
- 'upgrade'
- 'safe_outputs'
- 'create_labels'
- 'activity_report'
- 'close_agentic_workflows_issues'
- 'clean_cache_memories'
- 'update_pull_request_branches'
- 'validate'
- 'forecast'
run_url:
description: 'Run URL or run ID to replay safe outputs from (e.g. https://github.com/owner/repo/actions/runs/12345 or 12345). Required when operation is safe_outputs.'
required: false
@@ -60,7 +64,7 @@ on:
workflow_call:
inputs:
operation:
description: 'Optional maintenance operation to run (disable, enable, update, upgrade, safe_outputs, create_labels, clean_cache_memories, validate)'
description: 'Optional maintenance operation to run (disable, enable, update, upgrade, safe_outputs, create_labels, activity_report, close_agentic_workflows_issues, clean_cache_memories, update_pull_request_branches, validate, forecast)'
required: false
type: string
default: ''
@@ -81,7 +85,7 @@ permissions: {}
jobs:
close-expired-entities:
if: ${{ (!(github.event.repository.fork)) && (github.event_name != 'workflow_dispatch' && github.event_name != 'workflow_call' || inputs.operation == '') }}
if: ${{ (!(github.event.repository.fork)) && github.event_name != 'push' && (github.event_name != 'workflow_dispatch' && github.event_name != 'workflow_call' || inputs.operation == '') }}
runs-on: ubuntu-slim
permissions:
discussions: write
@@ -89,12 +93,12 @@ jobs:
pull-requests: write
steps:
- name: Setup Scripts
uses: github/gh-aw-actions/setup@46d564922b082d0db93244972e8005ea6904ee5f # v0.76.1
uses: github/gh-aw-actions/setup@v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
- name: Close expired discussions
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -103,7 +107,7 @@ jobs:
await main();
- name: Close expired issues
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -112,7 +116,7 @@ jobs:
await main();
- name: Close expired pull requests
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -121,18 +125,18 @@ jobs:
await main();
cleanup-cache-memory:
if: ${{ (!(github.event.repository.fork)) && (github.event_name != 'workflow_dispatch' && github.event_name != 'workflow_call' || inputs.operation == '' || inputs.operation == 'clean_cache_memories') }}
if: ${{ (!(github.event.repository.fork)) && github.event_name != 'push' && (github.event_name != 'workflow_dispatch' && github.event_name != 'workflow_call' || inputs.operation == '' || inputs.operation == 'clean_cache_memories') }}
runs-on: ubuntu-slim
permissions:
actions: write
steps:
- name: Setup Scripts
uses: github/gh-aw-actions/setup@46d564922b082d0db93244972e8005ea6904ee5f # v0.76.1
uses: github/gh-aw-actions/setup@v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
- name: Cleanup outdated cache-memory entries
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -141,7 +145,7 @@ jobs:
await main();
run_operation:
if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation != '' && inputs.operation != 'safe_outputs' && inputs.operation != 'create_labels' && inputs.operation != 'clean_cache_memories' && inputs.operation != 'validate' && (!(github.event.repository.fork)) }}
if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation != '' && inputs.operation != 'safe_outputs' && inputs.operation != 'create_labels' && inputs.operation != 'activity_report' && inputs.operation != 'close_agentic_workflows_issues' && inputs.operation != 'clean_cache_memories' && inputs.operation != 'update_pull_request_branches' && inputs.operation != 'validate' && inputs.operation != 'forecast' && (!(github.event.repository.fork)) }}
runs-on: ubuntu-slim
permissions:
actions: write
@@ -156,12 +160,12 @@ jobs:
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@46d564922b082d0db93244972e8005ea6904ee5f # v0.76.1
uses: github/gh-aw-actions/setup@v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
- name: Check admin/maintainer permissions
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
@@ -171,12 +175,12 @@ jobs:
await main();
- name: Install gh-aw
uses: github/gh-aw-actions/setup-cli@46d564922b082d0db93244972e8005ea6904ee5f # v0.76.1
uses: github/gh-aw-actions/setup-cli@v0.77.5
with:
version: v0.68.3
version: v0.77.5
- name: Run operation
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_AW_OPERATION: ${{ inputs.operation }}
@@ -193,6 +197,40 @@ jobs:
id: record
run: echo "operation=${{ inputs.operation }}" >> "$GITHUB_OUTPUT"
update_pull_request_branches:
if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'update_pull_request_branches' && (!(github.event.repository.fork)) }}
runs-on: ubuntu-slim
permissions:
contents: write
pull-requests: write
steps:
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
- name: Check admin/maintainer permissions
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs');
await main();
- name: Update pull request branches
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/update_pull_request_branches.cjs');
await main();
apply_safe_outputs:
if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'safe_outputs' && (!(github.event.repository.fork)) }}
runs-on: ubuntu-slim
@@ -213,12 +251,12 @@ jobs:
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@46d564922b082d0db93244972e8005ea6904ee5f # v0.76.1
uses: github/gh-aw-actions/setup@v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
- name: Check admin/maintainer permissions
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
@@ -228,7 +266,7 @@ jobs:
await main();
- name: Apply Safe Outputs
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_AW_RUN_URL: ${{ inputs.run_url }}
@@ -257,12 +295,12 @@ jobs:
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@46d564922b082d0db93244972e8005ea6904ee5f # v0.76.1
uses: github/gh-aw-actions/setup@v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
- name: Check admin/maintainer permissions
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
@@ -272,12 +310,12 @@ jobs:
await main();
- name: Install gh-aw
uses: github/gh-aw-actions/setup-cli@46d564922b082d0db93244972e8005ea6904ee5f # v0.76.1
uses: github/gh-aw-actions/setup-cli@v0.77.5
with:
version: v0.68.3
version: v0.77.5
- name: Create missing labels
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_CMD_PREFIX: gh aw
with:
@@ -288,6 +326,234 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/create_labels.cjs');
await main();
activity_report:
if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'activity_report' && (!(github.event.repository.fork)) }}
runs-on: ubuntu-slim
timeout-minutes: 120
permissions:
actions: read
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
- name: Check admin/maintainer permissions
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs');
await main();
- name: Install gh-aw
uses: github/gh-aw-actions/setup-cli@v0.77.5
with:
version: v0.77.5
- name: Restore activity report logs cache
id: activity_report_logs_cache
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ./.cache/gh-aw/activity-report-logs
key: ${{ runner.os }}-activity-report-logs-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-activity-report-logs-${{ github.repository }}-
${{ runner.os }}-activity-report-logs-
- name: Download activity report logs
timeout-minutes: 20
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_AW_CMD_PREFIX: gh aw
run: |
${GH_AW_CMD_PREFIX} logs \
--repo "${{ github.repository }}" \
--start-date -1w \
--count 100 \
--output ./.cache/gh-aw/activity-report-logs \
--format markdown \
> ./.cache/gh-aw/activity-report-logs/report.md
- name: Save activity report logs cache
if: ${{ always() }}
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ./.cache/gh-aw/activity-report-logs
key: ${{ steps.activity_report_logs_cache.outputs.cache-primary-key }}
- name: Generate activity report issue
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('node:fs');
const reportPath = './.cache/gh-aw/activity-report-logs/report.md';
if (!fs.existsSync(reportPath)) {
core.warning('Activity report markdown not found at ' + reportPath + '; skipping issue creation.');
return;
}
let reportBody = '';
try {
reportBody = fs.readFileSync(reportPath, 'utf8').trim();
} catch (error) {
core.warning('Failed to read activity report markdown at ' + reportPath + ': ' + error.message);
return;
}
if (!reportBody) {
core.warning('Activity report markdown is empty at ' + reportPath + '; skipping issue creation.');
return;
}
const repoSlug = context.repo.owner + '/' + context.repo.repo;
const body = [
'### Agentic workflow activity report',
'',
'Repository: ' + repoSlug,
'Generated at: ' + new Date().toISOString(),
'',
reportBody,
].join('\n');
const createdIssue = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '[aw] agentic status report',
body,
labels: ['agentic-workflows'],
});
core.info('Created issue #' + createdIssue.data.number + ': ' + createdIssue.data.html_url);
forecast_report:
if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'forecast' && (!(github.event.repository.fork)) }}
runs-on: ubuntu-slim
timeout-minutes: 60
permissions:
actions: read
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
- name: Check admin/maintainer permissions
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs');
await main();
- name: Install gh-aw
uses: github/gh-aw-actions/setup-cli@v0.77.5
with:
version: v0.77.5
- name: Restore forecast report logs cache
id: forecast_report_logs_cache
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: .github/aw/logs
key: ${{ runner.os }}-forecast-report-logs-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-forecast-report-logs-${{ github.repository }}-
${{ runner.os }}-forecast-report-logs-
- name: Generate forecast report
id: generate_forecast_report
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_AW_CMD_PREFIX: gh aw
run: |
mkdir -p ./.cache/gh-aw/forecast
${GH_AW_CMD_PREFIX} logs --repo "${{ github.repository }}" --start-date -30d --count 1500 > /dev/null
if ! compgen -G ".github/aw/logs/run-*/run_summary.json" > /dev/null; then
echo "::error::Missing run summary cache in .github/aw/logs after gh aw logs warm-up; cannot run forecast."
exit 1
fi
set +e
${GH_AW_CMD_PREFIX} forecast --repo "${{ github.repository }}" --timeout 10 --json 2> >(grep -Fv "forecast is an experimental command and may change without notice" >&2) > ./.cache/gh-aw/forecast/report.json
forecast_exit_code=$?
set -e
if [ "${forecast_exit_code}" -eq 124 ]; then
echo '{"outcome":"timeout","message":"Forecast computation timed out after 10 minutes."}' > ./.cache/gh-aw/forecast/error.json
echo "::error::Forecast computation timed out after 10 minutes."
exit 1
fi
if [ "${forecast_exit_code}" -ne 0 ]; then
echo '{"outcome":"error","message":"Forecast computation failed before producing a report."}' > ./.cache/gh-aw/forecast/error.json
echo "::error::Forecast computation failed with exit code ${forecast_exit_code}."
exit 1
fi
- name: Save forecast report logs cache
if: ${{ always() }}
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: .github/aw/logs
key: ${{ steps.forecast_report_logs_cache.outputs.cache-primary-key }}
- name: Generate forecast issue
if: ${{ always() }}
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
FORECAST_STEP_OUTCOME: ${{ steps.generate_forecast_report.outcome }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/create_forecast_issue.cjs');
await main();
close_agentic_workflows_issues:
if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'close_agentic_workflows_issues' && (!(github.event.repository.fork)) }}
runs-on: ubuntu-slim
permissions:
issues: write
steps:
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
- name: Check admin/maintainer permissions
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs');
await main();
- name: Close no-repro agentic-workflows issues
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/close_agentic_workflows_issues.cjs');
await main();
validate_workflows:
if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'validate' && (!(github.event.repository.fork)) }}
runs-on: ubuntu-latest
@@ -301,12 +567,12 @@ jobs:
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@46d564922b082d0db93244972e8005ea6904ee5f # v0.76.1
uses: github/gh-aw-actions/setup@v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
- name: Check admin/maintainer permissions
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
@@ -316,12 +582,12 @@ jobs:
await main();
- name: Install gh-aw
uses: github/gh-aw-actions/setup-cli@46d564922b082d0db93244972e8005ea6904ee5f # v0.76.1
uses: github/gh-aw-actions/setup-cli@v0.77.5
with:
version: v0.68.3
version: v0.77.5
- name: Validate workflows and file issue on findings
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_CMD_PREFIX: gh aw
with:
File diff suppressed because it is too large Load Diff
+46 -29
View File
@@ -14,49 +14,66 @@ on:
#
# See: /.github/actions/select-copilot-pat/README.md
# ###############################################################
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
#
# Run the `select_copilot_pat` custom job (defined under `jobs:` below)
# before the activation gate so its `copilot_pat_number` output is available
# to the activation and agent jobs that consume it in `engine: env`.
needs: [select_copilot_pat]
# Don't run scheduled triggers on forked repositories — forks lack the
# secrets and context required, and scheduled runs would consume the
# fork owner's minutes.
if: ${{ !(github.event_name == 'schedule' && github.event.repository.fork) }}
if: ${{ (!(github.event_name == 'schedule' && github.event.repository.fork)) }}
# Add the pre-activation output of the randomly selected PAT
# Custom job that randomly selects one PAT number from the pool of secrets.
# It is declared as an `on.needs` dependency above so it runs before the
# activation gate. Because it is a user-defined (non-built-in) job, the compiler
# wires it as a direct dependency of the agent job, so the
# `needs.select_copilot_pat.outputs.*` reference in `engine: env` resolves
# correctly at runtime in BOTH the activation and agent jobs. (A built-in job
# such as `pre_activation` is not a direct dependency of the agent job, so a
# `needs.pre_activation.*` reference there would silently evaluate to an empty
# string — which is the failure mode this approach avoids.)
jobs:
pre-activation:
select_copilot_pat:
runs-on: ubuntu-slim
permissions:
contents: read
if: ${{ !(github.event_name == 'schedule' && github.event.repository.fork) }}
outputs:
copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
# Override the COPILOT_GITHUB_TOKEN expression used in the activation job
# Consume the PAT number from the pre-activation step and select the corresponding secret
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
# Override the COPILOT_GITHUB_TOKEN expression used by the Copilot engine.
# Consume the PAT number from the select_copilot_pat job and select the corresponding secret.
engine:
id: copilot
env:
# We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow
# If none of the `COPILOT_GITHUB_TOKEN_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used
COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
COPILOT_GITHUB_TOKEN: ${{ case(needs.select_copilot_pat.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.select_copilot_pat.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.select_copilot_pat.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.select_copilot_pat.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.select_copilot_pat.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.select_copilot_pat.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.select_copilot_pat.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.select_copilot_pat.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
safe-outputs:
close-pull-request:
File diff suppressed because it is too large Load Diff
+46 -29
View File
@@ -23,49 +23,66 @@ on:
#
# See: /.github/actions/select-copilot-pat/README.md
# ###############################################################
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
#
# Run the `select_copilot_pat` custom job (defined under `jobs:` below)
# before the activation gate so its `copilot_pat_number` output is available
# to the activation and agent jobs that consume it in `engine: env`.
needs: [select_copilot_pat]
# Don't run scheduled triggers on forked repositories — forks lack the
# secrets and context required, and scheduled runs would consume the
# fork owner's minutes.
if: ${{ !(github.event_name == 'schedule' && github.event.repository.fork) }}
if: ${{ (!(github.event_name == 'schedule' && github.event.repository.fork)) }}
# Add the pre-activation output of the randomly selected PAT
# Custom job that randomly selects one PAT number from the pool of secrets.
# It is declared as an `on.needs` dependency above so it runs before the
# activation gate. Because it is a user-defined (non-built-in) job, the compiler
# wires it as a direct dependency of the agent job, so the
# `needs.select_copilot_pat.outputs.*` reference in `engine: env` resolves
# correctly at runtime in BOTH the activation and agent jobs. (A built-in job
# such as `pre_activation` is not a direct dependency of the agent job, so a
# `needs.pre_activation.*` reference there would silently evaluate to an empty
# string — which is the failure mode this approach avoids.)
jobs:
pre-activation:
select_copilot_pat:
runs-on: ubuntu-slim
permissions:
contents: read
if: ${{ !(github.event_name == 'schedule' && github.event.repository.fork) }}
outputs:
copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
# Override the COPILOT_GITHUB_TOKEN expression used in the activation job
# Consume the PAT number from the pre-activation step and select the corresponding secret
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
# Override the COPILOT_GITHUB_TOKEN expression used by the Copilot engine.
# Consume the PAT number from the select_copilot_pat job and select the corresponding secret.
engine:
id: copilot
env:
# We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow
# If none of the `COPILOT_GITHUB_TOKEN_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used
COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
COPILOT_GITHUB_TOKEN: ${{ case(needs.select_copilot_pat.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.select_copilot_pat.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.select_copilot_pat.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.select_copilot_pat.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.select_copilot_pat.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.select_copilot_pat.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.select_copilot_pat.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.select_copilot_pat.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
permissions:
contents: read
File diff suppressed because it is too large Load Diff
+46 -29
View File
@@ -19,49 +19,66 @@ on:
#
# See: /.github/actions/select-copilot-pat/README.md
# ###############################################################
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
#
# Run the `select_copilot_pat` custom job (defined under `jobs:` below)
# before the activation gate so its `copilot_pat_number` output is available
# to the activation and agent jobs that consume it in `engine: env`.
needs: [select_copilot_pat]
# Don't run scheduled triggers on forked repositories — forks lack the
# secrets and context required, and scheduled runs would consume the
# fork owner's minutes.
if: ${{ !(github.event_name == 'schedule' && github.event.repository.fork) }}
if: ${{ (!(github.event_name == 'schedule' && github.event.repository.fork)) }}
# Add the pre-activation output of the randomly selected PAT
# Custom job that randomly selects one PAT number from the pool of secrets.
# It is declared as an `on.needs` dependency above so it runs before the
# activation gate. Because it is a user-defined (non-built-in) job, the compiler
# wires it as a direct dependency of the agent job, so the
# `needs.select_copilot_pat.outputs.*` reference in `engine: env` resolves
# correctly at runtime in BOTH the activation and agent jobs. (A built-in job
# such as `pre_activation` is not a direct dependency of the agent job, so a
# `needs.pre_activation.*` reference there would silently evaluate to an empty
# string — which is the failure mode this approach avoids.)
jobs:
pre-activation:
select_copilot_pat:
runs-on: ubuntu-slim
permissions:
contents: read
if: ${{ !(github.event_name == 'schedule' && github.event.repository.fork) }}
outputs:
copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
# Override the COPILOT_GITHUB_TOKEN expression used in the activation job
# Consume the PAT number from the pre-activation step and select the corresponding secret
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
# Override the COPILOT_GITHUB_TOKEN expression used by the Copilot engine.
# Consume the PAT number from the select_copilot_pat job and select the corresponding secret.
engine:
id: copilot
env:
# We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow
# If none of the `COPILOT_GITHUB_TOKEN_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used
COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
COPILOT_GITHUB_TOKEN: ${{ case(needs.select_copilot_pat.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.select_copilot_pat.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.select_copilot_pat.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.select_copilot_pat.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.select_copilot_pat.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.select_copilot_pat.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.select_copilot_pat.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.select_copilot_pat.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
permissions:
contents: read
File diff suppressed because it is too large Load Diff
+44 -28
View File
@@ -39,47 +39,63 @@ on:
#
# See: /.github/actions/select-copilot-pat/README.md
# ###############################################################
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
#
# Run the `select_copilot_pat` custom job (defined under `jobs:` below)
# before the activation gate so its `copilot_pat_number` output is available
# to the activation and agent jobs that consume it in `engine: env`.
needs: [select_copilot_pat]
concurrency:
group: gh-aw-${{ github.workflow }}-${{ inputs.finding_id }}
# Add the pre-activation output of the randomly selected PAT
# Custom job that randomly selects one PAT number from the pool of secrets.
# It is declared as an `on.needs` dependency above so it runs before the
# activation gate. Because it is a user-defined (non-built-in) job, the compiler
# wires it as a direct dependency of the agent job, so the
# `needs.select_copilot_pat.outputs.*` reference in `engine: env` resolves
# correctly at runtime in BOTH the activation and agent jobs. (A built-in job
# such as `pre_activation` is not a direct dependency of the agent job, so a
# `needs.pre_activation.*` reference there would silently evaluate to an empty
# string — which is the failure mode this approach avoids.)
jobs:
pre-activation:
select_copilot_pat:
runs-on: ubuntu-slim
permissions:
contents: read
outputs:
copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
# Override the COPILOT_GITHUB_TOKEN expression used in the activation job
# Consume the PAT number from the pre-activation step and select the corresponding secret
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
# Override the COPILOT_GITHUB_TOKEN expression used by the Copilot engine.
# Consume the PAT number from the select_copilot_pat job and select the corresponding secret.
engine:
id: copilot
env:
# We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow
# If none of the `COPILOT_GITHUB_TOKEN_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used
COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
COPILOT_GITHUB_TOKEN: ${{ case(needs.select_copilot_pat.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.select_copilot_pat.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.select_copilot_pat.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.select_copilot_pat.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.select_copilot_pat.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.select_copilot_pat.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.select_copilot_pat.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.select_copilot_pat.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
permissions:
contents: read
File diff suppressed because it is too large Load Diff
+47 -25
View File
@@ -19,27 +19,11 @@ on:
#
# See: /.github/actions/select-copilot-pat/README.md
# ###############################################################
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
#
# Run the `select_copilot_pat` custom job (defined under `jobs:` below)
# before the activation gate so its `copilot_pat_number` output is available
# to the activation and agent jobs that consume it in `engine: env`.
needs: [select_copilot_pat]
# Only run when the 'auto-investigate' label is applied
if: ${{ github.event.label.name == 'auto-investigate' }}
@@ -47,17 +31,55 @@ if: ${{ github.event.label.name == 'auto-investigate' }}
concurrency:
group: gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}
# Add the pre-activation output of the randomly selected PAT
# Custom job that randomly selects one PAT number from the pool of secrets.
# It is declared as an `on.needs` dependency above so it runs before the
# activation gate. Because it is a user-defined (non-built-in) job, the compiler
# wires it as a direct dependency of the agent job, so the
# `needs.select_copilot_pat.outputs.*` reference in `engine: env` resolves
# correctly at runtime in BOTH the activation and agent jobs. (A built-in job
# such as `pre_activation` is not a direct dependency of the agent job, so a
# `needs.pre_activation.*` reference there would silently evaluate to an empty
# string — which is the failure mode this approach avoids.)
jobs:
pre-activation:
select_copilot_pat:
runs-on: ubuntu-slim
permissions:
contents: read
if: ${{ github.event.label.name == 'auto-investigate' }}
outputs:
copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
# Override the COPILOT_GITHUB_TOKEN expression used in the activation job
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
# Override the COPILOT_GITHUB_TOKEN expression used by the Copilot engine.
# Consume the PAT number from the select_copilot_pat job and select the corresponding secret.
engine:
id: copilot
env:
COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
# We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow
# If none of the `COPILOT_GITHUB_TOKEN_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used
COPILOT_GITHUB_TOKEN: ${{ case(needs.select_copilot_pat.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.select_copilot_pat.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.select_copilot_pat.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.select_copilot_pat.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.select_copilot_pat.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.select_copilot_pat.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.select_copilot_pat.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.select_copilot_pat.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
permissions:
contents: read
+401 -164
View File
File diff suppressed because it is too large Load Diff
+46 -25
View File
@@ -30,42 +30,63 @@ on:
#
# See: /.github/actions/select-copilot-pat/README.md
# ###############################################################
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
#
# Run the `select_copilot_pat` custom job (defined under `jobs:` below)
# before the activation gate so its `copilot_pat_number` output is available
# to the activation and agent jobs that consume it in `engine: env`.
needs: [select_copilot_pat]
concurrency:
group: gh-aw-${{ github.workflow }}-${{ github.event.issue.number || inputs.issue_number }}
# Add the pre-activation output of the randomly selected PAT
# Custom job that randomly selects one PAT number from the pool of secrets.
# It is declared as an `on.needs` dependency above so it runs before the
# activation gate. Because it is a user-defined (non-built-in) job, the compiler
# wires it as a direct dependency of the agent job, so the
# `needs.select_copilot_pat.outputs.*` reference in `engine: env` resolves
# correctly at runtime in BOTH the activation and agent jobs. (A built-in job
# such as `pre_activation` is not a direct dependency of the agent job, so a
# `needs.pre_activation.*` reference there would silently evaluate to an empty
# string — which is the failure mode this approach avoids.)
jobs:
pre-activation:
select_copilot_pat:
runs-on: ubuntu-slim
permissions:
contents: read
outputs:
copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
# Override the COPILOT_GITHUB_TOKEN expression used in the activation job
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
# Override the COPILOT_GITHUB_TOKEN expression used by the Copilot engine.
# Consume the PAT number from the select_copilot_pat job and select the corresponding secret.
engine:
id: copilot
env:
COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
# We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow
# If none of the `COPILOT_GITHUB_TOKEN_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used
COPILOT_GITHUB_TOKEN: ${{ case(needs.select_copilot_pat.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.select_copilot_pat.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.select_copilot_pat.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.select_copilot_pat.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.select_copilot_pat.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.select_copilot_pat.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.select_copilot_pat.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.select_copilot_pat.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
permissions:
contents: read
File diff suppressed because it is too large Load Diff
+48 -26
View File
@@ -18,38 +18,57 @@ on:
#
# See: /.github/actions/select-copilot-pat/README.md
# ###############################################################
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
#
# Run the `select_copilot_pat` custom job (defined under `jobs:` below)
# before the activation gate so its `copilot_pat_number` output is available
# to the activation and agent jobs that consume it in `engine: env`.
needs: [select_copilot_pat]
# Don't run scheduled triggers on forked repositories — forks lack the
# secrets and context required, and scheduled runs would consume the
# fork owner's minutes.
if: ${{ !(github.event_name == 'schedule' && github.event.repository.fork) }}
if: ${{ (!(github.event_name == 'schedule' && github.event.repository.fork)) }}
# Add the pre-activation output of the randomly selected PAT
# Custom job that randomly selects one PAT number from the pool of secrets.
# It is declared as an `on.needs` dependency above so it runs before the
# activation gate. Because it is a user-defined (non-built-in) job, the compiler
# wires it as a direct dependency of the agent job, so the
# `needs.select_copilot_pat.outputs.*` reference in `engine: env` resolves
# correctly at runtime in BOTH the activation and agent jobs. (A built-in job
# such as `pre_activation` is not a direct dependency of the agent job, so a
# `needs.pre_activation.*` reference there would silently evaluate to an empty
# string — which is the failure mode this approach avoids.)
jobs:
pre-activation:
select_copilot_pat:
runs-on: ubuntu-slim
permissions:
contents: read
if: ${{ !(github.event_name == 'schedule' && github.event.repository.fork) }}
outputs:
copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
super_linter:
runs-on: ubuntu-latest
@@ -97,11 +116,14 @@ jobs:
path: super-linter.log
retention-days: 7
# Override the COPILOT_GITHUB_TOKEN expression used in the activation job
# Override the COPILOT_GITHUB_TOKEN expression used by the Copilot engine.
# Consume the PAT number from the select_copilot_pat job and select the corresponding secret.
engine:
id: copilot
env:
COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
# We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow
# If none of the `COPILOT_GITHUB_TOKEN_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used
COPILOT_GITHUB_TOKEN: ${{ case(needs.select_copilot_pat.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.select_copilot_pat.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.select_copilot_pat.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.select_copilot_pat.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.select_copilot_pat.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.select_copilot_pat.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.select_copilot_pat.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.select_copilot_pat.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
permissions:
contents: read
File diff suppressed because it is too large Load Diff
+48 -24
View File
@@ -26,45 +26,69 @@ on:
#
# See: /.github/actions/select-copilot-pat/README.md
# ###############################################################
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
#
# Run the `select_copilot_pat` custom job (defined under `jobs:` below)
# before the activation gate so its `copilot_pat_number` output is available
# to the activation and agent jobs that consume it in `engine: env`.
needs: [select_copilot_pat]
# Skip on forks (no secrets, no point). Drafts are filtered out by the
# orchestrator before dispatch.
if: ${{ !github.event.repository.fork }}
if: ${{ (!github.event.repository.fork) }}
concurrency:
group: gh-aw-${{ github.workflow }}-${{ inputs.pr_number }}
cancel-in-progress: true
# Custom job that randomly selects one PAT number from the pool of secrets.
# It is declared as an `on.needs` dependency above so it runs before the
# activation gate. Because it is a user-defined (non-built-in) job, the compiler
# wires it as a direct dependency of the agent job, so the
# `needs.select_copilot_pat.outputs.*` reference in `engine: env` resolves
# correctly at runtime in BOTH the activation and agent jobs. (A built-in job
# such as `pre_activation` is not a direct dependency of the agent job, so a
# `needs.pre_activation.*` reference there would silently evaluate to an empty
# string — which is the failure mode this approach avoids.)
jobs:
pre-activation:
select_copilot_pat:
runs-on: ubuntu-slim
permissions:
contents: read
if: ${{ !github.event.repository.fork }}
outputs:
copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
name: Checkout the select-copilot-pat action folder
with:
persist-credentials: false
sparse-checkout: .github/actions/select-copilot-pat
sparse-checkout-cone-mode: true
fetch-depth: 1
- id: select-copilot-pat
name: Select Copilot token from pool
uses: ./.github/actions/select-copilot-pat
env:
# If the secret names are changed here, they must also be changed
# in the `engine: env` case expression below
SECRET_0: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_1: ${{ secrets.COPILOT_GITHUB_TOKEN_2 }}
SECRET_2: ${{ secrets.COPILOT_GITHUB_TOKEN_3 }}
SECRET_3: ${{ secrets.COPILOT_GITHUB_TOKEN_4 }}
SECRET_4: ${{ secrets.COPILOT_GITHUB_TOKEN_5 }}
SECRET_5: ${{ secrets.COPILOT_GITHUB_TOKEN_6 }}
SECRET_6: ${{ secrets.COPILOT_GITHUB_TOKEN_7 }}
SECRET_7: ${{ secrets.COPILOT_GITHUB_TOKEN_8 }}
# Override the COPILOT_GITHUB_TOKEN expression used by the Copilot engine.
# Consume the PAT number from the select_copilot_pat job and select the corresponding secret.
engine:
id: copilot
env:
COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
# We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow
# If none of the `COPILOT_GITHUB_TOKEN_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used
COPILOT_GITHUB_TOKEN: ${{ case(needs.select_copilot_pat.outputs.copilot_pat_number == '0', secrets.COPILOT_GITHUB_TOKEN, needs.select_copilot_pat.outputs.copilot_pat_number == '1', secrets.COPILOT_GITHUB_TOKEN_2, needs.select_copilot_pat.outputs.copilot_pat_number == '2', secrets.COPILOT_GITHUB_TOKEN_3, needs.select_copilot_pat.outputs.copilot_pat_number == '3', secrets.COPILOT_GITHUB_TOKEN_4, needs.select_copilot_pat.outputs.copilot_pat_number == '4', secrets.COPILOT_GITHUB_TOKEN_5, needs.select_copilot_pat.outputs.copilot_pat_number == '5', secrets.COPILOT_GITHUB_TOKEN_6, needs.select_copilot_pat.outputs.copilot_pat_number == '6', secrets.COPILOT_GITHUB_TOKEN_7, needs.select_copilot_pat.outputs.copilot_pat_number == '7', secrets.COPILOT_GITHUB_TOKEN_8, secrets.COPILOT_GITHUB_TOKEN) }}
permissions:
contents: read