Release pipeline: enforce the version guard on dispatch, clean SBOM, least-privilege jobs (#507) - #525
Merged
kgdunn merged 7 commits intoAug 29, 2026
Conversation
…lish pipeline (#507) The ENG-21 gate promised that a typo in pyproject.toml on main cannot ship a release, but three paths around the gate remained. This closes them: - publish.yml: the version guard now also runs on workflow_dispatch, which becomes a republish-only path: the checked-out commit must already carry the v<version> tag for the version in pyproject.toml. - publish.yml: the build job additionally asserts CHANGELOG.md has a matching "## [X.Y.Z]" heading (mirroring the extraction regex), and the notes-extraction step fails loudly instead of silently falling back to auto-generated notes. - publish.yml: gh release create passes --target with the SHA of the checked-out commit (HEAD, not GITHUB_SHA, since a dispatch run may check out inputs.ref), so the release tag lands on the published commit rather than the default branch head. - publish.yml: the SBOM is generated from a fresh venv containing only the built wheel and its runtime closure, with pip/setuptools/wheel removed; cyclonedx-bom runs from a separate tooling venv so build tooling no longer ships as runtime components. - publish.yml: permissions are per-job. The build job, which executes repo code via PEP 517 hooks, holds only contents: read; id-token, contents, and attestations write scopes stay on the publish job. - publish.yml: pypa/gh-action-pypi-publish is pinned to the commit SHA that release/v1 resolves to (v1.14.2) instead of the mutable branch. - Makefile: the release target no longer builds or publishes; it prints the tag-gated release instructions and exits nonzero. Version 1.73.3; CITATION.cff and CHANGELOG.md updated in step. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
The typecheck gate is red on main itself: the unpinned mcp extra now resolves to mcp 2.x, where FastMCP was renamed MCPServer, so mypy fails on mcp_server.py on every branch. This ports the migrated server and the mcp>=2.0 floor verbatim from #528; the diff no-ops once #528 merges. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
Owner
Author
|
The Generated by Claude Code |
63 tasks
…e-library-issues-hr7xxk-release # Conflicts: # CHANGELOG.md # CITATION.cff # pyproject.toml
…e-library-issues-hr7xxk-release # Conflicts: # CHANGELOG.md # CITATION.cff # pyproject.toml
…e-library-issues-hr7xxk-release # Conflicts: # CHANGELOG.md # CITATION.cff # pyproject.toml
test_budget_clamped_to_minimum_model_size fails intermittently on any PR's CI (macOS, assert 3 >= 4) in code this PR does not touch. Root cause and fix are in #531; ported verbatim so this PR's CI is deterministic. No-ops once #531 merges. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
…e-library-issues-hr7xxk-release # Conflicts: # CHANGELOG.md # CITATION.cff # pyproject.toml
kgdunn
deleted the
claude/process-improve-library-issues-hr7xxk-release
branch
August 29, 2026 07:47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #507. Closes the three paths around the ENG-21 (#303) publish gate, plus the smaller hardening items from the same issue. No library code changes; everything is in
.github/workflows/publish.yml,Makefile, and the release metadata files.workflow_dispatchthe checked-out commit must already carry av<version>tag matchingpyproject.toml, so dispatch becomes a republish-only path (re-run a failed release, re-upload the SBOM). I chose this over a required "expected version" dispatch input because an input only proves the operator typed the same string as the file they are publishing; it does not tie the publish to a deliberate tag on a specific commit. Requiring the existing tag preserves the workflow's stated promise exactly: no tag, no release, regardless of whatpyproject.tomlholds on the chosen ref. The guard errors also tell the operator what to do (push the tag; dispatch against the tag itself).## [X.Y.Z]heading exists inCHANGELOG.md(mirroring the extraction regex) and fails before anything is built or published. The notes-extraction step in the publish job now errors instead of silently falling back to--generate-notes.gh release createpasses--target "$(git rev-parse HEAD)".HEADof the checkout rather thanGITHUB_SHA, because a dispatch run may check outinputs.ref, which differs fromgithub.ref.pip/setuptools/wheelare uninstalled from it before the scan, andcyclonedx-bomruns from a separate tooling venv, pointed at the target venv's interpreter.build,cyclonedx-bom, and their transitive deps can no longer appear as components.permissions: {}; thebuildjob (which executes repo code via PEP 517 hooks) gets onlycontents: read;id-token: write,contents: write, andattestations: writestay on thepublishjob, which also creates the GitHub release (there is no separate release job). The trusted-publishing/OIDC and attestation setup is otherwise untouched, per the issue's non-goals.pypa/gh-action-pypi-publishis pinned todc37677b2e1c63e2034f94d8a5b11f265b73ba33, resolved viagit ls-remoteas the current head ofrelease/v1, which is the peeled commit of tagv1.14.2(noted in a comment next to the pin).releasetarget no longer pulls, builds, or publishes. It prints the tag-gated release instructions (git tag vX.Y.Z && git push origin vX.Y.Z, orworkflow_dispatchfor a republish) and exits nonzero.Housekeeping in the same PR: version 1.73.3 in
pyproject.tomlandCITATION.cff(date-released: 2026-08-29), plus the matching## [1.73.3] - 2026-08-29CHANGELOG section and link-footer updates. The version assumes the earlier queued PRs (1.73.x siblings) merge first; their CHANGELOG entries and compare links slot in above/below this one.Test plan
Full verification needs a real release run (tag push and a dispatch republish); the workflow paths cannot be exercised from CI on this PR. Verified locally:
python -c "import yaml; yaml.safe_load(open('.github/workflows/publish.yml'))"parses cleanlyCHANGELOG.md: they match1.73.3and1.71.0, and reject a missing versionuv run ruff check .anduv run ruff format --check .both passmake releasenow exits nonzero with the instructionsChecklist
pyproject.toml(PATCH for fixes/docs/config, MINOR for new features)ruff check .passesCHANGELOG.mdupdatedGenerated by Claude Code