Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

#253

Publish repositories as Go modules and move the module path to rodent.software

merged · by keenan 15h ago · merged into main at d37d301f by keenan 2h ago

keenan opened this 15h ago

The module named github.com/rodent-software/vole, a GitHub repository that does not exist. Moving it to the forge alone would not have been enough: go get resolves an import path by fetching https://<import-path>?go-get=1 and reading a <meta name="go-import"> tag, and the forge served only pages. So this change does both halves — the discovery tag first, then the path that depends on it.

What changed

Go module discovery. A new goModuleMeta on the web layer answers the ?go-get=1 probe from the catch-all route. The first path segment is the repository, any segments after it are packages, and the tag names the repository prefix and its Git transport:

<meta name="go-import" content="rodent.software/vole git https://rodent.software/git/vole.git">

It lives on the catch-all rather than a new route because a module path is not a page the forge serves, and the catch-all already sees exactly the paths no other route claimed — no new top-level route can shadow or be shadowed by /r/, /u/, /static/ and the rest. Decisions inside it:

  • Public repositories only. The tag is fetched without credentials — that is the discovery protocol — so answering for a private repository would confirm its existence to anyone who guessed the name. A private repository answers 404, as everywhere else. docs/go-modules.md says how to consume one instead (local checkout plus replace).
  • The host comes from public_url, never the request’s Host header, for the same reason the clone URL does: the import prefix is a claim about which module path this instance owns, and a header an attacker chose must not make it.
  • The prefix is the host name alone, because a module path cannot carry a port. An instance reachable only on a nonstandard port still serves pages; its repositories are not importable paths, which the page states.
  • The link in the tag’s explanation is /r/<repository>, the page a reader already knows.

The module path. module rodent.software/vole in go.mod, and every import in 253 files follows it. The build line in docs/getting-started.md, the nfpm homepage, and both packaged units’ Documentation= URL now point at the forge (https://rodent.software/r/vole) instead of the nonexistent GitHub repository.

Documentation. A new docs/go-modules.md (linked from the docs index and from the public_url section of the configuration guide) explains the lookup, what the instance must have configured, the public-only rule, and the naming limit below.

Naming limit

A repository named after a top-level route — r, u, admin, activity, login, static, and so on — keeps its pages and clone URL but cannot claim <host>/<name> as an import prefix, because the route wins the path. Because the probe is answered from the catch-all, this needs no reserved-name list; it simply never reaches it. That is documented rather than enforced, since renaming an existing repository is not something this change should decide.

Verification

  • TestPublicRepositoryServesGoImportMetadata checks the tag at the repository path, at a package path under it, and with a trailing slash, plus the HTML content type and that the path without the probe is still the styled 404.
  • TestPrivateRepositoryDoesNotAdvertiseAGoModule and TestGoImportIgnoresPathsThatNameNoRepository cover the refusals.
  • go build ./... and gofmt are clean under the new module path; ./vole workflow run verify passes (format, vet, build, licenses, govulncheck, packages, deployment files, markdown links, race tests).

Closes #248.

Discussion (2)

keenan 15h ago

Rebased onto main after #250, #251, and #252 landed, so the head now includes them (merge: clean against main, fast-forward). The import rename picked up server/ui_test.go, which #251 added; git grep github.com/rodent-software is now empty. ./vole workflow run verify re-run and green at d37d301.

keenan 2h ago

Note: #254 (root-level repository URLs) is stacked on this branch. With repositories at /<name>, the go-import probe can no longer live on the catch-all, so #254 moves it to the pre-router and rebases the module path change on top of it. Landing this request first, then #254, gives the cleanest history; if #254 lands first it contains these commits and this request can be closed as superseded.