Skip to content

Latest commit

 

History

History
147 lines (117 loc) · 9.09 KB

File metadata and controls

147 lines (117 loc) · 9.09 KB

Select Copilot PAT

Selects a random Copilot PAT from a numbered pool of secrets. This addresses limitations that arise from having a single PAT shared across all agentic workflows, such as rate-limiting.

This is a stop-gap workaround. As soon as organization/enterprise billing is offered for agentic workflows, this approach will be removed from our workflows.

Repository Onboarding

To use Agentic Workflows in a repository:

  1. Follow the instructions for Configuring Your Repository | Agentic Authoring | GitHub Agentic Workflows.
  2. Copy this select-copilot-pat folder into the repository under .github/actions/select-copilot-pat, including both the README.md and action.yml.
  3. Merge those additions into the repository and then follow the instructions for the PAT Creation and Usage below.

Optional: If you plan to manage secrets or workflows from the command line (e.g., gh aw secrets set), install the gh aw CLI extension:

gh extension install github/gh-aw

PAT Management

Team members provide PATs into the pools for the repository by adding them as repository secrets with secret names matching the pattern of <pool_name>_<0-9>, such as COPILOT_PAT_0.

Use this link to prefill the PAT creation form with the required settings:

  1. Resource owner is your user account, not an organization.
  2. Copilot Requests (Read) must be granted.
  3. Repository access set to Public repositories only — or, if the consuming workflow's agent needs to read private repositories, add those repos explicitly.
  4. Any additional read-only permissions the consuming workflow's agent requires (e.g., reading issues or metadata from other repositories) should also be included in the PAT scope. Consult the workflow's documentation for its specific requirements.

The Token Name does not need to match the secret name and is only visible to the owner of the PAT. It's recommended to use a token name indicating the PAT is used for agentic workflows in this repository. The Description is also only used for your own reference.

Team members providing PATs for workflows should set recurring reminders to regenerate and update their PATs in the repository secrets before they expire.

PATs are added to repositories through the Settings > Secrets and variables > Actions UI, saved as Repository secrets and matching the <pool_name>_<0-9> naming convention. This can also be done using the GitHub CLI.

gh aw secrets set "<pool_name>_<0-9>" --value "<your-github-pat>" --repo <owner/repo>

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.

Usage

Add the following frontmatter at the top-level of an agentic workflow. These elements are not supported through imports, so they must be copied into all workflows.

Up to 10 SECRET_# environment variables can be passed to the action, numbered 0-9. Different workflows can use different pools of PATs if desired. Change the secrets.COPILOT_PAT_0 through secrets.COPILOT_PAT_9 secret names in both the select-copilot-pat step env values and in the case expression under the engine: env configuration.

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

    - 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 }}

# Add the pre-activation output of the randomly selected PAT
jobs:
  pre-activation:
    outputs:
      copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }}

# 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
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) }}

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 select-copilot-pat action only references the secret values to determine which values are non-empty, filtering the secret numbers to those with values.
  2. The select-copilot-pat action does not require any permissions. It merely selects a random number from the pool of non-empty secrets and returns the number (not the secret). The consuming workflow uses the returned secret number to provide the corresponding PAT to the agent job.
  3. 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 capability was added to support using a secret with a name different from the default COPILOT_GITHUB_TOKEN.

Each of the references below contributed to the design and implementation to ensure a secure and reliable design.

References