fix(publisher): record repository.id at init so renames stay resolvable - #1570
Open
UgaTheDev wants to merge 1 commit into
Open
fix(publisher): record repository.id at init so renames stay resolvable#1570UgaTheDev wants to merge 1 commit into
UgaTheDev wants to merge 1 commit into
Conversation
`repository.id` is documented in the schema as the forge's own identifier, stable across renames and usable to detect a repository being deleted and recreated. Nothing ever populates it: `mcp-publisher init` writes only `url` and `source`, so in practice every entry's only pointer at its source is a URL. A URL is not a stable pointer. Renaming or transferring a GitHub repository leaves the registered URL resolving only through GitHub's redirect — which the REST API follows but GraphQL does not, so GraphQL consumers see "Could not resolve to a Repository" and the source link is effectively broken. modelcontextprotocol#1484 measured this across the 398 highest-graded remote servers: 38 of them (9.5%) already point at renamed or transferred repos. Resolve the ID at init and write it alongside the URL. One request, at scaffolding time rather than in the publish path, and the entry stays re-resolvable afterwards even once its URL has gone stale. Deliberately best effort: `init` is otherwise fully offline, so being off the network, rate limited, or pointed at a private repo leaves the field empty rather than failing the command. `GITHUB_TOKEN` is used when set. This stops new entries from rotting. It does not backfill the 38 already affected, and it does not decide whether publish should reject or warn on a URL that redirects — both need a maintainer call, raised on the issue. Signed-off-by: Kush Zingade <kush.zingade@gmail.com>
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.
Towards #1484
Background
#1484 audited the
repository.urlof the 398 highest-graded remote servers andfound 38 (9.5%) pointing at repositories that have since been renamed or
transferred. No hard 404s — GitHub's REST API follows the redirect — but GraphQL
consumers resolve them as nonexistent (
Could not resolve to a Repository), sothe source link is broken for a real class of tooling, and it stays broken once
the redirect eventually lapses.
The gap this closes
pkg/model/types.goalready defines the field that solves this:Nothing populates it.
mcp-publisher initbuilds the repository block fromdetectRepoURL()and writesurlandsourceonly, so in practice every entry'ssole pointer at its source is a URL — and a URL is not a stable pointer.
This PR resolves the ID at init time and writes it alongside the URL. A rename
after that point no longer loses the entry: the ID still identifies the
repository, and it also gives the "deleted and recreated" detection the schema
doc already describes something to compare against.
Scope and deliberate limits
latency or GitHub rate-limit exposure to publishing.
initis otherwise fully offline. Being off the network,rate limited, or pointed at a private repo leaves the field empty rather than
failing the command.
GITHUB_TOKENis used when set, mostly so a rate-limiteddeveloper still gets an ID.
repository.sourcealso allowsgitlab, anddetectRepoURLcan produce a plain
gitsource. Those return empty; GitLab's equivalentlookup is easy to add if you want it, but I did not want to guess at the
ID semantics for a forge the audit did not cover.
github.com, optionallywww.) so a lookalike hostcannot get us to fetch an ID that belongs to somebody else. Covered by a test.
What this does not do
Two parts of #1484 are maintainer calls, not code I should pick unilaterally, and
I have written them up on the issue rather than guessing here:
database, not this repo —
CLAUDE.mdis explicit thatdata/seed.jsonislocal dev seed data and must not be used to publish. So a data fix cannot
arrive as a PR to this repository at all; it needs an operator-run migration,
and someone has to decide whether rewriting a publisher's
repository.urlwithout them re-publishing is acceptable.
record.
ValidateServerJSONis currently pure and offline; the only networkvalidation lives in
ValidatePublishRequestbehindcfg.EnableRegistryValidation, and it returns a bareerrorwith no channelfor a warning even though
ValidationIssueSeverityWarningexists elsewhere.Wiring a warning through is a real design decision about the publish contract.
Test
cmd/publisher/commands/init_internal_test.go:TestParseGitHubOwnerRepo— the URL shapesdetectRepoURLactually produces(plain,
www., trailing slash,.git), plus the ones that must not betreated as GitHub: gitlab, a
github.com.evil.examplelookalike, a deep/tree/main/...path, an owner with no repo.TestDetectRepoID— against anhttpteststub: records the numeric id andrequests
/repos/{owner}/{repo}; and stays empty on 404 / non-GitHub source /empty URL, so a failed lookup can never fail
init.golangci-lintwas not available in my environment, so that gate is unverifiedlocally.