Baseline and allowlist¶
When you adopt Lintel on an existing codebase, you usually have findings from day zero that you don't want to fix immediately but don't want to block commits either. Lintel gives you three layered tools for this, in increasing specificity.
| Tool | Scope | File | Audit trail |
|---|---|---|---|
paths.exclude |
Whole paths, never scanned | lintel.yaml |
YAML diff |
| Allowlist | Specific rule-on-path, suppressed | .lintel/allowlist.yaml |
YAML diff + required reason |
| Baseline | Accept everything currently found | .lintel/baseline.json |
JSON diff |
| Inline ignore | One line or block | In the source file | Required reason in comment |
Pick the least-broad tool for the job.
Allowlist¶
An allowlist entry permanently suppresses a (scanner, rule, optional file pattern) tuple. Every entry requires a reason string - reviewers can verify the judgment.
# .lintel/allowlist.yaml
version: 1
entries:
- scanner: gitleaks
rule: generic-api-key
files: ["testdata/**"]
reason: "Test fixtures contain placeholder keys."
- scanner: golangci-lint
rule: G104
files: ["internal/legacy/**"]
reason: "Legacy module scheduled for rewrite in Q3."
Managing from the CLI:
lintel ignore add --scanner gitleaks --rule generic-api-key \
--files 'testdata/**' --reason "Test fixtures"
lintel ignore refuses to add an entry without a reason.
Baseline¶
The baseline is a snapshot of every finding at a point in time. Anything in the baseline is treated as known and is excluded from the gate. Anything new fails the commit as usual.
lintel baseline # snapshot current findings into .lintel/baseline.json
lintel baseline --check # fail if the baseline is stale compared to current findings
The file is JSON - check it in alongside your code. A finding is considered "the same" across runs via its stable fingerprint (see first scan), so cosmetic code moves (renaming a function, shifting lines) still match as long as the (scanner, rule, file, normalized-message) tuple is preserved.
When you fix a finding, re-run lintel baseline to shrink the snapshot. CI should run lintel baseline --check on pull requests so a PR that fixes a finding doesn't accidentally let the same finding slip back in via the baseline.
Baseline vs. allowlist¶
- Use a baseline during adoption or a big refactor, when you want to freeze the backlog and fix it down over time. The baseline is meant to shrink.
- Use the allowlist for long-lived, per-rule exceptions you have actively judged acceptable. The allowlist is meant to be stable.
Reviewability
Both files are intentionally diffable in PRs. Reviewers should push back on growing baselines and vague allowlist reasons - they are the mechanism for preventing silent regressions.
Inline ignores¶
See severities § inline ignores. Inline directives are the most surgical tool and also the most visible at the point of change, so they are preferred for targeted, permanent accept-this-one-spot cases.
Precedence¶
Filters run in this order; once a finding is suppressed it does not propagate further:
flowchart LR
A[finding] --> B{paths.exclude}
B -- match --> Z[dropped]
B -- no --> C{allowlist}
C -- match --> Z
C -- no --> D{baseline}
D -- match --> Z
D -- no --> E{inline ignore}
E -- match --> Z
E -- no --> F{warn_paths}
F -- match --> G[severity downgraded]
F -- no --> H[gate]
G --> H
The full precedence and rationale are documented in spec.md §14.