Command gosumcheck is a command-line utility that checks a go.sum file against a go.sum database server.
gosumcheck is a proof-of-concept command-line tool for verifying go.sum files against a checksum database. It is meant as a demonstration and should not be used in production scripts or continuous integration testing.
Important Limitations:
For production use, use the sumdb package to implement a proper client with caching and security checks.
go install golang.org/x/mod/gosumcheck@latestOr build from source:
git clone https://go.googlesource.com/mod
cd mod/gosumcheck
go buildgosumcheck [-h H] [-k key] [-u url] [-v] go.sum-h HChanges the tile height (default 8). The tile height determines the size of transparency log tiles downloaded from the server. Larger values reduce the number of HTTP requests but increase the size of each request.
Example:
gosumcheck -h 10 go.sum-k keyChanges the go.sum database server key. This should be the verifier key for the checksum database you want to verify against.
Example:
gosumcheck -k "sum.golang.org+033de0ae+Ac4zctda..." go.sum-u urlOverrides the URL of the server. Usually the URL is derived from the key name, but this flag allows explicit specification.
Example:
gosumcheck -u https://sum.golang.org go.sum-vEnables verbose output. Reports the URL and elapsed time for each server request, useful for debugging or understanding the verification process.
Example:
gosumcheck -v go.sumgo.sumPath to the go.sum file to verify. This is a required argument.
Verify a go.sum file using default settings:
$ gosumcheck go.sumIf successful, gosumcheck will silently exit. If there are errors, they will be printed to stderr.
See what gosumcheck is doing:
$ gosumcheck -v go.sum
GET https://sum.golang.org/latest (142ms)
GET https://sum.golang.org/lookup/golang.org/x/text@v0.3.0 (89ms)
GET https://sum.golang.org/tile/8/0/000 (56ms)
GET https://sum.golang.org/tile/8/0/001 (61ms)
...Use larger tiles to reduce HTTP requests:
$ gosumcheck -h 10 go.sumThis downloads tiles of height 10 (1024 hashes per tile) instead of the default 8 (256 hashes per tile).
Verify against a custom checksum database:
$ gosumcheck -k "myserver.com+abc123+..." -u https://sumdb.myserver.com go.sumCreate a minimal go.sum with just the modules you want to check:
$ grep "golang.org/x/text" go.sum > text.sum
$ gosumcheck text.sumThe go.sum file contains checksums for module downloads. Each line has the format:
<module> <version> <hash>
<module> <version>/go.mod <hash>Example go.sum:
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=Each module version has two lines:
Parse go.sum: Reads the go.sum file and extracts module paths and versions
Fetch Latest Tree: Downloads the latest signed tree from the checksum database
Verify Signatures: Verifies the tree signature using the server's public key
Lookup Checksums: For each module in go.sum:
Compare: Compares checksums from go.sum with those from the database
Report: Prints any mismatches or errors
Every run downloads all data fresh:
$ time gosumcheck go.sum
# Takes several seconds
$ time gosumcheck go.sum
# Takes several seconds again (no caching)For production use, implement caching using the sumdb.Client with appropriate ClientOps.
gosumcheck does not set exit status to indicate success or failure:
$ gosumcheck go.sum
$ echo $?
0 # Always 0, even if errors occurredThis makes it unsuitable for CI/CD pipelines. For automated testing, use the sumdb package directly.
gosumcheck cannot detect:
A proper client implementation should cache tree states and detect inconsistencies.
For production use, implement a proper client:
package main
import (
"context"
"log"
"golang.org/x/mod/sumdb"
)
type ProductionClientOps struct {
// Implement caching, monitoring, etc.
}
func (ops *ProductionClientOps) ReadRemote(path string) ([]byte, error) {
// Implement with retries, timeouts, metrics
}
func (ops *ProductionClientOps) ReadConfig(file string) ([]byte, error) {
// Persistent storage
}
func (ops *ProductionClientOps) WriteConfig(file string, old, new []byte) error {
// Atomic writes
}
func (ops *ProductionClientOps) ReadCache(file string) ([]byte, error) {
// Persistent cache
}
func (ops *ProductionClientOps) WriteCache(file string, data []byte) {
// Persistent cache
}
func (ops *ProductionClientOps) Log(msg string) {
log.Println(msg)
}
func (ops *ProductionClientOps) SecurityError(msg string) {
log.Fatalf("SECURITY ERROR: %s", msg)
}
func main() {
client := sumdb.NewClient(&ProductionClientOps{})
// Verify checksums
lines, err := client.Lookup("golang.org/x/text", "v0.3.0")
if err != nil {
log.Fatal(err)
}
// Compare with go.sum
// ...
}Use -v to see all HTTP requests:
$ gosumcheck -v go.sum
GET https://sum.golang.org/latest (142ms)
→ Downloaded latest signed tree
GET https://sum.golang.org/lookup/golang.org/x/text@v0.3.0 (89ms)
→ Looked up module checksum
GET https://sum.golang.org/tile/8/0/000 (56ms)
→ Downloaded transparency log tileCompare different tile heights:
# Default (height 8 = 256 hashes/tile)
$ time gosumcheck go.sum
# May make more requests
# Larger tiles (height 10 = 1024 hashes/tile)
$ time gosumcheck -h 10 go.sum
# Fewer requests, more data per requestTest against a local checksum database:
$ gosumcheck -u http://localhost:8080 -k "localhost+..." go.sumThe module version isn't in the checksum database. This could mean:
The checksum in go.sum doesn't match the database. This could indicate:
Action: Regenerate go.sum:
$ rm go.sum
$ go mod tidyThe server's signature doesn't verify. This could mean:
-k-uThe gosumcheck source code is available in the golang.org/x/mod repository:
golang.org/x/mod/gosumcheck/main.goUse it as a reference for understanding the checksum verification process, but implement your own production client using the sumdb package with proper caching and monitoring.