Skip to content

release.yaml: callers forced to grant unused permissions for conditionally-skipped jobs #149

Description

@sonupreetam

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:

  1. 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.

  2. Document the minimum required permission set per feature combination, so callers know upfront what to grant even for skipped jobs.

  3. 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.

Metadata

Metadata

Assignees

Labels

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