Problem
The release.yaml reusable workflow bundles several optional jobs (release_goreleaser, release_image, release_discussion) alongside the core create_release and publish_release jobs. Each optional job declares its own permissions block:
release_goreleaser: attestations: write, id-token: write
release_image: attestations: write, packages: write, id-token: write
release_discussion: discussions: write
These jobs are correctly gated behind if conditions (e.g. inputs.goreleaser-config-path != ''), so they are skipped when callers don't use those features. However, GitHub validates permission boundaries for reusable workflow nested jobs at parse time, before evaluating any if conditions.
This means a caller that only needs release-drafter + tagging is forced to grant all six permission scopes:
permissions:
contents: write
pull-requests: read
packages: write # unused -- no Docker image
id-token: write # unused -- no attestation
attestations: write # unused -- no attestation
discussions: write # unused -- no discussion
Without these, the workflow fails with a startup error:
The nested job 'release_goreleaser' is requesting 'attestations: write, id-token: write', but is only allowed 'attestations: none, id-token: none'.
Example failure: https://github.com/gemaraproj/gemara-publish-action/actions/runs/26768581701
Suggestion
A few possible approaches:
-
Split into composable workflows -- e.g. release-draft.yaml, release-goreleaser.yaml, release-image.yaml so callers only pull in (and grant permissions for) the features they use.
-
Document the minimum required permission set per feature combination, so callers know upfront what to grant even for skipped jobs.
-
Move optional jobs into separate reusable workflows called from within release.yaml conditionally -- this may sidestep the parse-time validation since the nested call itself would be conditional.
Context
We hit this in gemaraproj/gemara-publish-action, which is a GitHub Action repo that only needs release-drafter + tagging (no goreleaser, no Docker image, no attestation). We ended up inlining the workflow to avoid the over-permissioning.
Problem
The
release.yamlreusable workflow bundles several optional jobs (release_goreleaser,release_image,release_discussion) alongside the corecreate_releaseandpublish_releasejobs. Each optional job declares its ownpermissionsblock:release_goreleaser:attestations: write,id-token: writerelease_image:attestations: write,packages: write,id-token: writerelease_discussion:discussions: writeThese jobs are correctly gated behind
ifconditions (e.g.inputs.goreleaser-config-path != ''), so they are skipped when callers don't use those features. However, GitHub validates permission boundaries for reusable workflow nested jobs at parse time, before evaluating anyifconditions.This means a caller that only needs release-drafter + tagging is forced to grant all six permission scopes:
Without these, the workflow fails with a startup error:
Example failure: https://github.com/gemaraproj/gemara-publish-action/actions/runs/26768581701
Suggestion
A few possible approaches:
Split into composable workflows -- e.g.
release-draft.yaml,release-goreleaser.yaml,release-image.yamlso callers only pull in (and grant permissions for) the features they use.Document the minimum required permission set per feature combination, so callers know upfront what to grant even for skipped jobs.
Move optional jobs into separate reusable workflows called from within
release.yamlconditionally -- this may sidestep the parse-time validation since the nested call itself would be conditional.Context
We hit this in gemaraproj/gemara-publish-action, which is a GitHub Action repo that only needs release-drafter + tagging (no goreleaser, no Docker image, no attestation). We ended up inlining the workflow to avoid the over-permissioning.