You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
push: branches: [main], bare pull_request:, release: [published]
⚠️The two active rulesets target ~DEFAULT_BRANCH, not a branch name. So v1/main inherits nothing — it will be completely unprotected the moment it is created. This phase must create a new ruleset explicitly targeting refs/heads/v1/main; there is no "it's covered by main's rules" shortcut.
git rev-parse origin/v1/main
git rev-list -n1 1.0.0 # must match
Step 2 — give it CI (PR into v1/main)
.github/workflows/main.yml on v1/main, add the branch to the push trigger:
on:
push:
branches:
- main
+ - v1/main
pull_request: is already unfiltered, so PRs into v1/main are covered with no change — verify, don't edit.
Merge this before applying the ruleset in step 3, so the build check has registered on the branch and the first protected PR can't deadlock on a check that has never run.
Step 3 — branch ruleset for v1/main
Clone the existing ruleset rather than hand-writing it — this preserves the exact bypass_actors (with their actor_ids) and the build check's integration_id, both of which are easy to get wrong by transcription:
gh api repos/modelcontextprotocol/inspector/rulesets/3187937 \
| jq '{ name: "v1/main - full protection", target, enforcement, bypass_actors, conditions: { ref_name: { include: ["refs/heads/v1/main"], exclude: [] } }, rules }'> /tmp/v1-ruleset.json
gh api -X POST repos/modelcontextprotocol/inspector/rulesets --input /tmp/v1-ruleset.json
This carries over: deletion, non_fast_forward, pull_request (1 approval, dismiss stale reviews on push, require code-owner review, require last-push approval), and required_status_checks on context build.
Step 4 — tag ruleset for 1.x
No tag rulesets exist today. Protect the released v1 tags from being moved or deleted, while still allowing creation (phase 2 needs to create 1.0.1):
update blocks moving a tag; creation is deliberately not included.
Verification
⚠️Never test protection with a real git push origin v1/main. You are a
repo admin and the ruleset's bypass_actors include RepositoryRole 5 at bypass_mode: always — so the push succeeds, proves nothing, and writes to v1/main. non_fast_forward then blocks a clean undo. Use the API check below.
Steps 1–2 — branch exists at 1.0.0 + the workflow commit, build ran on the PR.
Step 3 — ruleset 19858989 active. Rules resolve on the branch: sh gh api 'repos/modelcontextprotocol/inspector/rules/branches/v1%2Fmain' --jq '.[].type' # → deletion, non_fast_forward, pull_request, required_status_checks
Step 4 — tag ruleset 19859230 active. (There is no/rules/tags/
API — GitHub only exposes /rules/branches/ — so read the ruleset back:) sh gh api repos/modelcontextprotocol/inspector/rulesets/19859230 \ --jq '{target, enforcement, include: .conditions.ref_name.include, rules: [.rules[].type]}' # → tag, active, ["refs/tags/1.*"], ["deletion","update"] # creation absent, so phase 2 can still cut 1.0.1
Why the protection is load-bearing
The release environment's Deployment branches and tags is No restriction (verified 2026-07-27). Combined with npm trusted publishing matching on workflow filename only, v1/main's main.yml is authorized to publish the root package name — including to latest — from the moment the branch exists. Anyone who can push to v1/main can publish the v2 package name. This is not a parking branch.
Phase 1 of 9 in the v2 go-live runbook — see #1804 (§2, §10). Reversible.
Stand up
v1/mainas a real, guarded branch before anything is published from it.Ground truth (verified 2026-07-27)
mainbranch protection (legacy API)2749948"L3 - full protection"~DEFAULT_BRANCH, rules: deletion, non_fast_forward, pull_request3187937"L3 - full protection"~DEFAULT_BRANCH, rules: deletion, non_fast_forward, pull_request, required_status_checks (build)2781134"build"~ALLpush: branches: [main], barepull_request:,release: [published]Step 1 — create the branch
Verify it sits on the released commit:
git rev-parse origin/v1/main git rev-list -n1 1.0.0 # must matchStep 2 — give it CI (PR into
v1/main).github/workflows/main.ymlonv1/main, add the branch to the push trigger:on: push: branches: - main + - v1/mainpull_request:is already unfiltered, so PRs intov1/mainare covered with no change — verify, don't edit.Merge this before applying the ruleset in step 3, so the
buildcheck has registered on the branch and the first protected PR can't deadlock on a check that has never run.Step 3 — branch ruleset for
v1/mainClone the existing ruleset rather than hand-writing it — this preserves the exact
bypass_actors(with theiractor_ids) and thebuildcheck'sintegration_id, both of which are easy to get wrong by transcription:This carries over:
deletion,non_fast_forward,pull_request(1 approval, dismiss stale reviews on push, require code-owner review, require last-push approval), andrequired_status_checkson contextbuild.Step 4 — tag ruleset for
1.xNo tag rulesets exist today. Protect the released v1 tags from being moved or deleted, while still allowing creation (phase 2 needs to create
1.0.1):updateblocks moving a tag;creationis deliberately not included.Verification
1.0.0+ the workflow commit,buildran on the PR.19858989active. Rules resolve on the branch:sh gh api 'repos/modelcontextprotocol/inspector/rules/branches/v1%2Fmain' --jq '.[].type' # → deletion, non_fast_forward, pull_request, required_status_checks19859230active. (There is no/rules/tags/API — GitHub only exposes
/rules/branches/— so read the ruleset back:)sh gh api repos/modelcontextprotocol/inspector/rulesets/19859230 \ --jq '{target, enforcement, include: .conditions.ref_name.include, rules: [.rules[].type]}' # → tag, active, ["refs/tags/1.*"], ["deletion","update"] # creation absent, so phase 2 can still cut 1.0.1Why the protection is load-bearing
The
releaseenvironment's Deployment branches and tags is No restriction (verified 2026-07-27). Combined with npm trusted publishing matching on workflow filename only,v1/main'smain.ymlis authorized to publish the root package name — including tolatest— from the moment the branch exists. Anyone who can push tov1/maincan publish the v2 package name. This is not a parking branch.Blocks #1815.