e2e: scope copilot GitHub token to the copilot-cli agent only · Entire
e2e: scope copilot GitHub token to the copilot-cli agent only
eb32a04→main·
Soph·2w ago·3 files·+31 added/-7 removed
The E2E workflows that run agents in a shared/single job were handing the copilot GitHub token to every agent. A third-party agent CLI (opencode, gemini-cli, cursor-cli, factoryai-droid, codex) would receive a usable GitHub token in its process environment — credentials it has no need for.
Fix, without reverting the single-matrix design:
- e2e.yml, e2e-checkpoint-store.yml: COPILOT_GITHUB_TOKEN is now set only for
the copilot-cli matrix leg (
matrix.agent == 'copilot-cli' && github.token || ''), in both the bootstrap and test steps. - e2e-isolated.yml: same per-agent guard on the COPILOT_GITHUB_TOKEN secret
(
inputs.agent == 'copilot-cli' && secrets.COPILOT_GITHUB_TOKEN || ''). - e2e.yml, e2e-checkpoint-store.yml: checkout now runs with
persist-credentials: false so the copilot-scoped GITHUB_TOKEN isn't left in
.git/config for an agent process to read. (The job-level
copilot-requests: writepermission must stay — GitHub does not allow matrix expressions inpermissions:— but the token is no longer reachable by non-copilot agents via env or disk.)
e2e-checkpoints-v2.yml already compartmentalizes copilot in its own copilot-cli-only job, so it needs no change.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Changes
3
.github/workflows
Me2e-checkpoint-store.yml+13/-3
Me2e-isolated.yml+4/-2
Me2e.yml+14/-2
55 unmodified lines
permissions:
actions: read
contents: read
# Granted for every leg so copilot-cli works in the matrix; harmless for others.
# Needed by the copilot-cli leg. GitHub does not allow matrix expressions in
# `permissions:`, so this scope is granted to every leg's GITHUB_TOKEN. The
# token is kept away from non-copilot agents in two ways: it is only placed
# in COPILOT_GITHUB_TOKEN for the copilot-cli leg (see env blocks below), and
# checkout runs with persist-credentials: false so it is not left in
# .git/config for an agent process to read.
copilot-requests: write
strategy:
fail-fast: false
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# Don't persist the (copilot-scoped) GITHUB_TOKEN in .git/config, where
# an agent process running in the checkout could read it.
persist-credentials: false
- name: Install system dependencies
run: |
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
FACTORY_API_KEY: ${{ secrets.FACTORY_API_KEY }}
COPILOT_GITHUB_TOKEN: ${{ github.token }}
# Only the copilot-cli leg gets the token; other agents must not receive it.
COPILOT_GITHUB_TOKEN: ${{ matrix.agent == 'copilot-cli' && github.token || '' }}
run: go run ./e2e/bootstrap ${{ matrix.agent }}
- name: Run isolated test
run: |
E2E_CODEX_MODEL: ${{ inputs.agent == 'codex' && 'gpt-5.4-mini' || '' }}
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
FACTORY_API_KEY: ${{ secrets.FACTORY_API_KEY }}
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
# Only copilot-cli gets the token; other agents must not receive it.
COPILOT_GITHUB_TOKEN: ${{ inputs.agent == 'copilot-cli' && secrets.COPILOT_GITHUB_TOKEN || '' }}
E2E_ARTIFACT_DIR: ${{ github.workspace }}/e2e-artifacts
E2E_ENTIRE_BIN: /usr/local/bin/entire
run: |
The above content has been cleaned according to the specified requirements.