Does your green actually check anything?
voidguard is a static scanner for void guards —
checks that are present, plausible, and verify nothing. It asks one question per
guard: could this, as configured, ever be observed to fail? — and shows its
evidence for every answer.
pip install voidguard voidguard scan .
name: voidguard on: [pull_request] permissions: contents: read pull-requests: write jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: driivai/voidguard@v0
Report-only by default — it comments findings on the PR and never fails
your build unless you opt in with fail-on. Requires Python 3.11+
for the CLI; the Action brings its own.
A guard that fails is doing its job.
A guard that's absent is at least honest.
The dangerous one runs, reports green, and verifies nothing.
What it catches
python -I/-E, which
drop them; workflow env set and never read; a Docker ARG consumed after FROM
without re-declaration.if: requiring an event the workflow's triggers never
deliver; schedules with no run on the record; golden-file assertions whose path
matches nothing.Every verdict — VOID, WARN, or an honest UNKNOWN — carries its enumerated search set: what was searched, what was found, absent conventional locations named as absent. A tool about unverified claims does not get to make any.
What it cannot catch
The taxonomy this tool comes from has seven instance-types. voidguard v0 detects the shapes of four. It would not have caught the other three:
- Semantic voids — a verdict typed nullable so “nothing” can be mistaken for a value, or a field the code carries but nothing ever persists. These need type-flow and data-flow analysis, not file-shape analysis.
- Process voids — a human approval gate that a merge routed around while every check was green. No scanner catches a decision that nobody waited for.
- Anything requiring execution — voidguard never runs your code. A guard that runs and is wrong is outside its question; it only asks whether a guard could ever be observed to fail at all.
Where static analysis cannot decide, the verdict is UNKNOWN with the reason — because a scanner that overclaims void guards is itself a void guard.
Where it comes from
In one week, one repository turned up seven guards that were present, plausible, and void — a core integrity test that had silently skipped in CI since inception, a type gate that passed while checking nothing, an approval step a merge walked straight past. Every one of them was green. voidguard is the generalization of the sweep that found them.