Fail CI when your Go code or its dependencies gain access to new privileged operations: spawning processes, opening sockets, calling cgo, touching the filesystem. Built on google/capslock.
govulncheck tells you when a dependency has a CVE. capcheck tells you when a dependency (or your own code) gains the ability to do something it couldn't before: spawn a process, open a socket, write a file, call cgo. You check a baseline into your repo and CI fails when the capability set drifts.
go install github.com/git-pkgs/capcheck/cmd/capcheck@latest
Binaries for linux, darwin, and windows are attached to each release.
From the root of a Go module:
capcheck init ./...
This analyses your packages, writes a default capcheck.json, and writes the current capability set to capcheck.lock.json. Commit both.
Thereafter, in CI or locally:
capcheck ./...
Exit code 0 means no new capabilities. Exit code 1 means something changed and you'll see the offending call path:
capcheck: 1 new capability since baseline
github.com/you/app gained EXEC
cmd/server/main.go:42:3 main.run
handler/upload.go:88:5 handler.processImage
github.com/disintegration/imaging.Resize
os/exec.Command
Run `capcheck update` to accept, or remove the offending call path.
If the change is expected, run capcheck update ./... and commit the new lock file.
capcheck init [packages] analyse and write capcheck.json + capcheck.lock.json
capcheck check [packages] compare against the lock file (default command)
capcheck update [packages] re-analyse and overwrite the lock file
capcheck list [packages] print current capabilities, no baseline involved
packages defaults to ./....
Flags accepted by all commands:
-c, --config string path to capcheck.json (default "capcheck.json")
--baseline string path to capcheck.lock.json (overrides config)
-C, --dir string run as if in this directory
-f, --format string text, json, or github (default "text")
--granularity string package or function (overrides config)
--timeout duration analysis timeout (overrides config)
--strict fail on removed capabilities as well as added
--omit-paths do not record call paths (smaller lock file)
--ignore strings capabilities to ignore (repeatable, stacks with config)
capcheck.json is optional; missing keys take defaults.
{
"granularity": "package",
"timeout": "5m",
"baseline": "capcheck.lock.json",
"ignore": [
"FILES",
"NETWORK",
"REFLECT",
"RUNTIME"
]
}ignore matches hierarchically: an entry of MODIFY_SYSTEM_STATE also ignores MODIFY_SYSTEM_STATE/ENV. Most projects will want to ignore the noisy capabilities and watch only for EXEC, CGO, ARBITRARY_EXECUTION, UNSAFE_POINTER, and MODIFY_SYSTEM_STATE.
The full capability list is documented in capslock's docs.
granularity controls what counts as a change. At package (the default) you're told when a package gains a capability it didn't have. At function you're told when a new entry point reaches an existing capability, which is more precise but produces a much larger and more volatile lock file.
goos and goarch pin the platform the analysis runs as. capslock's results depend on which stdlib files are compiled in, so a lock file generated on macOS will not match one generated on Linux. init writes linux/amd64 by default since that is what most CI runs on; change it if your CI runs elsewhere, but pick one and stick with it.
Other keys: build_tags is passed through to package loading; capability_map points to a custom capslock classifier file if you want to extend the stdlib mappings; omit_paths drops the example call path from each lock entry, which shrinks capcheck.lock.json considerably at the cost of less helpful failure output.
- uses: git-pkgs/capcheck@v1
with:
packages: ./...The action installs capcheck, runs check --format github, and turns each new capability into an error annotation anchored at the first line of user code in the call path. On failure it also writes the human-readable diff to the job summary.
Inputs: go-version (default stable), capcheck-version (default latest), working-directory, packages, config, baseline, strict, ignore.
If you need to check multiple platforms, keep one config per platform and run the action in a matrix:
strategy:
matrix:
goos: [linux, darwin, windows]
steps:
- uses: git-pkgs/capcheck@v1
with:
config: capcheck.${{ matrix.goos }}.jsonwhere each capcheck.<goos>.json sets its own goos and baseline.
0 no new capabilities (or only removed ones, when not --strict)
1 capability set changed
2 analysis or configuration error
capcheck does not reimplement any analysis. It calls github.com/google/capslock/analyzer directly and the lock file is the same protojson that capslock -output=json produces, so you can inspect or regenerate it with the upstream tool. What capcheck adds is the config file, the diff, the exit codes, and the CI ergonomics.
MIT