+++
title = "gomodsri"
summary = "Using tailscale/nardump to generate a go module SRI without building first"
date = 2024-03-10
category = "Nix"
+++
### The problem
When building a Go module with `nix`, generally you would use `buildGoModule`. Like other builders in the nix ecosystem, it uses a `vendorHash` property (or similar name).
Although there _have_ been various workarounds, the process typically involves building, noting the "expected" new hash, and replacing the old hash with the correct one before the build succeeds.
### The solution
My solution is inspired by [tailscale](https://tailscale.com), which I've adapted into a (nu)shell command for easier generic usage.
The original idea starts with the [nardump](https://github.com/tailscale/tailscale/tree/ad33e47270509345469af795aed65177df88904e/cmd/nardump) command. This is combined with the [vendoring](https://pkg.go.dev/cmd/go#hdr-Make_vendored_copy_of_dependencies) ability of Go modules to predict the `vendorHash`. Put together, it can look something like the following:
- [update-flake.sh](https://github.com/tailscale/tailscale/blob/ad33e47270509345469af795aed65177df88904e/update-flake.sh#L9-L10)
```sh
# [...] setting up a tempdirgo mod vendor -o "$OUT"go run tailscale.com/cmd/nardump --sri "$OUT" >go.mod.sri
# [...] cleanup```- [flake.nix](https://github.com/tailscale/tailscale/blob/ad33e47270509345469af795aed65177df88904e/flake.nix#L69)
```nix
pkgs.buildGoModule{# ...vendorHash=pkgs.lib.fileContents./go.mod.sri;# ...}```---
I've modified it to use across other projects as the following nushell function:
```nu
def gomodsri [] {
let tmp = (mktemp -d)
go mod vendor -o $tmp
let sri = (go run tailscale.com/cmd/nardump@latest --sri $tmp)
$sri | save -f go.mod.sri
rm -rf $tmp
echo 'nixpkgs.lib.fileContents ./go.mod.sri'
}
```<small>The echo at the end is because I always forget the invocation otherwise...</small>