-
Notifications
You must be signed in to change notification settings - Fork 0
Audit
letsgo audit [<tag>] [--repo owner/name] [--token]
A release is checked for vulnerabilities once, at the moment it is built. The
vulnerability database moves afterwards. letsgo audit re-runs govulncheck
against a release that already shipped, using that release's own source, and
records the answer on the release itself.
This is the question nothing else answers: not "is my current branch safe" — which CI already tells you — but "is the thing people are running right now still safe".
With no tag, audit checks the newest non-retracted stable release of each major
version. A repository on v1 and v2 gets both, and nothing older: the
releases people are told to use.
With a tag, it checks only that one.
letsgo audit # the current release of each major
letsgo audit v1.4.0 # one releaseThe source archive's digest is checked against the manifest first. A mismatch fails the audit and writes nothing — scanning bytes that are not the release's bytes would produce an answer about something else.
The scan then runs with the manifest's own build tags and targets, so what it reports is reachable in the binaries that actually shipped, not in the module in the abstract.
Results are appended to audit.json, an asset on that release:
{"schema": 1, "tag": "v1.2.0", "audits": [
{"at": "2026-09-24T03:17:00Z", "vulndb": "2026-09-23", "govulncheck": "v1.1.4",
"status": "affected",
"findings": [{"id": "GO-2026-1234", "module": "golang.org/x/net", "fixed": "v0.31.0"}]}
]}Entries are appended, never replaced. The history of what was known about a release, and when, is the useful part — a file that only ever shows today's answer cannot tell you whether a vulnerability was known before or after you deployed.
Running again with the same database date and the same findings appends nothing, so a nightly schedule does not grow the file for saying the same thing.
Nothing else on the release is touched.
Findings do not fail the command. The exit code is 0 whether a release is clean
or affected, and non-zero only when the audit could not run — a missing
govulncheck, an unreadable release, a tampered source archive.
That is deliberate. A scheduled audit that goes red the day an advisory lands gets muted within a week. The finding belongs in the record on the release, where anyone deciding whether to upgrade will see it.
letsgo verify prints the latest entry as an informational line:
· audit affected by GO-2026-1234 (as of 2026-09-24)
or clean (as of ...). It never changes the verify result: a release that
reproduces byte for byte is verified, and an advisory published afterwards does
not make the build a lie. audit.json is also not counted as an unexpected
asset.
A release made before letsgo — no manifest, no source archive — is skipped with a reason rather than failed. So is an immutable release, which cannot take the extra asset.
on: { schedule: [{ cron: "17 3 * * *" }] }
jobs:
audit:
runs-on: ubuntu-latest
permissions: { contents: write }
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with: { go-version-file: go.mod }
- uses: danielriddell21/letsgo-action@v1
with: { command: audit }contents: write is needed because the result is written back to the release.
Start here
Releasing
Checking
Extending
Running it
About