Skip to content

Cut v1.0.0 with release-cut — and settle which actor pushes the tag #1073

Description

@bdelanghe

Correction to this issue's original premise

It was filed saying "a ruleset restricts tag creation, so a human must grant it in [settings]". Both halves of that look wrong, and the correction matters more than the issue did.

Rulesets in this org are code, not UI. They live in .github-private at org/rulesets/*.json and are applied by org-sync.yml. Nothing about them is a human clicking in a settings pane.

And none of them touch tags. Every committed ruleset is target=branch or target=repository:

ci-green*.json                 target=branch
default-branch-protection.json target=branch
critical-repo-protection.json  target=branch   (enforcement=disabled)
protect_important_repos.json   target=repository

A search across docs/, org/ and .github/ in .github-private for refs/tags, tag creation, protected tag returns nothing.

So what was the 403?

Almost certainly the Claude Code session git proxy, not a repository rule. The observed pattern, isolated at the time:

operation, from a session result
create branch allowed
delete branch refused
create tag refused

No GitHub ruleset produces that shape — a tag-creation rule does not also refuse branch deletes. A proxy permitting creates/updates under refs/heads/* and refusing everything else explains all three. mint#22 reached exactly this conclusion for an identical symptom, and explicitly separated it from mint#18's org ruleset: "Different mechanism from #18 — that's an org ruleset, this is a Claude Code session's git proxy — but the same shape."

A GitHub Actions runner is not behind that proxy. So release-cut.yml may be able to push the tag with github.token today, with no grant and no settings change.

This has never been tested: mint#23's release-cut has never cut a real tag either, so nobody in this org has yet observed a workflow attempting a tag push.

What to do

Dispatch release-cut with expect-version: 1.0.0, dry-run: false.

That is the test, and it is a safe one to run: all four guards pass already (verified against real repo state in #1071), and the only remaining step is the push. If no restriction exists, the tag lands, release-binary.yml is dispatched at it, and v1.0.0 ships — the outcome we want. If a restriction does exist, it fails closed at the push having created nothing but a local tag inside the runner. There is no half-released state between those.

Run dry-run: true first if you want the guard output on the record; it cannot tell you anything about the push.

The actor question still stands

Independent of whether a restriction exists today, it is worth deciding who should hold tag-creation, because the answer shapes the workflow:

  • A — the repo's Actions actor (what the code does today). Cuts with github.token. Simplest; nothing to mint. If tag rules are ever introduced, they would have to name this actor, which is broad: any workflow with contents: write inherits it.
  • B — a pinned App identity, minted from a capability-named broker entry pinned to release-cut.yml — the shape version.yml uses (/github/forge-version) and claim-ticket.yml uses (front-desk-claim). Narrower by construction. Costs an infra-side broker entry.

On mint#22's rejection of "a PAT or App token so the push looks human": that objection is about buying a trigger with a standing credential. release-cut.yml already solves triggering separately, by dispatching release-binary.yml at the new tag. B would be authorization, not triggering — related but not the same, and worth saying out loud if adopted.

If B is chosen, the dispatch step must be removed: an App-token push does fire on: push: tags, so release-binary.yml would otherwise run twice. Under A the dispatch is load-bearing, because a GITHUB_TOKEN push triggers nothing.

Acceptance

  • v1.0.0 is cut and release-hashes.json on main moves off 0.29.0.
  • The actor that pushes release tags is a deliberate choice, recorded.
  • If a tag restriction is discovered to exist after all, it is added to org/rulesets/ as code — not applied by hand.

Related: #1068, #1069, #1071, #434, #1072, mint#18, mint#22.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions