Skip to content

ll: <level> + write-only scope expands to invalid id-token: read in generated lock file #43189

Description

@Evangelink

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

Metadata

Metadata

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions