Help us shape the future of Go! Take the 2026 Go Developer Survey

buildstamp

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2026 License: BSD-3-Clause Imports: 6 Imported by: 0

README

buildstamp

Read the Go build information of any binary — WebAssembly included — and fail one that was built from a modified tree.

go version -m and debug/buildinfo read ELF, Mach-O, PE, XCOFF and Plan 9 files. Given a .wasm file they answer unrecognized file format. The go command writes the same module information into every binary, as text between two 16-byte sentinels (infoStart and infoEnd in cmd/go/internal/modload/build.go). buildstamp finds that text and hands it to runtime/debug.ParseBuildInfo, so one reader works for every format.

Why

A release built in CI after something wrote into the checkout is stamped vcs.modified=true. Its main module version reads v0.0.0-…-<commit>+dirty, and it is not the commit it claims to be. go-wasmcontainers/dashboard v0.4.2 shipped that way: its Pages job wrote _site/ inside the work tree. buildstamp is the gate that would have refused it.

Command

go install github.com/go-fleettools/buildstamp/cmd/buildstamp@latest

buildstamp check [--revision SHA] FILE...   # exit 1 unless every file is clean
buildstamp show FILE...                       # print the build information

A file is clean when all of these hold:

  • it has a vcs.revision;
  • its vcs.modified is false;
  • with --revision, its revision is the commit given.

Exit status:

Status Meaning
0 every file is clean
1 at least one file is not (every file is still reported)
2 a file could not be read, or it carries no Go module information

In a workflow, build outside the checkout and gate before you publish:

- run: GOOS=js GOARCH=wasm go build -o "$RUNNER_TEMP/site/app.wasm" ./cmd/app
- run: go run github.com/go-fleettools/buildstamp/cmd/buildstamp@v0.1.0 check --revision "$GITHUB_SHA" "$RUNNER_TEMP/site/app.wasm"

Package

import "github.com/go-fleettools/buildstamp"

bi, err := buildstamp.ReadFile("app.wasm") // or buildstamp.Read(bytes)
err = buildstamp.Clean(bi, os.Getenv("GITHUB_SHA"))
rev, _ := buildstamp.Setting(bi, "vcs.revision")

The Go version is not part of the module information, so bi.GoVersion is empty.

Safety

A binary is untrusted input, so every read is bounded:

  • the module information is read at most 1 MiB past its start sentinel;
  • a file over 1 GiB is refused before it is read;
  • Read is fuzzed (FuzzRead) in CI.

Tests

  • Every statement is covered (covblocks).
  • The tests build a real js/wasm binary twice in a repository of their own: once from a clean commit, and once after an untracked file appears. The clean build must pass at that commit, and the dirty one must fail and say +dirty.
  • CI runs the tool on its own clean build, and on a planted dirty one, which must exit with status 1.

License

See LICENSE.

Documentation

Overview

Package buildstamp reads the Go build information embedded in a binary of any format — js/wasm and wasip1/wasm included — and judges whether it was built from a clean commit.

debug/buildinfo reads ELF, Mach-O, PE, XCOFF and Plan 9 files only; given a WebAssembly module it answers "unrecognized file format", and so does `go version -m`. The go command writes the module information into every binary as text between two 16-byte sentinels (infoStart and infoEnd in cmd/go/internal/modload/build.go), in the format runtime/debug.ParseBuildInfo reads. This package finds the text between the sentinels and hands it to the standard parser, which works the same whatever the container format.

The question it exists to answer: a release built in CI after something wrote into the checkout (an output directory, a generated file) is stamped vcs.modified=true and its main module version gets a "+dirty" suffix — it is not the commit it claims to be. Clean reports that.

Index

Constants

View Source
const MaxFile = 1 << 30

MaxFile bounds what ReadFile reads.

View Source
const MaxInfo = 1 << 20

MaxInfo bounds the module information: a binary is untrusted input, and a start sentinel with no end nearby must not make the parser read megabytes.

Variables

View Source
var ErrNoInfo = errors.New("no Go module information in the file")

ErrNoInfo is returned for a file that carries no Go module information (not a Go binary, or one built without module support).

Functions

func Clean

func Clean(bi *debug.BuildInfo, want string) error

Clean reports an error unless bi was stamped from a version-controlled tree with no modification — vcs.revision present and vcs.modified=false — at revision want when want is not empty.

func Read

func Read(bin []byte) (*debug.BuildInfo, error)

Read returns the build information embedded in bin. The Go version is not part of the module information and is left empty.

func ReadFile

func ReadFile(path string) (*debug.BuildInfo, error)

ReadFile reads the build information of the file at path (at most MaxFile bytes).

func Setting

func Setting(bi *debug.BuildInfo, key string) (string, bool)

Setting returns the value of the build setting key, and whether it is set.

Types

This section is empty.

Directories

Path Synopsis
cmd
buildstamp command
Command buildstamp reads the Go build information of binaries — wasm included, which `go version -m` cannot — and fails one built from a modified tree.
Command buildstamp reads the Go build information of binaries — wasm included, which `go version -m` cannot — and fails one built from a modified tree.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL