[HN Gopher] Go.sum is not a lockfile
___________________________________________________________________
Go.sum is not a lockfile
Author : pabs3
Score : 161 points
Date : 2026-01-08 04:10 UTC (18 hours ago)
(HTM) web link (words.filippo.io)
(TXT) w3m dump (words.filippo.io)
| anishgupta wrote:
| nice, if a module like github.com/foo/bar v1.2.3 is later
| modified or compromised upstream, the checksum in go.sum will
| cause the build to fail unless the exact same content is fetched.
| peterldowns wrote:
| Correct, but it's been ages and the default actions/setup-go
| github action still uses go.sum instead. I see that someone
| already commented on the longstanding issue to reference this
| post, and that there is some hope that they'll update it!
|
| https://github.com/actions/setup-go/issues/478
| Groxx wrote:
| The private repo mention in the comments there is kinda a good
| one, unfortunately. If someone runs a private gosum/goproxy
| (relatively common) and amends a tag (hopefully very uncommon
| _but_ I have personally seen it happen at least three times)
| then the cache could be wrong because go.mod didn 't have to
| change. Which is Bad(tm) but it depends on what edge cases they
| want to handle automatically, vs optimization for the majority
| case.
|
| For well-behaving/stable/consistent setups I fully agree
| though, go.mod is both sufficient and better, and those other
| cases can probably just key off both instead. I _think_ I 've
| seen go.mod to change without go.sum changes (change an unused
| transitive dependency into a direct dependency), which can lead
| to your build needing something that wasn't cached because it
| was pruned in the previous version.
| saghm wrote:
| From a relatively naive outside perspective, it sounds like
| this would be pretty much only ever a self-inflicted probably
| (where "self" might be an org rather than an individual).
| What you're describing sounds almost like a force push to a
| private repo; if you're doing that, you might break things
| for anyone using it, so the risks should probably rest with
| you for asking so. "This breaks my setup if I modify history
| in a way that's expected to be immutable" isn't a super
| compelling argument for everyone behaving well to have to
| continue dealing with a suboptimal status quo.
| Groxx wrote:
| It's basically a force-push, yeah. Which does happen, like
| with git, so you do kinda need a way to deal with it even
| if it's not automatic.
|
| Which it sounds like they have (planned), which seems like
| a good improvement.
| Groxx wrote:
| > _If the main module imports example.com /mod1/pkg1 and a
| separate example.com/mod1/pkg2 imports example.com/mod2, there is
| no way for example.com/mod2 to affect the build or run code on
| the developer's machine, so you don't need to consider it a
| dependency._
|
| iirc (I do not have a test setup at the moment to verify) it
| _does_ affect your dependency resolution, and therefore your
| build, though _its code_ does not exist in your binary. I know
| this because those AWS / K8S / Google Cloud libraries cause
| MASSIVE problems with their constant breaking changes without
| major version changes, and their importing other libraries that
| also have frequent breaking changes without major version
| changes, even if the dependency those unused subpackages include
| (and therefore raise the minimum version) is only used by some
| other module that needs a lower version (iirc). It's quite a
| headache sometimes, and could be rather easily solved if you
| could set upper bounds and not just lower. Or if those giga-
| projects would stop doing such obviously bad things.
|
| The version-affecting behavior is kinda unavoidable afaict. If
| they _didn 't_ include those unused version constraints, `go
| build ...` or just importing a new package within existing
| modules could cause your build to fail, forcing you to rerun
| version resolution. That'd probably just lead people to feel like
| "go is broken UGH", and go leans awfully hard towards avoiding
| that kind of thing. Mostly for the better, but not quite always /
| not in all ways.
| nasretdinov wrote:
| These libraries are honestly so bad that whenever I have to
| interact with them I just split those dependencies into a
| separate binary :)
| supriyo-biswas wrote:
| I just write my own, small, focused client for these AWS
| services since the SDKs are generally just so unergonomic.
| With vibe coding becoming a thing it's become even easier to
| do that.
| kbolino wrote:
| You may already know these things, but for others who may
| not: the AWS SDK for Go suffers from _shockingly_ bad
| discoverability.
|
| For example, take the S3 library, github.com/aws/aws-sdk-
| go-v2/service/s3. If you have an s3.Client and you look at
| e.g. the ListObjectsV2 method, you might have no idea that
| there is a ListObjectsV2Paginator which makes it much
| easier to use, because nowhere in the method docs is it
| mentioned. Indeed, most operations that paginate have more
| ergonomic paginators, but none of them tell you this.
|
| But that isn't even the worst of it. Say you want to
| download or upload a file to S3. If you haven't worked with
| AWS for other languages, you might think that you just do
| GetObject and PutObject. And yes, for small files, that's
| generally fine. But for large files you want to use
| resumable downloads and multipart uploads. So you look and
| lo, there is no simple way to do this in the AWS SDK for
| Go. But actually, there is! It's in a totally unrelated and
| unlinked package, called github.com/aws/aws-sdk-
| go-v2/feature/s3/manager.
|
| Now you're getting some religion, so you ask "what are the
| other so-called 'feature' packages?" and you try to browse
| pkg.go.dev at the github.com/aws/aws-sdk-go-v2/feature
| level but nope, that's not a Go module so there's nothing
| to see there. In fact, you can't even browse the other s3
| features, never mind find out what other services have
| features. Fortunately, you can browse their GitHub repo at
| least: https://github.com/aws/aws-sdk-
| go-v2/tree/main/feature
|
| It's quite clear that they use poorly thought-out cross-
| language codegen for this, which partly explains the lack
| of ergonomics, but also shows that they don't much care
| whether you use their stuff properly.
| onionisafruit wrote:
| I dabbled in Kubernetes at work a few years ago. I was
| shocked at the state of their go.mod files. Especially
| because I had heard Kubernetes used as an example of great Go
| software. Right off the bat I needed to copy a dozen or so
| `replace` statements into my go.mod. I was sure I just didn't
| understand something and spent an hour or so looking for the
| "right way" only to discover other open source controllers
| that had the same replaces in their go.mods.
|
| Maybe that was a transitory stage and it's straightened out
| now. I certainly hope so.
| cpuguy83 wrote:
| Definitely _do not_ look at Kubernetes as a good example of
| go code and especially not how it handles deps (btw, it
| only relatively recently switched to go mods).
|
| Not to say it is a bad project. Not at all.
| jerf wrote:
| I think a lot of people assume Kubernetes must be a good Go
| example, because it's so big and successful. But it started
| life as a Java project and was ported into Go, and that
| shows in some of the architecture, Also, in general across
| all languages, picking the absolute largest projects you
| can is often not a great idea in terms of copying design
| unless you too are going to be that large, e.g., I wouldn't
| suggest using Firefox as an example of C++ necessarily.
| Such projects always end up developing solutions to
| problems you will never have, and solving problems we don't
| have is one of the most common mistakes software developers
| make.
| nullpoint420 wrote:
| I like your comparison about Firefox not being a great
| example of "good" C/C++.
|
| I'd personally consider myself comfortable in C/C++. I've
| built Wayland compositors, H264 backends for live-
| streaming, and built Chromium occasionally for testing.
| Despite being a die-hard Firefox (zen) user - I still
| have not been able to compile Firefox! To be fair, this
| was pre-Firefox quantum days so I hope their SVM and
| build tools have improved.
| lokar wrote:
| I remember early on the Go people complaining about the
| K8S Go code
| renewiltord wrote:
| They write it in space shuttle mode. Which means that it's
| all got too many components from too many makers all
| kludged together and then one piece falls off and the whole
| thing blows up in production.
| nvarsj wrote:
| godep and vendoring completely solved this problem.
|
| Go modules relies too heavily on dependencies being good
| citizens, which is a very naive approach to dependency
| management.
| quacker wrote:
| You can still do vendoring with Go modules, using the `go mod
| vendor` command.
| nvarsj wrote:
| I'm a bit out of date now, but 'go mod vendor' did not in
| fact vendor all dependencies when I last used it. It seemed
| more like a CI caching mechanism then actual complete
| dependency vendoring.
| FiloSottile wrote:
| It's tricky, to the point that I made a little playground to
| explore it.
|
| https://github.com/FiloSottile/mostly-harmless/tree/main/dep...
|
| The example.com/mod2 go.mod does not in fact affect version
| resolution, because it's not even fetched. However, it affects
| the example.com/mod1 go.mod, and the example.com/mod1 go.mod
| affects version resolution.
|
| This doesn't help with the problem you are describing, but it
| still has value from a security point of view, because
| example.com/mod2 truly doesn't matter except to the extent that
| was already checked into example.com/mod1, which you do need to
| trust.
|
| If you try to "go build" or "go test" something in
| example.com/mod2, you actually do get an error since Go 1.17,
| as if it was not in your dependency tree at all. You need to
| "go get" it like any new dependency.
| djha-skin wrote:
| > Instead, just look at go.mod. It lists the precise version at
| which all dependencies are built.
|
| No, it does not. Minimum version selection means that the
| libraries will _at least_ be that version, but it could be
| substituted for a later version if a transient dependency asks
| for such.
|
| That I'm reading this blog post at all suggests there is a
| "market" for a single checksum/version manifest, which data is
| currently housed in go.sum . This is sad, but, Hyrum's Law and
| all that.
| LukeShu wrote:
| The correct answer is `go mod vendor && cat vendor/modules.txt`
| saghm wrote:
| Just to clarify, this will download the entirety of all of
| the dependencies in order to find out what versions are
| resolved? And then those versions aren't actually locked
| unless you keep the vendored dependencies around
| indefinitely?
|
| My understanding is that the point of a lockflle is that you
| _don 't_ need to do that.
| ncruces wrote:
| > No, it does not. Minimum version selection means that the
| libraries will at least be that version, but it could be
| substituted for a later version if a transient dependency asks
| for such.
|
| No?
|
| All dependencies - direct and indirect - are listed in your
| go.mod. Your module - as is - depends on nothing else. And
| those exact versions will be used to build it, _if yours is the
| main module_.
|
| If your module is used as a dependency of another module, then
| yes, your module may be built with a newer version of those
| dependencies. But _that_ version will be listed in _that_
| module 's go.mod.
|
| There's no way to use different versions without them being
| listed in _some_ go.mod.
|
| go.sum to only maps between versions and hashes, and may
| contain hashes for multiple versions of modules.
| skywhopper wrote:
| But a "version" as listed in go.mod may have different hashes
| over time, if tags are changed. That's the issue.
| jchw wrote:
| This doesn't make any sense to me.
|
| If you wanted to verify the _contents_ of a dependency, you
| _would_ want to check go.sum. That 's what it is there for,
| after all. So if you wanted to _fetch_ the dependencies,
| then you would want to use it to verify hashes.
|
| If all you care about the is the _versions_ of
| dependencies, you really can (and should) trust go.mod
| alone. You can do this because there are multiple
| overlapping mechanisms that all ensure that a tag is
| immutable once it is used:
|
| - The Go CLI tools will of course use the go.sum file to
| validate that a given published version of a module can
| never change (at least since it was depended on, but it
| also is complementary with the features below as well, so
| it can be even better than that.)
|
| - Let's say you rm the go.sum file. That's OK. They also
| default to using the Go Sum DB to verify that a given
| published version of a module can never change. So if a
| module has ever been `go get`'d by a client with the Sum DB
| enabled and it's publicly accessible, then it should be
| added to the Sum DB, and future changes to tags will cause
| it to be rejected.
|
| - And even then, the module proxy is used by default too,
| so as soon as a published version is used by anyone, it
| will wind up in the proxy as long as its under a suitable
| license. Which means that even if you go and overwrite a
| tag, almost nobody will ever actually _see_ this.
|
| The downside is obviously all of this centralized
| infrastructure that is depended on, but I think it winds up
| being the best tradeoff; none of it is a _hard_ dependency,
| even for the "dependencies should be immutable" aspect
| thanks to go.sum files. Instead it mostly helps dependency
| resolution remain fast and reproducible. Most language
| ecosystems have a _hard_ dependency on centralized
| infrastructure, whether it is a centralized package manager
| service like NPM or a centralized repository on GitHub,
| whereas the centralized infrastructure with Go is strictly
| complementary and you can even use alternative instances if
| you want.
|
| But digression aside, because of that, you can trust the
| version numbers in go.mod.
| terinjokes wrote:
| A local cache of sums are also stored in (iirc) $GOCACHE,
| so even if you delete go.sum from the project, the local
| toolchain should still be able to verify module versions
| previously seen without needing to call out to the Sum
| DB.
| onionisafruit wrote:
| > If you wanted to verify the contents of a dependency,
| you would want to check go.sum
|
| You're right, but also TFA says "There is truly no use
| case for ever parsing it outside of cmd/go". Since cmd/go
| verifies the contents of your dependencies, the point
| generally stands. If you don't trust cmd/go to verify a
| dependency, then you have a valid exception to the rule.
| lokar wrote:
| Probably unpopular, but I just use Bazel and pick the
| versions of software I use.
|
| I know the current attitude is to just blindly trust 3rd
| party libraries (current and all future versions) and all
| of their dependencies, but I just can't accept that. This
| is just unsustainable.
|
| I guess I'm old or something.
| jchw wrote:
| Go MVS does not require you to blindly trust 3rd party
| libraries. Certainly not "current and all future
| versions". Go modules also offer hermetic and
| reproducible dependency resolution by default.
| ncruces wrote:
| Conversely, I can say that an hash being in go.sum doesn't
| mean it will be used for anything.
|
| Only that _if_ the corresponding version does get used,
| _and_ the hash doesn 't match, you get an error. But you
| can have multiple versions of the same dep in your go.sum -
| or none at all - and this has no bearing on what version
| gets picked when you build your module.
|
| The version that does get picked is the one in go.mod of
| the main module, period; go.sum, if it exists, assists hash
| verification.
|
| Yes, if you want a lockfile in the npm sense, you need
| _both_.
|
| But a Go module does not get built with new transitive
| dependencies (as was claimed) unless they're listed in some
| go.mod; go.sum is irrelevant for that.
| onionisafruit wrote:
| Although he doesn't spell it out, I suspect this is the
| primary misunderstanding that drove Filo to open with "I
| need everyone to stop looking at go.sum, especially to
| analyze dependency graphs". I've had more than one code
| reviewer ding me on a module showing up in go.sum.
| Usually it's a situation where a dependency has tests for
| compatibility with some other module so that other module
| gets added to go.sum. Given Filo is a professional open
| source maintainer, any annoyance I've run into he's
| probably experienced 100x.
| PhilippGille wrote:
| Minimum version selection happens when the go.mod file is
| updated, so it contains the minimum versions already.
|
| It doesn't happen only later at build time.
|
| For example:
|
| - `go get x@v1.0.0` => Your go.mod contains `x v1.0.0`
|
| - `go get y@v1.0.0` with y having x v1.0.1 as dep => Your
| go.mod is already updated with the resolved minimum selected
| version: `x v1.0.1`
|
| This requires using Go commands to manage the go.mod file. If
| you edit it in a text editor then a final `go mod tidy` will
| help.
| uasi wrote:
| I'm not deeply familiar with this, but from reading the `go mod
| tidy` manual[1], it seems that running `go mod tidy` loads all
| packages imported from the main module (including transitive
| dependencies) and records them with their precise versions back
| to `go.mod`, which should prevent them from being substituted
| with later versions. Am I understanding this correctly?
|
| [1]: https://go.dev/ref/mod#go-mod-tidy
| kadoban wrote:
| go.mod will always match whatever versions are being used
| directly, as far as I know. But it's not possible to lock
| them using go.mod. Like if you wanted to bump one version
| only in go.mod, you're then stumped for actually doing that.
| Because _probably_ the only reasonable way to get that to
| build is to do `go mod tidy` after doing that, which will
| modify go.mod itself. And you can't _really_ go back in and
| undo it unless you just manually do all of go.mod and go.sum
| yourself.
| ncruces wrote:
| Running `go mod tidy` months apart with no other changes to
| your module will not change your go.mod. It certainly _won
| 't_ update dependencies.
|
| You run that when you've made manual changes (to go.mod or
| to your Go code), or when you want to slim down your go.sum
| to the bare minimum needed for the current go.mod.
|
| And that's one common way to update a dependency: you can
| edit your go.mod manually. But there are _also_ commands to
| update dependencies one by one.
| arccy wrote:
| go always requires a dependency graph that is consistent
| with all the declared requirements.
|
| Which means if you wanted to update one version, it might
| bump up the requirements on its dependencies, and that's
| all the changes you see from running go mod tidy
| afterwards.
|
| Manually constructing an inconsistent dependency graph will
| not work.
| jchw wrote:
| The MVS choices will be encoded into the go.mod; you may have
| been correct in the past, but as the post mentions transitive
| dependencies have been incorporated since Go 1.17. So yes,
| really: the only point of go.sum is to enable checking the
| integrity of dependencies, as a nice double-check against the
| sumdb itself.
| arccy wrote:
| This comment suggests that there is a "market" for confidently
| incorrect, contrarian HN comments. This is sad, but, Hyrum's
| Law and all that.
| FiloSottile wrote:
| No.
|
| As explained in the post, if a transitive dependency asks for a
| later version than you have in go.mod, that's an error if -mod
| is readonly (the default for non-get non-tidy commands).
|
| I encourage you to experiment with it!
|
| This is exactly how the "stricter" commands of other package
| managers work with lockfiles.
| wereHamster wrote:
| A lock file, in my world, contains a cryptographic hash of
| dependencies. go.mod does not, it only lists tags, which are (in
| git) movable references.
|
| If go.sum has "no observable effect on builds", you don't know
| what you're building and go can download and run unverified code.
|
| I'm not a go developer and must be misunderstanding something...
| PunchyHamster wrote:
| > I'm not a go developer and must be misunderstanding
| something...
|
| I think it's coz not EVERY language's lockfile comes with
| checksum
|
| So, Go's go.mod is functionally equivalent Ruby Gem lockfile
| (that doesn't have checksum) but need to get go.sum to be
| equivalent to npm's (that does come with checksum)
|
| Author just compared it to languages where lockfile means just
| version lock
| wereHamster wrote:
| Now I understand :) thanks for clarifying
| inglor wrote:
| You are not misunderstanding anything, I use Go and
| Rust/TypeScript in my daily work and you are correct - it is
| the OP that does not understand why people use lockfiles in CI
| (to prevent minor updates and changes in upstream through
| verifying a hash signature).
| alias_neo wrote:
| I would hazard a guess that the (former) head of the Go
| security team at Google (OP) _does_ in fact understand.
| kibwen wrote:
| They may be an expert in Go, but from their writing they
| appear to be misunderstanding (or at least misrepresenting)
| how things work in other languages. See the previous
| discussion here:
| https://lobste.rs/s/exv2eq/go_sum_is_not_lockfile
| typical182 wrote:
| > _They may be an expert in Go, but from their writing
| they appear to be misunderstanding (or at least
| misrepresenting) how things work in other languages_
|
| Thanks for that link.
|
| Based on reading through that whole discussion there just
| now and my understanding of the different ecosystems, my
| conclusion is that certainly people there are _telling_
| Filippo Valsorda that he is misunderstanding how things
| work in other languages, but then AFAICT Filippo or
| others chime in to explain how he is in fact not
| misunderstanding.
|
| This subthread to me was a seemingly prototypical
| exchange there:
|
| https://lobste.rs/s/exv2eq/go_sum_is_not_lockfile#c_d26oq
| 4
|
| Someone in that subthread tells Filippo (FiloSottile)
| that he is misunderstanding cargo behavior, but Filippo
| then reiterates which behavior he is talking about (add
| vs. install), Filippo does a simple test to illustrate
| his point, and some others seem to agree that he is
| correct in what he originally said.
|
| That said, YMMV, and that overall discussion does
| certainly seem to have some confusion and people
| seemingly talking past each other (e.g., some people
| mixing up "dependents" vs. "dependencies", etc.).
| kibwen wrote:
| _> but then AFAICT Filippo or others chime in to explain
| how he is in fact not misunderstanding._
|
| I don't get this impression. Rather, as you say, I get
| the impression that people are talking past each other, a
| property which also extends to the author, and the
| overall failure to reach a mutual understanding of terms
| only contributes to muddying the waters all around.
| Here's a direct example that's still in the OP:
|
| _" The lockfile (e.g. uv.lock, package-lock.json,
| Cargo.lock) is a relatively recent innovation in some
| ecosystems, and it lists the actual versions used in the
| most recent build. It is not really human-readable, and
| is ignored by dependents, allowing the rapid spread of
| supply-chain attacks."_
|
| At the end there, what the author is talking about has
| nothing to do with lockfiles specifically, let alone when
| they are applied or ignored, but rather to do with the
| difference between minimum-version selection (which Go
| uses) and max-compatible-version selection.
|
| Here's another one:
|
| _" In other ecosystems, package resolution time going
| down below 1s is celebrated"_
|
| This is repeating the mistaken claims that Russ Cox made
| years ago when he designed Go's current packaging system.
| Package resolution in e.g. Cargo is almost too fast to
| measure, even on large dependency trees.
| JetSetIlly wrote:
| By default, all go mod downloads go through the golang proxy
| (https://proxy.golang.org/). That is part of the verification
| process.
| zelphirkalt wrote:
| Does this mean, that when you change the proxy, you lose all
| guarantees?
| arccy wrote:
| Only if you change checksum servers https://sum.golang.org/
| Note that the default one uses data from
| https://proxy.golang.org/
| wereHamster wrote:
| Let's assume I publish a github repo with some go code, and
| tag a particular commit with tag v1.0.0. People start using
| it and put v1.0.0 into their go.mod file. They use the golang
| proxy to fetch the code (and that proxy does the
| "verification", according to your comment). Now I delete the
| v1.0.0 tag and re-create the tag to point to different
| (malicious) commit. Will the golang proxy notice? How does it
| verify that the people that expect the former commit under
| the v1.0.0 tag will actually get that and not the other
| (malicious) commit?
| compsciphd wrote:
| yes.
|
| From my understanding
|
| its stored forever in the proxy cache and your new tag will
| never be fetched by users who go through the language's
| centralized infrastructure (i.e. proxy).
|
| go can also validate the checksums (go.sum) against the
| languages central infrastructure that associates
| version->checksums.
|
| i.e. if you cut a release, realize you made a mistake and
| try to fix it quitely, no user will ever see it if even one
| user saw the previous version (and that one user is
| probably you, as you probably fetched it through the proxy
| to see the mistake)
| kibwen wrote:
| _> its stored forever in the proxy cache_
|
| This is mistaken. The Go module proxy doesn't make any
| guarantee that it will permanently store the checksum for
| any given module. From the outside, we would expect that
| their policy is to only ever delete checksums for modules
| that haven't been fetched in a long time. But in general,
| you should not base your security model on the notion
| that these checksums are stored permanently.
| agwa wrote:
| > _The Go module proxy doesn 't make any guarantee that
| it will permanently store the checksum for any given
| module_
|
| Incorrect. Checksums are stored forever, in a Merkle
| Tree, meaning if the proxy were to ever delete a
| checksum, it would be detected (and yes, people like me
| are checking - https://sourcespotter.com/sumdb).
|
| Like any code host, the proxy does not guarantee that the
| code for a module will be available forever, since code
| may have to be removed for legal reasons.
|
| But you absolutely can rely on the checksum being
| preserved and thus you can be sure you'll never be given
| different code for a particular version.
| kibwen wrote:
| Ah, my mistake. I had read in the FAQ that it does not
| guarantee that data is stored forever, but overlooked the
| part about preserving checksums specifically.
| neild wrote:
| To be very pedantic, there are two separate services: The
| module proxy (proxy.golang.org) serves cached modules and
| makes no guarantees about how long cache entries are
| kept. The sum database (sum.golang.org) serves module
| checksums, which are kept forever in a Merkle
| tree/transparency log.
| wereHamster wrote:
| Ok. So to answer the question whether the code for v1.0.0
| that I downloaded today is the same as I downloaded
| yesterday (or whether the code that I get is the same as
| the one my coworker is getting) you basically have to
| trust Google.
| ncruces wrote:
| Not really.
|
| For the question "is the data in the checksum database
| immutable" you can trust people like the parent, who
| double checks what Google is doing.
|
| For the question "is it the same data that can be
| downloaded directly from the repos" you can skip the
| proxy to download dependencies, then do it again with the
| proxy, and compare.
|
| So I'd say you don't need to trust Google at all in this
| case.
| agwa wrote:
| The checksums are published in a transparency log, which
| uses a Merkle Tree[1] to make the attack you describe
| detectable. Source Spotter, which is unaffiliated with
| Google, continuously verifies that the log contains only
| one checksum per module version.
|
| If Google were to present you with a different view of
| the Merkle Tree with different checksums in it, they'd
| have to forever show you, and only you, that view. If
| they accidentally show someone else that view, or show
| you the real view, the go command would detect it. This
| will eventually be strengthened further with
| witnessing[2], which will ensure that everyone's view of
| the log is the same. In the meantime, you / your coworker
| can upload your view of the log (in
| $GOPATH/pkg/sumdb/sum.golang.org/latest) to Source
| Spotter and it will tell you if it's consistent with its
| view: $ curl --data-binary "@$(go env
| GOPATH)/pkg/sumdb/sum.golang.org/latest"
| https://gossip.api.sourcespotter.com/sum.golang.org
| consistent: this STH is consistent with other STHs that
| we've seen from sum.golang.org
|
| [1] https://research.swtch.com/tlog
|
| [2] https://github.com/C2SP/C2SP/blob/main/tlog-
| witness.md
| kbolino wrote:
| Here's another person auditing the checksum database:
| https://raphting.dev/posts/gosumdb-live-again/
| compsciphd wrote:
| ok, I guess I was wrong about the cache, but not the
| checksums. I was somewhat under the impression that it
| was forever due to the getting rid of vendoring. Getting
| rid of vendoring (to me) only makes sense if its cached
| forever (otherwise vendoring has significant value).
| typical182 wrote:
| Go modules did not get rid of vendoring. You can do 'go
| mod vendor' and have been able to do so since Go modules
| were first introduced.
|
| How long the google-run module cache (aka, module proxy
| or module mirror) at https://proxy.golang.org caches the
| contents of modules is I think slightly nuanced.
|
| That page includes:
|
| > Whenever possible, the mirror aims to cache content in
| order to avoid breaking builds for people that depend on
| your package
|
| But that page also discusses how modules might need to be
| removed for legal reasons or if a module does not have a
| known Open Source license:
|
| > proxy.golang.org does not save all modules forever.
| There are a number of reasons for this, but one reason is
| if proxy.golang.org is not able to detect a suitable
| license. In this case, only a temporarily cached copy of
| the module will be made available, and may become
| unavailable if it is removed from the original source and
| becomes outdated.
|
| If interested, there's a good overview of how it all
| works in one of the older official announcement blog
| posts (in particular, the "Module Index", "Module
| Authentication", "Module Mirrors" sections there):
|
| https://go.dev/blog/modules2019#module-index
| sidewndr46 wrote:
| This makes the assumption that everyone uses the default
| proxy, which is not the case
| markkitti wrote:
| The pyproject.toml, package.json, and Cargo.toml are declarative
| project configuration files. While the Rust community refers to
| Cargo.toml as a manifest, it is not a comprehensive and detailed
| list of a build. That is the lock file.
|
| While go.mod does not allow for explicit version ranges, the
| versions given are the minimum versions. In other words, the
| versions given are the lower bound of the compatibility range.
|
| Go also strictly follows semantic versioning. Thus the implicit
| exclusive upper bound is the next major version. This assumes
| that all minor and patch releases are backwards compatibile and
| not breaking.
|
| Dependency resolution in Go uses minimum version selection. That
| means the minimum requirements of all dependencies are evaluated
| and highest minimums are selected. In principle, this minimum
| version selection should be time invariant since the oldest
| versions of the compatible dependencies are used
|
| While the minimum versions specified in go.mod are not
| necessarily the version of the dependencies used, they can be
| resolved to the versions used irrespective of time or later
| versions of dependencies being released.
|
| Other languages do not use minimum version selection. Their
| package resolution often tries to retrieve the latest compatible
| dependency. Thus a lock file is needed.
|
| Python packages in particular do not follow semantic versioning.
| Thus ranges are critical in a pyproject.toml.
|
| In summary, the "manifests" files that the original author
| describes are configuration files. In some languages, or more
| accurately their package management schemes, they can also be
| lock files, true manifests, due to version semantics. If those
| semantics are absent, then lock files are necessary for
| compatibility.
| brabel wrote:
| That's very interesting. Most systems I know would pick the
| highest versions allowed by the ranges. In maven and gradle,
| for example, at least by default they choose the highest
| versions allowed. Even if no version range is used, it picks
| the highest choice even across major versions, which I always
| thought was completely broken. What does go do if you have two
| transitive dependency versions whose allowed major is
| different?
| Athas wrote:
| In some sense, Go does not allow you to change the major
| version. Packages with the same name but different major
| versions are treated as different packages.
| FiloSottile wrote:
| > While the minimum versions specified in go.mod are not
| necessarily the version of the dependencies used
|
| This has not been true since Go 1.17 with the default
| -mod=readonly, which is why go.mod is a reliable lockfile.
| virajk_31 wrote:
| I am today years old to find this...
| dmarwicke wrote:
| npm's package.json and package-lock.json get out of sync
| constantly on my team. at least go only has one file to mess up
| abejfehr wrote:
| how is this possible? isn't everyone using the same node
| version?
|
| and checking in lockfile changes
| pie_flavor wrote:
| Two very similar things are presented as though they are
| different (go.mod and lockfiles, not go.sum) for the purpose of
| sneering at one of them, when both are essentially the same.
| 'Ignored by downstream dependents' is not any less true of go.mod
| than of lockfiles. In both cases a later version can be demanded,
| overriding the earlier version, potentially breaking your code.
___________________________________________________________________
(page generated 2026-01-08 23:01 UTC)