foxguard 0.12.0

A security scanner as fast as a linter, written in Rust. 200+ built-in rules across 12 source languages.
Documentation
# Semgrep registry coverage

> Status: 2026-07-05. Generated by `cargo run --release --bin registry_coverage -- .registry-snapshot`.
> Living document — regenerate after loader changes.

Measures how well foxguard's existing Semgrep-compat YAML loader (`src/rules/semgrep_compat.rs`) handles a snapshot of the real [semgrep-rules](https://github.com/semgrep/semgrep-rules) registry. Each rule is classified by whether the loader produces a live matcher, and skips are attributed to the single unsupported operator/key that blocks them. This drives the parity roadmap: build the operator at the top of the priority list to unlock the most rules.

## Overall

| Metric | Value |
|---|---|
| Rule files scanned | 2070 |
| Files with YAML parse errors | 0 |
| Total rules | 2144 |
| Rules loaded OK | 2106 (98.2%) |
| Rules skipped | 38 (1.8%) |

**Headline load rate: 98.2%** (2106 / 2144 rules).

## Skip-reason histogram

Sorted by frequency. The reason names the operator/key that blocks the rule today.

| Skip reason | Rules | % of skipped | % of all rules |
|---|---:|---:|---:|
| `mode: taint (unsupported shape)` | 37 | 97.4% | 1.7% |
| `generic mode (languages: [generic])` | 1 | 2.6% | 0.0% |

## Priority order — operator/feature backlog

Matcher capabilities (implementable in `semgrep_compat.rs` / `semgrep_taint.rs`) ranked by how many registry rules each would unlock. These are independent of adding new language grammars. Build top-down.

| Rank | Capability to add | Rules unlocked |
|---:|---|---:|
| 1 | `mode: taint (unsupported shape)` | 37 |

Operator/feature gaps account for **37 rules** (1.7% of all rules). Closing the top of this list is the highest-leverage parity work that does not require a new parser.

## Priority order — missing language grammars

Rules foxguard cannot run because it has no tree-sitter grammar for the target language (a separate, heavier lift than matcher operators).

| Rank | Language to add | Rules unlocked |
|---:|---|---:|
| 1 | `generic mode (languages: [generic])` | 1 |

Missing-grammar gaps account for **1 rules** (0.0% of all rules).

## Per-language breakdown

Language is the rule's first declared language (js/ts/jsx/tsx collapsed to `javascript`, matching the loader).

| Language | Total | Loaded | Skipped | Load rate |
|---|---:|---:|---:|---:|
| python | 423 | 417 | 6 | 98.6% |
| hcl | 359 | 359 | 0 | 100.0% |
| javascript | 243 | 232 | 11 | 95.5% |
| regex | 237 | 237 | 0 | 100.0% |
| java | 131 | 127 | 4 | 96.9% |
| generic | 103 | 102 | 1 | 99.0% |
| yaml | 100 | 100 | 0 | 100.0% |
| go | 97 | 95 | 2 | 97.9% |
| ruby | 92 | 87 | 5 | 94.6% |
| php | 63 | 59 | 4 | 93.7% |
| solidity | 50 | 49 | 1 | 98.0% |
| csharp | 48 | 45 | 3 | 93.8% |
| dockerfile | 39 | 39 | 0 | 100.0% |
| ocaml | 34 | 34 | 0 | 100.0% |
| scala | 23 | 23 | 0 | 100.0% |
| c | 16 | 16 | 0 | 100.0% |
| kotlin | 15 | 15 | 0 | 100.0% |
| bash | 13 | 13 | 0 | 100.0% |
| apex | 12 | 11 | 1 | 91.7% |
| rust | 10 | 10 | 0 | 100.0% |
| elixir | 7 | 7 | 0 | 100.0% |
| json | 7 | 7 | 0 | 100.0% |
| swift | 6 | 6 | 0 | 100.0% |
| clojure | 5 | 5 | 0 | 100.0% |
| terraform | 5 | 5 | 0 | 100.0% |
| html | 4 | 4 | 0 | 100.0% |
| dart | 1 | 1 | 0 | 100.0% |
| xml | 1 | 1 | 0 | 100.0% |

## Top skip reasons per language

- **apex**: `mode: taint (unsupported shape)` (1)
- **csharp**: `mode: taint (unsupported shape)` (3)
- **generic**: `generic mode (languages: [generic])` (1)
- **go**: `mode: taint (unsupported shape)` (2)
- **java**: `mode: taint (unsupported shape)` (4)
- **javascript**: `mode: taint (unsupported shape)` (11)
- **php**: `mode: taint (unsupported shape)` (4)
- **python**: `mode: taint (unsupported shape)` (6)
- **ruby**: `mode: taint (unsupported shape)` (5)
- **solidity**: `mode: taint (unsupported shape)` (1)

---

Regenerate with `cargo run --release --bin registry_coverage -- <registry-dir>`. The registry snapshot is gitignored (`.registry-snapshot/`) and never committed.