Live data from Hacker News

How Go mitigates supply chain attacks

go.dev

91–100 of 265 posts

Re: How Go mitigates supply chain attacks

#91

I'm annoyed by the false dichotomy that colors most discussions around package management that there are only two solutions to publishing software packages: 1. a carefully curated professionally maintained standard library, 2. the complete wild west where anything goes. It's not really "false" because this is the reality of how package managers are designed today, but it's false in the sense that it doesn't have to b…

The original solution is the intermediate solution. You can build an entire useful userspace around nothing but libc and an ssl lib (take your pick between OpenSSL or GnuTLS usually). That is effectively what busybox is. Need to do some heavyweight math in Fortran? BLAS and LAPACK probably have everything you need. You can get really far with a C++ application using nothing but Boost.

For whatever reason, newer language ecosystems migrated away from that in the direction of increasingly smaller libraries until npm practically became a parody of it.

There is no reason you can't have lots and lots of useful functionality packed into a few large, well-maintained, well-packaged, well-vetted and trusted libraries, but you need trustworthy organizations willing to that maintaining and vetting. Historically, that seemed to largely be universities and research labs, where the funding and incentives are a lot different from the weekend warriors and solo devs that dominate open source landscapes today. Interestingly, I think library projects that still have large organizations behind them keep with the larger old-school ethos. Look at the world of ML and scientific computing. NumPy and SciPy are still huge libraries. Same with PyTorch and Tensorflow. QuantLib is an interesting example because it actually doesn't have a single large organization behind it. A bunch of Quants just got tired of doing the same things from scratch over and over and decided to aggregate their work for their common good. But it was 22 years ago, so maybe it was still just different back then and the trend toward small libraries hadn't kicked in yet.

Re: How Go mitigates supply chain attacks

#92

> There is no way for changes in the outside world—such as a new version of a dependency being published—to automatically affect a Go build. > Unlike most other package managers files, Go modules don’t have a separate list of constraints and a lock file pinning specific versions. The version of every dependency contributing to any Go build is fully determined by the go.mod file of the main module. I don't know if thi…

There are some subtleties here, but go.mod files are not lockfiles, including go.mod files don't follow a traditional constraint/lockfile split, which I think is part of the point in that snippet you quoted. Another way they differ is when installing a top-level tool by default npm does not use the exact version from a library's lockfile to pick the selected version of another library as far I as understand, whereas…

Wouldn't build size increase a lot if transitive dependencies were pinned to direct dependency lockfiles? Like if library A says "use version 1.0.0 of library X" and library B says "use version 1.0.1 of library X", then you'd likely end up bundling duplicate code in your build.

Not saying the tradeoff isn't worth it, but pinning to dependency lockfiles isn't without downsides.

Re: How Go mitigates supply chain attacks

#93

Go is a distillation of many decades of software engineering experience. The people behind Go (e.g., Russ Cox) have learned from history. The peanut gallery loves to complain about superficial aspects of Go. Typically these are people with little or no actual experience using the language and tools. They fixate on imagined problems that don't matter in practice. But anyone who has used Go full-time for a few years is…

I've been using Go for a couple of years now and it's funny: I do not love Go, I just work effectively in it. I am not passionate about it, but I recommend it for absolutely all appropriate use-cases. It doesnt go for intellectual satisfaction, it goes for getting shit done. You have to respect it for being so radically bland.

I get intellectual satisfaction from solving the problems not from the language I use to do it. go hits a fantastic blend in that regard.

Re: How Go mitigates supply chain attacks

#94

Earlier quoted context omitted.

There are some subtleties here, but go.mod files are not lockfiles, including go.mod files don't follow a traditional constraint/lockfile split, which I think is part of the point in that snippet you quoted. Another way they differ is when installing a top-level tool by default npm does not use the exact version from a library's lockfile to pick the selected version of another library as far I as understand, whereas…

Wouldn't build size increase a lot if transitive dependencies were pinned to direct dependency lockfiles? Like if library A says "use version 1.0.0 of library X" and library B says "use version 1.0.1 of library X", then you'd likely end up bundling duplicate code in your build. Not saying the tradeoff isn't worth it, but pinning to dependency lockfiles isn't without downsides.

FWIW, that's not what Go does. In your scenario, a Go binary ends up with a single copy of library X -- the 1.0.1 version. That's because library A is stating "I require at least v1.0.0 of X", and library B is stating "I require at least v1.0.1 of X". The minimal version that satisfies both of those requirements is v1.0.1, and that's what ends up in the binary.

That behavior is Go's "Minimal Version Selection" or "MVS". There are many longer descriptions out there, but a concise graphical description I saw recently and like is:

https://encore.dev/guide/go.mod

That's the default behavior, but a human can ask for other versions. For example, a consumer of A and B could do 'go get X@latest', or edit their own go.mod file to require X v1.2.3, or do 'go get -u ./...' to update all their direct and indirect dependencies, which would include X in this case, etc.

Re: How Go mitigates supply chain attacks

#95
post #13

Go is a distillation of many decades of software engineering experience. The people behind Go (e.g., Russ Cox) have learned from history. The peanut gallery loves to complain about superficial aspects of Go. Typically these are people with little or no actual experience using the language and tools. They fixate on imagined problems that don't matter in practice. But anyone who has used Go full-time for a few years is…

Some of those "superficial aspects" are really annoying. For example, Go forced version tags to have a `v` prefix in git repos for their dependency system, which broke a whole host of CI tools that expected plain numeric values for release versions. There's a outsized amount of Go-specific special casing for this one seemingly arbitrary decision in multi-language CI systems.

> Go forced version tags to have a `v` prefix in git repos for their dependency system

"Forced" is a bit strong - you can pin any ref, the vX tags just also have some default semver-ish treatment.

> a whole host of CI tools that expected plain numeric values for release versions

Like what? Pure numeric tags are also ambiguous with git refs; this can be worked around by careful arguments, but it means most tooling was already broken when dealing with such things.

If you were one of the people using "release-X.Y.Z" or "rXYZ" I feel for you though.

> Go-specific special casing

'v' tags have been idiomatic for ages. Semver 1.0 went so far as to mandate it in 2010, though that was taken out in 2.0. https://semver.org/spec/v1.0.0.html#tagging-specification-se...

Re: How Go mitigates supply chain attacks

#96
post #61

Earlier quoted context omitted.

Build things by KISS principle. Dependencies will complicate system you are building. ( with things like supply chain attacks, bloat, liscensing etc...)

So we just don't build GUI applications unless we understand all of the nuances of layout, text rendering, graphics programming, etc sufficient to implement it ourselves (and without the bugs that even domain experts have introduced but which have been found and fixed over time in libraries)? Or maybe we just say "fuck users who speak languages that aren't easily expressed in ASCII"? There's a reason libraries exist.…

Software programmer usually need to solve specific task, not worlds problems. If you go too generalized you will need 10x, 100x or 1000x more amount of time and code.

Look at Big tech, this is what they are doing, they employ thousands workers that write millions of lines of code every day, only to make it work for every case in a world. And still can't compete with specialized solution.

Re: How Go mitigates supply chain attacks

#97

Earlier quoted context omitted.

> any new, poisoned version of libB Conversely, you will get any old security-buggy version of libB instead. Most package managers when adding a new dependency assume newer versions are "better" than older versions. Go's minimum version system assumes older is better than newer. I don't think there's any clear argument you can make on first principles for which of those is actually the case. You'd probably have to do…

> I don't think there's any clear argument you can make on first principles for which of those is actually the case. I don't understand why someone would try to argue from first principles here, it just seems like such a bizarre approach. Anyway, it's not just a security issue. Malicious packages and security fixes are only part of the picture. Other issues: - Despite a team's promise to use semantic versioning, poin…

> Other systems for determining the versions to use are much more unpredictable and hard to understand than estimated (look at Dart and Cargo)

I'm one of the co-authors of Dart's package manager. :)

Yes, it is complex. Code reuse is hard and there's no silver bullet.

Re: How Go mitigates supply chain attacks

#98

Earlier quoted context omitted.

Let's say my_app uses package foo which uses package bar. It turns out there is a security bug in bar. The bar maintainers release a patch version that fixes it. In most package managers, users of my_app can and will get that fix with no work on the part of the author of foo. I'm not very familiar with Go's approach but I thought that unless foo's author puts out a version of foo that bumps its minimum version depend…

> I thought that unless foo's author puts out a version of foo that bumps its minimum version dependency on bar, my_app won't get the fix. Version solving will continue to select the old buggy version of bar because that's the minimum version the current version of foo permits. That is incorrect. The application's go.mod defines all dependencies, even indirect ones. Raise the version there, and you raise it for all d…

That still implies that I need to know to update the version constraint of what may be a very deep transitive dependency, doesn't it?

Re: How Go mitigates supply chain attacks

#99

Earlier quoted context omitted.

Maybe I'm just not familiar with it enough but I don't see how merging a package manifest and lockfile into a single file is a net win. This means it's no longer clear which dependencies are immediate and which are transitive. It's not clear which versions are user-authored constraints versus system-authored version selections. For dependencies that are transitive, it's not clear why the dependency is in there and wh…

FWIW, there are two machine-formatted sections of go.mod -- the first for direct dependencies, the second section for indirect dependencies. (That's as of Go 1.17. Previously, that information was communicated via machine-generated comments in a single section).

That seems reasonable.

I think I personally lean towards keeping them in separate files entirely because I like a clearer separation between human-authored content and machine-derived state.

Re: How Go mitigates supply chain attacks

#100

Earlier quoted context omitted.

> I thought that unless foo's author puts out a version of foo that bumps its minimum version dependency on bar, my_app won't get the fix. Version solving will continue to select the old buggy version of bar because that's the minimum version the current version of foo permits. That is incorrect. The application's go.mod defines all dependencies, even indirect ones. Raise the version there, and you raise it for all d…

That still implies that I need to know to update the version constraint of what may be a very deep transitive dependency, doesn't it?

The version constraint is always listed in your top level go.mod file, so you know the dependency exists, no digging into the dependency tree required at all, and it’s not hidden in some lock file no one ever looks at. Plus, there are plenty of tools that help you with this problem, including the language server helping you directly in your editor and Dependabot on GitHub.

I’m not aware of any languages that send you an email when your dependencies are out of date, so yes, you need to check them. Dependabot can do this for you and open a PR automatically, which will result in an email, so this is one way for people to stay on top of this stuff even for projects they deploy but don’t work on every single week.

If you’re suggesting that indirect dependencies should automatically update themselves, then you are quite literally saying those code authors should have a shell into your production environments that you have no control over, compromising all your systems with a single package update that no one but the malicious author got to review. It is possible with tools like Dependabot to be notified proactively when updates are required so you can review and apply those, but it is not possible to go back in time and un-apply a malicious update that went straight to prod.

Repeatedly assuming that the Go core team never thought through the design of Go Modules and how it relates to security updates is such a strange choice. Go is a very widely used language with tons of great tooling.

Post reply on HN