📱

Read on Your E-Reader

Thousands of readers get articles like this delivered straight to their Kindle or Boox. New articles arrive automatically.

Learn More

This is a preview. The full article is published at news.ycombinator.com.

Cursed Bundler: Using go get to install Ruby Gems

By Andrew NesbittHacker News: Front Page

Here’s a thought experiment. What if Ruby had require "github.com/rails/rails" and you used go get to fetch it? Set GOPATH to a Ruby load path, and Go’s module fetcher becomes your transport layer. The Go team did not intend this. But it works. Consider this a gift from the Ghost of Package Managers Yet to Come. The setup would look something like this: export GOPATH=/usr/local/lib/ruby/vendor_gems go get github.com/rack/ [email protected] Go fetches the module, and now you have: /usr/local/lib/ruby/vendor_gems/pkg/mod/ github.com/ rack/ [email protected] / lib/ rack.rb rack/ request.rb response.rb ... Build your load path from the lockfile: RUBYLIB=/usr/local/lib/ruby/vendor_gems/pkg/mod/github.com/rack/ [email protected] /lib Now require "rack" just works. Ruby doesn’t care how the files got there. The version resolution happened once, when you built the load path. And because each version lives in its own directory on disk, multiple versions coexist without conflict. Go’s filesystem layout handles what Ruby’s load path never did gracefully. Self-describing paths Go’s import path convention makes this possible. When you write import "github.com/foo/bar" , Go doesn’t look up “bar” in some central index. The path itself contains everything needed to find the code: the hosting domain, the org, the repo. It’s self-describing. Compare this to gem install foo , where “foo” is a magic string that only means something if you know to ask rubygems.org . Without the registry, “foo” is just noise. This decentralisation is unusual in package management. Most systems work the other way: short names resolve through a central index. npm’s lodash is meaningless without npmjs.com. PyPI’s requests is meaningless without pypi.org. Central indexes come with social costs too: governance, trust, gatekeeping, decisions about who gets to publish what. Go’s approach embeds the registry into the import path itself. You can host your own modules anywhere, and the path tells clients exactly where to find them. The proxy and the sumdb Now here’s where it gets interesting. Go doesn’t just fetch code from GitHub directly. It goes through proxy.golang.org , a caching proxy run by Google that mirrors every public Go module. And every module version gets an entry in sum.golang.org , a transparency log that records cryptographic hashes of module contents. First fetch wins: once a hash is logged, it’s permanent. This matters because a compromised maintainer can’t silently replace a version. If they try, the hash won’t match and every Go client will refuse the download. Anyone can audit the log for tampering. The security properties are genuinely good. When you run go get github.com/rack/ , here’s what actually happens: [email protected] 1. Ask proxy.golang.org for github.com/rack/ [email protected] 2. Proxy checks its cache, or fetches from GitHub 3. Proxy returns a zip file of the module contents 4. Go computes SHA-256 hash of the zip 5. Ask sum.golang.org: "what's the hash for this module?" 6. If first fetch ever: sumdb records the hash permanently 7. If seen before: verify hash matches the logged one 8. Unzip to $GOPATH/pkg/mod/github.com/rack/ [email protected] / Your Ruby gem just got the same integrity guarantees as...

Preview: ~500 words

Continue reading at Hacker News

Read Full Article

More from Hacker News: Front Page

Subscribe to get new articles from this feed on your e-reader.

View feed

This preview is provided for discovery purposes. Read the full article at news.ycombinator.com. LibSpace is not affiliated with Hacker News.

Cursed Bundler: Using go get to install Ruby Gems | Read on Kindle | LibSpace