Skip to content

Allowlists

The principle

Some findings can't be fixed immediately — a third-party vulnerability awaiting a vendor patch, a designed exception with an open tracking issue, a known false positive while a gate's predicate is being refined.

The framework allows these to be suppressed via per-gate allowlist files. But every allowlist entry must have:

  1. A tracking issue (e.g. MAT-1234) — proves someone owns the resolution.
  2. A hard expiration date — proves the suppression is temporary.

The runner validates every allowlist on every run. Past-expiry entries become hard failures. The build won't pass until the entry is renewed (with a fresh expiration) or the underlying finding is fixed.

This is the difference between a healthy and an unhealthy gate culture. An unbounded allowlist is just unenforced rules. A bounded one shrinks monotonically.

File location

Sibling to the gate file:

packages/components/src/cards/__gates__/
  card-action-targets.gate.ts
  card-action-targets.allowlist.json

The runner reads the allowlist at <gate-base>.allowlist.json automatically.

File shape

{
  "entries": [
    {
      "key": "<finding-fingerprint>",
      "fingerprint": "<finding-fingerprint>",
      "reason": "Vendor patch not yet released; switching libs in Q3.",
      "tracking_issue": "MAT-1234",
      "expires_at": "2026-09-01",
      "added_by": "alice",
      "added_at": "2026-05-15"
    }
  ]
}
FieldRequiredNotes
keyyesStable identifier. Usually equals the finding's fingerprint.
fingerprintnoIf provided, match by fingerprint; otherwise match by key.
reasonyesPlain English, ≤240 chars. Future you needs to read this.
tracking_issueyesAn issue tracker reference (e.g. MAT-1234, GitHub URL).
expires_atyesISO date (YYYY-MM-DD). Typically 60–90 days out.
added_byyesAuthor handle / email.
added_atyesISO date of when the entry was added.

How matches work

The runner runs the gate, collects its Finding[], then for each finding:

  1. Look up the gate's allowlist (if present).
  2. If any entry has fingerprint === finding.fingerprint or key === finding.fingerprint, the finding is suppressed (does not contribute to exit code).
  3. The suppressed count is reported in the gate's summary (allowlistApplied) so over-suppression is visible.

What goes wrong if you skip a field

  • No tracking_issue — the runner throws on allowlist load with a clear error. Add the issue or remove the entry.
  • No expires_at — same. There are no permanent allowlist entries.
  • Past-expiry expires_at — the runner emits a blocking Finding ("allowlist entry X expired on Y"). Either renew the entry (with a new tracking issue and a new horizon) or fix the underlying finding.

How a healthy allowlist looks

gate                    allowlist_size   max_age_days   expiring_within_30
card-action-targets             0              -              -
dependency-audit                1             47              0
secret-scan                     0              -              -

Small, recent, no imminent expirations. The scorecard at /testing/scorecard charts this per gate.

On this page