Documentation
¶
Overview ¶
Package main implements the GNU build-ID tool used by the Bazel `content_build_id` rule (see defs.bzl).
Why this exists ¶
rules_go links every Go binary with `-buildid=redacted` for reproducibility, and since Go 1.24 the Go linker derives the ELF `.note.gnu.build-id` note from that Go build ID by default (`-B gobuildid`). A constant input yields a constant note, so every aether Go binary ever built carried the same GNU build-ID (498919aff001d8366249403a2544fba2d833084f) no matter what code was in it (issue #651). Profilers that join samples to symbols purely by build-ID — the Pyroscope eBPF symbolizer does — then silently symbolize one binary against another binary's offsets.
The first fix (#652) rewrote the note to the release commit SHA. That traded one collision for another: a commit produces *seven* released ELFs, so all seven ended up sharing a single ID (issue #653). A GNU build-ID identifies a *linked object*, not a source revision.
What this tool writes ¶
The ID is derived from the binary's own bytes, which is what `ld --build-id=sha1` does natively and what the custom Envoy now gets from the linker:
build_id = SHA-1( image bytes, with the 20-byte build-ID descriptor
field replaced by 20 zero bytes )
Zeroing the descriptor before hashing is what makes the value well defined: the descriptor is the one field the hash is about to overwrite, so excluding it removes the circular dependency. Three properties follow, and all three are covered by unit tests:
- deterministic — the same image bytes always yield the same ID, so the ID is remote-cache-friendly and reproducible;
- idempotent — writing the ID changes only the descriptor, which the hash ignores, so re-running the tool on an already-written binary computes and writes exactly the same 20 bytes;
- collision-free in practice — two ELFs that differ anywhere outside the descriptor get different IDs, which is precisely the #653 requirement.
Nothing else in the image moves: the descriptor is exactly 20 bytes wide, the same width as a SHA-1 digest, so the note is patched in place.
Release traceability does not live in this note. It lives in the `--stamp` x_defs version information and in the image tags; the ELF note is the symbolizer's key and nothing else.