HI version is available. Content is displayed in original English for accuracy.
Advertisement
Advertisement
⚡ Community Insights
Discussion Sentiment
83% Positive
Analyzed from 1599 words in the discussion.
Trending Topics
#package#source#proxy#files#module#vcs#code#git#still#tarball

Discussion (25 Comments)Read Original on HackerNews
In many cases I think it's impossible to avoid the pain that comes with decentralization without defeating the point. It's challenging because certain things are hard to do decentralized so it's easier to just give up and rely on central authorities and components.
When you install Go, it does just that, to some approximation; it will try to fetch from the module proxy first and fall back after that fails. But what makes Go different and more interesting is that you can just turn that off with no consequence. As long as all of the Git hosts are up, you can still use Go just fine with no proxy. I'm pretty sure Nix builds do this by default with Go so I believe most dependencies are usually online. That means the proxy approach and the decentralized approach are both fully redundant with eachother, while allowing the decentralized VCS hosts to remain the source of truth.
Go also separately has the sumdb to enforce immutability, so you can know that when you go grab a specific package that the tag name corresponds to one and only one exact source code. This is also optional, and even without it you get the benefit of local sum checking via your own cache and go.sum files in source checkouts. But having this be separate is great because it also means you could use another third party module proxy or a third party sumdb, or use just the sumdb and no proxy. It gives you many options to not have to rely on a single party while still getting some of the benefits of centralization.
Systems like this are rare. Many systems try very hard to have the cake and eat it too, but it usually fails somewhere. For me Go's approach works, and that is worth some attention.
With NPM, uv, composer, Cargo, etc. you can indeed choose to make your dependencies pull from VCS, but:
- Not having universal module proxies with caching means you will run into the usual problems. Repos can disappear, history can be rewritten, hosts can go down. Even if you invented an equivalent caching service, without making it an ecosystem default it won't achieve the same effectiveness as Go because less would be in the cache.
- Because it isn't an ecosystem standard, dependencies you pull would then still reference dependencies from centralized repos anyways, more or less defeating the point. You'd have to go and override every recursive dependency to really make it decentralized.
(And again, it usually comes with other downsides depending on the specific ecosystem. Performance is a big one, the module cache definitely helps make fetching dependencies in Go faster.)
Not having centralized package repos comes with its ups and downs, but the lack of one existing means there are a limited number of interesting attacks you can really pull in the Go ecosystem and they are heavily tamper-evident. You can try to poison the module cache with a given revision for a dependency with malicious code then overwrite it with an inoccuous commit, but this will probably be detected when someone (possibly in Nixpkgs or another packaging system) runs GOPROXY=direct and the sumdb doesn't line up. So the least noticeable thing you can really do is just leave your malicious code in the repo. Go also has the kind of nice property that fetching and building modules is supposed to be safe with untrusted code. That's pretty good, it would be hard to do better than that.
It also means there really isn't any central namespace to poison. You can still trick someone into downloading and using malicious software but you're mostly limited to doing it the old fashioned way. Again, hard to do much better than that.
While everyone has been losing their minds over supply chain issues, the Go ecosystem has been concerned but less so. It's still a huge risk still, dependencies can get compromised still, but attackers have no real central target to go after and get a bunch of damage at once. Nothing realistical, anyway. So, it's back to just trying to pwn individual GitHub repos.
Go is telling you that your VCS has a deficiency, without saying it out loud.
That proxy should be your own repo... but git sub modules, sub trees, sub directories are non starters for 99 percent of cases...
Git is an amazing tool, and if you want to manage your development like the linux kernel its dam near perfect. Most orgs dont work that way, and the tools and machinations that we have built around these shortcomings are rather burdensome.
I long for google to productize piper for the rest of us.
Andrew Nesbitt has a good write [0] up on why using Git as a database is a bad idea
[0] https://nesbitt.io/2025/12/24/package-managers-keep-using-gi...
First, I'm uncomfortable with making a package creator's VCS provider part of the language's module infrastructure.
Second, not all files under version control necessarily belong in a tarball, and not all files in a tarball necessarily need to be under version control.
However, the point that there should be an easy way to track changes in your dependencies is well taken. One possible approach would be that publishing a packge boils down to importing the files that normally would go in your tarball into a community-controlled VCS.
Why can't you store a (possibly shallow) clone of the repository in the "package" registry?
> Second, not all files under version control necessarily belong in a tarball
How likely is it that files under version control but "not belonging in a tarball" (not needed to compile the current version) take so much space to justify making a tarball? At least if you make a shallow clone.
> not all files in a tarball necessarily need to be under version control
Which wouldn't (besides huge files that can be handled with git-lfs and similar)?
If you have configure in mind, let's not do it please.
The risks introduced by including them vastly overcome their convenience, in my opinion.
And maybe let's move towards getting rid of autotools
Yes, that would be an option.
As to your question, you generally want to version control input files, but distribute the generated artifacts. Some possible scenarios would be documentation, data tables in source or binary form, generated code including maybe even configure scripts if you cannot avoid it (though if I had to 'vendor' 3rdparty code that uses autotools, I think I probably would just unpack a tarball and commit the relevant artifacts).
Even for documentation, you'd think it would be harmless to generate it, but it's far from a given that the tools (e.g. browsers) used to read it are safe from malicious documentation files
I think go is also a little more amenable to source library distribution since there's a pretty broad pure go ecosystem. For interpreted languages, a lot of performance sensitive stuff tends to be offloaded to arbitrary compiled languages so you end up needing a bunch of different toolchains to get everything working. A statically linked binary library is a useful abstraction layer.
> A hash of all files is checked against known hashes on sum.golang.org to prevent tags from being replaced, and it uses a proxy to prevent repos from being left-pad’d.
there is no need for 3rd party hosts to stay online. It's the best combination of de-centralized and centralized approaches.
Re pre-buiild packages: Python makes a difference between source and binary wheels. This approach is obviously for source wheels only.
if you mean nixos, that's just starting yet another distro maintenance issue from scratch
Would you mind elaborating why (presumably) nixos (since you gave a Debian example), doesn’t help with this.
As much as I'd have liked Git to be a viable option compared to centralized registries, last couple of years demonstrated running arbitrary commands during install is too much of a risk for it to work at scale.
Package contains child porn, what now?
It wasn't that long ago...