Repository navigation
When A Gate Is Wrong
The design constraint is that a gate must express a binary, mathematically unambiguous condition. That makes every finding reproducible. It does not make every finding correct, and the README is unusually direct about the difference:
A gate can be perfectly deterministic about the bytes and still wrong about what they mean.
Three of its own examples, all real:
- A mock AWS key in a fixture. The bytes are an AWS key. The meaning is a test
-
A
0.0.0.0bind, which is the only correct choice inside a container -
A
docker.sockmount in the service whose entire job is talking to Docker
The current defaults come out of an adversarial sweep against 220 real repositories, and several categories ship off by default for exactly this reason. That is the honest response to the problem: not pretending the gates understand context, but tuning the defaults against reality and leaving the rest to you.
l0-git scans clean against itself, and its own .l0git.json shows how:
{
"gate_options": {
"secrets_scan": { "exclude_paths": ["server/known_non_secrets.go", "server/secrets.go", "..."] },
"connection_strings": { "exclude_paths": ["server/conn_gate.go", "README.md", "CHANGELOG.md"] },
"network_scan": { "exclude_paths": ["server/network_gate.go", "docs/gates/network-scan.md", "..."] },
"dead_placeholders": { "exclude_paths": ["server/dead_placeholders_gate.go", "README.md", "..."] }
}
}Read what that is. The secrets gate fires on the source code of the secrets gate, because that file necessarily contains the patterns it looks for. The network gate fires on its own tests. The dead-placeholder gate fires on its own documentation, which has to quote the placeholders it detects.
This is the false-positive class in its purest form, and the fix is the right one: a narrow exclude_paths naming the exact files, not turning the gate off.
Two things to take from it:
- Excluding a path is normal, not an admission of defeat, when the path legitimately contains what the gate hunts for
-
Keep the exclusion narrow.
server/secrets.gois a decision.server/**is a hole
| The situation | Use |
|---|---|
| One line is a legitimate exception |
Inline directive with a reason. It emits override_accepted, so the exception stays visible |
| A specific file or directory legitimately contains the pattern |
exclude_paths, naming it as narrowly as you can |
| The gate is right but its threshold does not fit this project |
A gate option, such as threshold_mb
|
| The finding is real but not urgent |
Downgrade the severity to info, keeping it in the audit layer |
| The gate does not apply to this project at all | ignore |
The order matters. Each row down that table hides more, and the first row hides nothing: it records the exception in the code, next to the line, with the reason, and still emits a finding saying an override was accepted.
Most linters treat a suppression as the end of the conversation. Here, suppressing produces a record.
The practical consequence: you can ask the store how many exceptions a project is carrying, which is a health metric that suppressions usually destroy. A repository with thirty accepted overrides is telling you something, and in a conventional setup that information does not exist.
If a gate fires on something that is not an exception but simply wrong, that is worth reporting rather than excluding. The gates are deterministic, so a false positive is reproducible from a small example, which makes it one of the easier bug reports to write and to fix.
The distinction: an exception is your repository legitimately doing something the gate is right to flag in general. A bug is the gate being wrong about the bytes themselves.
l0-git · Documentation · Gate reference · Issues · MIT · Deterministic about bytes, not about intent
In this wiki
Reference
Project