Summary
When workflow permissions: uses the all: <level> meta-key together with an explicit write-only scope (e.g. copilot-requests: write or id-token: write), the compiler expands all into every scope in GetAllPermissionScopes() — including id-token: read. GitHub Actions rejects any workflow containing id-token: read (that scope only accepts write/none), so the generated .lock.yml fails to run with:
Invalid workflow file
(Line: N, Col: 17): Unexpected value 'read'
The compile itself reports 0 errors, 0 warnings in strict mode, even though the docs state id-token: read "will be rejected at compile time".
Version
gh aw version v0.81.6 (setup action + CLI both v0.81.6).
Minimal reproduction
.github/workflows/repro.md:
---
on:
workflow_dispatch:
permissions:
all: read
copilot-requests: write
engine: copilot
---
# Repro
Body.
gh aw compile repro
grep "id-token" .github/workflows/repro.lock.yml
# id-token: read <-- invalid; GitHub Actions rejects the workflow
Key observation (root cause is the merge path)
permissions:\n all: read alone compiles fine — no id-token is emitted (it renders as read-all / only the needed scopes).
- Adding a second explicit key such as
copilot-requests: write forces all to be expanded into explicit scopes so the map can be merged. That expansion (permissions_operations.go: for _, s := range GetAllPermissionScopes() { ... p.permissions[s] = p.allLevel }) includes PermissionIdToken and assigns it allLevel (= read), producing the invalid id-token: read.
This matters because all: read + copilot-requests: write is exactly the pattern the compiler itself now recommends (it prints Tip: set permissions.copilot-requests: write ...).
Expected behavior
id-token should be excluded from (or special-cased in) the all-expansion merge — it only supports write/none, so all: read must never yield id-token: read. Ideally strict compile should also error rather than emit an invalid lock file.
Workaround
Replace all: read with the explicit read-scope map minus id-token, keeping the write-only scope:
permissions:
actions: read
attestations: read
checks: read
contents: read
copilot-requests: write
deployments: read
discussions: read
issues: read
models: read
packages: read
pages: read
pull-requests: read
repository-projects: read
security-events: read
statuses: read
vulnerability-alerts: read
Summary
When workflow
permissions:uses theall: <level>meta-key together with an explicit write-only scope (e.g.copilot-requests: writeorid-token: write), the compiler expandsallinto every scope inGetAllPermissionScopes()— includingid-token: read. GitHub Actions rejects any workflow containingid-token: read(that scope only acceptswrite/none), so the generated.lock.ymlfails to run with:The compile itself reports 0 errors, 0 warnings in strict mode, even though the docs state
id-token: read"will be rejected at compile time".Version
gh aw version v0.81.6(setup action + CLI both v0.81.6).Minimal reproduction
.github/workflows/repro.md:Key observation (root cause is the merge path)
permissions:\n all: readalone compiles fine — noid-tokenis emitted (it renders asread-all/ only the needed scopes).copilot-requests: writeforcesallto be expanded into explicit scopes so the map can be merged. That expansion (permissions_operations.go:for _, s := range GetAllPermissionScopes() { ... p.permissions[s] = p.allLevel }) includesPermissionIdTokenand assigns itallLevel(=read), producing the invalidid-token: read.This matters because
all: read+copilot-requests: writeis exactly the pattern the compiler itself now recommends (it printsTip: set permissions.copilot-requests: write ...).Expected behavior
id-tokenshould be excluded from (or special-cased in) theall-expansion merge — it only supportswrite/none, soall: readmust never yieldid-token: read. Ideally strict compile should also error rather than emit an invalid lock file.Workaround
Replace
all: readwith the explicit read-scope map minusid-token, keeping the write-only scope: