hashwatch CLI — verify files#
Verify files against HashWatch’s known-good corpus from a terminal or a build pipeline, using the
open-source hashwatch CLI (Apache-2.0, standard-library Go) — a small, standalone binary with no
dependency on the HashWatch platform.
hashwatch verify <file>... # hash local file(s) and verify
hashwatch verify --url <url> # stream-download, hash, and verify
hashwatch verify --sha256 <hex> # verify a precomputed digest
cat file | hashwatch verify - # hash stdinFlags: --api-key (or $HASHWATCH_API_KEY) is optional — it widens the check to the full
known-good corpus; --offline checks against the local cache only; --refresh updates it now ·
--json · --quiet · --allow-unknown.
Exit codes make it easy to fail a build on an unverified artifact — run the binary as a build step and check its result:
| Code | Meaning |
|---|---|
0 | every input is known-good |
1 | at least one input is unknown |
2 | usage or runtime error |
Without a key vs. with an API key#
The CLI is free and needs no account — a key changes what it checks against, not whether it works:
| No key (free) | With an API key | |
|---|---|---|
| Checks against | Today’s public verified set — the current release of each tracked product (the same data as the dashboard) | The full known-good corpus — NIST NSRL/BinTrust (~72 M hashes) plus every release HashWatch has ever recorded |
| How | A local snapshot downloaded from the public feed at most once a day, then reused | A live, authenticated lookup per run |
| Works offline | ✓ — after the first run; force with --offline, update with --refresh | ✗ — needs the API |
| Older versions / past releases | ✗ — anything that isn’t today’s release comes back unknown | ✓ |
OS-shipped binaries (certutil.exe, bash, …) | ✗ | ✓ — covered by the NSRL corpus |
hashwatch verify ./installer.exe # free: today's verified set, cached locally
hashwatch verify --offline ./installer.exe # free: cache only, no network at all
export HASHWATCH_API_KEY=... # any paid tier's key works
hashwatch verify ./installer.exe # full corpus, incl. older releases + NSRLReading a free-mode unknown honestly: it means “not in today’s verified set” — the file may
still be a perfectly legitimate older release. If an unknown matters (CI gate, IR triage), add
a key so the full corpus can answer definitively. Keys are issued with any paid account — see
Tiers.
Install#
The CLI is Apache-2.0 and standard-library-only (no dependency on the HashWatch platform; no account
needed for the free path). Everything is served from cli.hashwatch.us — no public repo, no
auth. Pick one:
- Prebuilt binary (no Go needed):Downloads the binary for your OS/arch and verifies its SHA-256. Windows: grab the
curl -fsSL https://cli.hashwatch.us/install.sh | sh.exefrom https://cli.hashwatch.us/hashwatch. go install(Go 1.26+):The module path is a vanity import path served fromgo install cli.hashwatch.us/hashwatch@latestcli.hashwatch.us/hashwatch; the binary is namedhashwatch.- Build from source (from a checkout of the HashWatch repo):
cd cli && go build -o hashwatch . # then put ./hashwatch on your PATH - Container:
docker build -f Dockerfile.cli -t hashwatch-cli .
Use in CI/CD pipelines#
hashwatch verify is exit-code driven, so it drops into any pipeline as a supply-chain gate:
hash the artifact you built or downloaded and fail the job (exit 1) if it isn’t known-good. Install
it per the Install section above.
GitHub Actions#
# .github/workflows/verify.yml
name: verify-artifact
on: [push]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: '1.26' }
- run: go install cli.hashwatch.us/hashwatch@latest
- name: Verify the installer is a known-good release
env:
HASHWATCH_API_KEY: ${{ secrets.HASHWATCH_API_KEY }} # optional: widens to the full corpus
run: hashwatch verify ./dist/installer.exeThe job fails if the file isn’t known-good. Omit the env: block to run free against today’s public
verified set; add --allow-unknown to report without failing the build.
GitLab CI#
verify-artifact:
image: golang:1.26
variables:
HASHWATCH_API_KEY: $HASHWATCH_API_KEY # optional: full corpus (set as a masked CI/CD variable)
script:
- go install cli.hashwatch.us/hashwatch@latest
- hashwatch verify ./dist/installer.exePre-download supply-chain gate (any shell)#
Verify a third-party installer before you execute it — hash it straight from its URL, no local copy needed:
hashwatch verify --url https://example.com/tool-setup.exe \
|| { echo "refusing to run an unverified installer"; exit 1; }Or gate on an already-published digest without downloading anything:
hashwatch verify --sha256 "$EXPECTED_SHA256"Container image (no Go toolchain in the runner)#
docker build -f Dockerfile.cli -t hashwatch-cli .
docker run --rm -v "$PWD:/w" -w /w -e HASHWATCH_API_KEY \
hashwatch-cli verify ./dist/installer.exeJSON for downstream steps: add --json to emit { "results": [...], "unknown": N } for a later
step to parse; the exit code is unchanged, so the gate still works.