Skip to content

Move the Release Task's Job Scopes to the Caller - #772

Merged
ptr727 merged 2 commits into
developfrom
feature/nuget-idtoken-at-caller
Aug 16, 2026
Merged

Move the Release Task's Job Scopes to the Caller#772
ptr727 merged 2 commits into
developfrom
feature/nuget-idtoken-at-caller

Conversation

@ptr727

@ptr727 ptr727 commented Aug 16, 2026

Copy link
Copy Markdown
Owner

What

build-release-task.yml no longer declares job-level permissions: on build-nuget (id-token: write) or github-release (contents: write, actions: write). The caller grants what the targets it enables need, and docs/reusable-workflows.md "Adopting the Release Chain" says so.

Why

The hub's first release through the task, dispatched on main at 82fecef after #768, ended in startup_failure (run 31972504539). A called job's permissions: block is validated against the caller's grant before its if: runs (GOVERNANCE.md "Workflow YAML Conventions", the reusable-workflows bullet), so build-nuget asking for id-token: write fails any caller that does not grant it, the hub's own publish job included, even though the job is disabled. github-release's block has the same shape and would fail every smoke build, since a Dependabot pull request holds a read-only token that cannot grant contents: write. This is the finding #762 declined on the ground that only NuGet/login consumes the scope: the consumption was never the problem, the declaration was.

Verification

actionlint, prose gate, audit self-test, 686 unit tests, markdownlint. The live proof is the re-dispatched hub release after this promotes, which is the next step.

The hub's first release through build-release-task.yml failed at
startup: build-nuget declared id-token: write at job level, and a
called job's permissions block is validated against the caller's grant
before its if: runs, so a caller that does not grant that scope fails
the whole workflow even with the job disabled. github-release carried
the same trap for contents and actions write, which a smoke build under
a read-only pull request token could never grant. Both blocks go, the
caller grants what the targets it enables need, and the doc says so.
Copilot AI lite review requested due to automatic review settings August 16, 2026 21:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the hub’s reusable release workflow to avoid startup failures caused by job-level permissions: blocks that are validated against the caller’s token grant even when the job is skipped. It shifts responsibility for granting write/OIDC scopes to the caller workflow and documents the required caller-side permissions.

Changes:

  • Remove job-level permissions: from build-nuget and github-release in build-release-task.yml.
  • Expand docs/reusable-workflows.md guidance so adopters grant the needed permissions at the caller job level.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
docs/reusable-workflows.md Documents caller-granted permissions for release-chain adoption.
.github/workflows/build-release-task.yml Removes job-level permissions to prevent reusable-workflow startup validation failures.
Suppressed comments (1)

.github/workflows/build-release-task.yml:536

  • This comment implies contents: write and actions: write are needed for any publish, but they are only required when this job is enabled (inputs.github is true and inputs.smoke is false). Making that explicit helps callers avoid granting write scopes when they do not create a GitHub release.
    # The release upload and the artifact-delete cleanup both write with GITHUB_TOKEN, and the caller grants contents: write and actions: write on a publish.
    # No job-level permissions: block here, for the reason build-nuget gives: a block is validated against the caller's grant before if: runs, and a smoke caller holds a read-only token.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/reusable-workflows.md Outdated
Comment thread .github/workflows/build-release-task.yml Outdated
Copilot AI review requested due to automatic review settings August 16, 2026 21:15
@ptr727

ptr727 commented Aug 16, 2026

Copy link
Copy Markdown
Owner Author

Answering the suppressed finding, "Suppressed comments (1)", from the round on 4daf37b: .github/workflows/build-release-task.yml:536, "This comment implies contents: write and actions: write are needed for any publish, but they are only required when this job is enabled". Fixed in a244452: the comment says the caller grants them when it sets github: true on a non-smoke run, and that a registry-only or smoke caller leaves the job disabled and grants neither.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@ptr727
ptr727 merged commit 63d244b into develop Aug 16, 2026
8 checks passed
@ptr727
ptr727 deleted the feature/nuget-idtoken-at-caller branch August 16, 2026 21:30
ptr727 added a commit that referenced this pull request Aug 16, 2026
Promote `develop` to `main`, carrying two changes:

- #772 Move the Release Task's Job Scopes to the Caller:
`build-release-task.yml` declares no job-level `permissions:` on
`build-nuget` or `github-release`, since a called job's block is
validated against the caller's grant before its `if:` and failed the
hub's own release at startup (run 31972504539 on `82fecef`). The caller
grants what its enabled paths write with.
- #771 Bump astral-sh/setup-uv from 8.1.0 to 10.0.0 (Dependabot,
auto-merged to `develop` by the App through the hub-hosted merge-bot
task, run 31972622149, the same bump #770 merged to `main` through it,
run 31972611554, so both live proofs of the stage-0 tracker are in).

The release dispatched after this merge is the live proof of the scope
fix: the hub's `publish` job grants `contents: write` and `actions:
write`, every target is disabled, and `github-release` must run and
create the tag.
ptr727 added a commit that referenced this pull request Aug 16, 2026
…nippets (#775)

Release `2.0.352` (`main` `0b07a59d7c65d07d8df275a96deaf2e06cbefd51`) is
the
first tag carrying every hub-hosted reusable workflow task, produced by
[the publish-release
run](https://github.com/ptr727/ProjectTemplate/actions/runs/31974067182)
after promotion #774. In that run `build-release-task.yml` ran with
every
target disabled and its `github-release` job succeeded while all five
build
jobs skipped, proving the `github-release` skip fix (#762) and the
caller-granted scopes (#772). The earlier release attempt on `82fecef`

([run](https://github.com/ptr727/ProjectTemplate/actions/runs/31972504539))
ended in `startup_failure` because `build-nuget`/`github-release`
declared
job-level permissions; #772 fixed it.

## docs/reusable-workflows.md "Rollout"

- Ticks the two stage-0 merge-bot proof items: Dependabot PR #771 merged
to
  `develop` with `--squash` through `merge-bot-task.yml`

([run](https://github.com/ptr727/ProjectTemplate/actions/runs/31972622149)),
  and Dependabot PR #770 merged to `main` with `--merge`

([run](https://github.com/ptr727/ProjectTemplate/actions/runs/31972611554)).
- Ticks "Promoted and released" in stages 2, 3, 4, and 5 with `2.0.352`
on
  `0b07a59d` and #774, and stage 4 also notes the first attempt's
  `startup_failure` and its #772 fix.
- Leaves every adoption and pilot checkbox untouched.
- Does **not** tick either stage's "Catalog snippets ... pinned to that
release" item, since neither stage's full set of snippets is complete
this
  time: stage 2's release-with-smoke shape still calls its own repo's
`build-release-task.yml` by `./` path rather than the hub's, and stage
5's
  `deploy-site.yml`, `publish-docker-readme-task.yml`, and
  `check-upstream-version-task.yml` each stay open for reasons the doc
  itself already states (no manifest-wide snippet by design, or a job
  embedded in a larger stub rather than a standalone caller). Both items
  gain an inline note identifying which of their snippets this PR adds.

## New catalog snippets

Three of the five/six candidate files, each pinned
`0b07a59d7c65d07d8df275a96deaf2e06cbefd51 # 2.0.352` and byte-identical
to
its doc stub block apart from the pin (and, where the doc's own comment
wrapping does not survive an actual YAML file's comment-wrap rule, a
reworded comment kept in sync on both sides):

- `catalog/snippets/workflows/test-pull-request.yml` (the no-build gate
  shape from "Adopting the Gates")
- `catalog/snippets/workflows/publish-release.yml` (the release-repo
shape
  from "Adopting the Release Chain")
- `catalog/snippets/workflows/run-periodic-codegen-pull-request.yml`
(the
  codegen stub, which the doc already says keeps today's per-repo shape)

Skipped, with the doc updated to say why:

- `test-pull-request-smoke.yml` - the doc's smoke stub still calls the
caller's own `./.github/workflows/build-release-task.yml` by local path,
  never the hub's `build-release-task.yml` directly, so it does not meet
  the "calls the hub task" condition.
- `deploy-site.yml` - the doc's own "Deploy-site" paragraph states it
  "has no manifest-wide catalog snippet either," the same reason
`get-version-task.yml`/`publish-plan-task.yml` have none: each site's
own
  shape varies too much around the shared `deploy` job.
- `check-upstream-version.yml` - the doc gives only the
`check-upstream-version:`
job body, not a complete top-level trigger/concurrency shape, and unlike
the codegen stub there is no doc statement that a uniform shape exists
to
  copy.

`catalog/snippets/workflows/README.md` gained rows for the three new
snippets and an updated intro paragraph explaining the partial rollout.

## TODO.md

Added one **Settled** line under "Host the type-specific tasks" naming
`2.0.352` as the release that makes stages 2-5 adoptable and the run
that
proved the release chain, and noting #769 as the one open follow-up from
the promotion review.

## reports/workflow-reuse.md

Regenerated with `python3 spec/workflow_reuse.py --report` against the
live
fleet at hub `63d244b` (this branch's base). The numbers move against
the
last committed report only because the live fleet moved since then, not
because of anything in this PR.

## Gates run locally

`spec/validate.py`, `python3 -m unittest discover -s scripts/tests` (686
tests), `spec/audit.py --selftest`, `spec/workflow_reuse.py --selftest`,
`scripts/repo_gate.py` (sha-pin resolved against GitHub),
`scripts/build_dist.py --check`,
`scripts/prose_lint.py` (all nine checks), `ruff check`/`ruff format
--check`,
`mypy`, and the Docker `actionlint`, `markdownlint-cli2`, and
`editorconfig-checker` linters (only `.ruff_cache` noise there).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants