Problem
Cascade emits permissions: contents: write at the workflow level for orchestrate (and contents: write, actions: write for promote, contents: write for external-update). Because GHA caps called-workflow permissions to the caller's permissions, every callback job inherits at least contents: write even when the callback only needs contents: read or no permissions at all.
GHA supports permissions: on individual jobs.<id>.uses entries, scoping the token permissions to what that specific job actually needs. Cascade cannot express this today.
The OIDC work (planned separately for id-token) already calls for a permissions field per callback. This issue generalises that to the full permissions map so both that work and least-privilege callbacks can be addressed with one schema field.
What to add
Add an optional permissions: map to each callback entry in the manifest schema:
callbacks:
- name: build-image
workflow: ./.github/workflows/build.yaml
permissions:
contents: read
packages: write
- name: deploy-prod
workflow: ./.github/workflows/deploy.yaml
permissions:
contents: read
id-token: write # OIDC
When permissions: is present, the generator emits it on the corresponding jobs.<id> block. When absent, the workflow-level permissions apply as today (backward-compatible).
Valid permission values follow the GHA spec (read, write, none). The generator should validate that all keys are known GHA permission scopes.
Acceptance criteria
Problem
Cascade emits
permissions: contents: writeat the workflow level for orchestrate (andcontents: write, actions: writefor promote,contents: writefor external-update). Because GHA caps called-workflow permissions to the caller's permissions, every callback job inherits at leastcontents: writeeven when the callback only needscontents: reador no permissions at all.GHA supports
permissions:on individualjobs.<id>.usesentries, scoping the token permissions to what that specific job actually needs. Cascade cannot express this today.The OIDC work (planned separately for id-token) already calls for a
permissionsfield per callback. This issue generalises that to the fullpermissionsmap so both that work and least-privilege callbacks can be addressed with one schema field.What to add
Add an optional
permissions:map to each callback entry in the manifest schema:When
permissions:is present, the generator emits it on the correspondingjobs.<id>block. When absent, the workflow-level permissions apply as today (backward-compatible).Valid permission values follow the GHA spec (
read,write,none). The generator should validate that all keys are known GHA permission scopes.Acceptance criteria
permissions:map on callback entries (keys: GHA permission scopes, values:read/write/none).permissions:onjobs.<id>when the callback entry specifies it.cascade validateerror.permissions:emit no job-level permissions block (unchanged from today).id-token: writeuse case works via this field without any separate schema addition.permissions: {contents: read}and one with nopermissions:generates a workflow where the first job haspermissions: {contents: read}and the second has no job-levelpermissions:block;cascade validatepasses.