Repository navigation
Apply cooldown to Go modules - #564
Merged
Merged
Conversation
With cooldown on, @v/list leaves out versions whose .info time is inside the window, and @latest falls back to the newest release out of cooldown when upstream's answer is too new. Each listed version's .info is read once and its time is stored in the versions table, as npm does, except for modules whose path has uppercase letters, since golang PURLs are lowercased. A .info, .mod or .zip for a version in cooldown, and a query such as a branch name that resolves to one, gets 403. The go command moves on to the next GOPROXY entry after 404 or 410, so a 404 would let GOPROXY=proxy,direct fetch the version directly. Go has no publish time: .info carries the commit time of the revision, so a version tagged on an old commit counts as old. The docs say so. Part of git-pkgs#132
A failed .info fetch counted as an unknown time, so a rate-limited or flaky upstream let versions in cooldown through. It now fails the list or download with 502; only a version upstream doesn't know, or whose .info has no time, is let through. Times are stored under the escaped module path, which keeps modules that differ only in case apart. Modules with uppercase letters were not stored before and fetched every .info again on each list request. Only canonical versions are stored, since a query such as a branch name can resolve to a later commit. A .mod or .zip whose version doesn't unescape is answered with 404 instead of being passed upstream unchecked.
andrew
approved these changes
Oct 23, 2026
andrew
left a comment
Contributor
There was a problem hiding this comment.
Small follow-up worth doing: with cooldown on, every @v/list request calls GetVersionByPURL once per listed version, so a module with 2,000 versions costs 2,000 DB queries per list even when every time is stored. One GetVersionsByPackagePURL at the top of allowedVersions, then fetching .info only for versions missing from that map, would cut it to one query.
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.
Go part of #132, on the existing
proxy.Cooldownhook as suggested there.With cooldown on:
@v/listleaves out versions whose.infotime is inside the window. Each listed version's.infois fetched once, eight at a time, and its time is stored in theversionstable, the same way npm stores its times. The key uses the escaped module path (github.com/!azure/...), so modules that differ only in case don't share a row. Only canonical versions are stored, so a query likemasteris never stored..infocan't be fetched, the list or download fails with 502 instead of letting the version through. A.modor.zipwhose version doesn't unescape gets 404 and is not passed upstream.@latestis served unchanged when upstream's answer is out of cooldown. Otherwise the proxy serves the newest listed release out of cooldown, or the newest pre-release if there is no release..info,.modand.zip, and so does a query such as@v/main.infothat resolves to one. It is 403 rather than 404 because the go command tries the nextGOPROXYentry after 404 or 410, so withGOPROXY=proxy,directa 404 would fetch the version directly.Caveat: Go has no publish time.
.infogives the commit time of the revision, so a version tagged on an old commit counts as old. I noted this in the README and indocs/configuration.md.I checked this with the go command against proxy.golang.org through a local proxy with a 30-day cooldown and
GOPROXY=proxy,direct:go get golang.org/x/mod@latestadded v0.41.0. v0.42.0 is from 9 October.go get golang.org/x/mod@v0.42.0failed with403 Forbidden: version is in cooldownand did not fall back todirect.