Skip to content

Refuse to publish a tag that is not on main - #10

Merged
bitWarrior merged 1 commit into
mainfrom
hardening/release-provenance
Sep 3, 2026
Merged

Refuse to publish a tag that is not on main#10
bitWarrior merged 1 commit into
mainfrom
hardening/release-provenance

Conversation

@bitWarrior

Copy link
Copy Markdown
Owner

Branch protection governs main; it says nothing about tags. The release build
checked out the tagged commit and verified only that the tag matched
_version.py -- a number, not a history. Anyone able to push a tag and publish
a GitHub Release could therefore ship a commit that never passed review, and
the deployment approval was the sole remaining control.

Reproduced: a commit made off main with a backdoor added, tagged v1.2.2 with a
matching _version.py, passes the version guard unchanged.

The build now fetches main and refuses unless the tagged commit is reachable
from it, before setting up Python or building anything -- an unreviewed commit
should not produce an artifact at all. Verified the gate rejects the off-main
tag and accepts both real tags, v1.2.1 and v1.3.0.

Two supporting controls, applied to the repository rather than this file:

  • A ruleset blocking deletion and non-fast-forward updates of v* tags, so a
    published tag cannot be quietly repointed at different code. Note that tag
    rulesets cannot express "must be on main" -- there is no such rule type --
    which is why the ancestry check lives in the workflow.
  • can_admins_bypass is now false on the pypi environment, so the approval wait
    applies to the owner too rather than being skippable.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_0114gUUe4CxYr8W8oC95ffmD

Branch protection governs main; it says nothing about tags. The release build
checked out the tagged commit and verified only that the tag matched
_version.py -- a number, not a history. Anyone able to push a tag and publish
a GitHub Release could therefore ship a commit that never passed review, and
the deployment approval was the sole remaining control.

Reproduced: a commit made off main with a backdoor added, tagged v1.2.2 with a
matching _version.py, passes the version guard unchanged.

The build now fetches main and refuses unless the tagged commit is reachable
from it, before setting up Python or building anything -- an unreviewed commit
should not produce an artifact at all. Verified the gate rejects the off-main
tag and accepts both real tags, v1.2.1 and v1.3.0.

Two supporting controls, applied to the repository rather than this file:

- A ruleset blocking deletion and non-fast-forward updates of v* tags, so a
  published tag cannot be quietly repointed at different code. Note that tag
  rulesets cannot express "must be on main" -- there is no such rule type --
  which is why the ancestry check lives in the workflow.
- can_admins_bypass is now false on the pypi environment, so the approval wait
  applies to the owner too rather than being skippable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114gUUe4CxYr8W8oC95ffmD
@bitWarrior
bitWarrior merged commit 379cea6 into main Sep 3, 2026
4 checks passed
@bitWarrior
bitWarrior deleted the hardening/release-provenance branch September 3, 2026 19:54
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.

1 participant