Administrator Guide

<!-- Copyright (c) 2026 Pierre Gronau, ndaal in Cologne -->

# Administrator Guide

## Installation

nvulnlookup is a single binary with no
external dependencies. No Redis, PostgreSQL,
or Meilisearch needed. The Go `csaf_downloader`
binary is no longer required (replaced by a
native Rust CSAF downloader in v0.1.27).

```bash
# Build release binary
cargo build --release -p vl-web --features quic

# Binary located at:
# target/release/vl-web  (11 MB)
# target/release/vl-cli  (7.4 MB)
```

### Ansible Deployment

An Ansible role is provided at
`tools/ansible/roles/nvulnlookup/`:

```bash
ansible-playbook -i inventory site.yml \
    -e nvulnlookup_version=1.2.66
```

The role handles user creation, binary
download, TLS certificate provisioning,
systemd service setup, firewall rules,
AppArmor profiles, and log rotation.

### Replacing the binary on a deployed host ("Text file busy")

The Ansible role swaps the binary safely on every run (it stages to a
temporary path and renames), so a normal `ansible-playbook` redeploy
never hits this. The error below only appears when you copy a new
build **over the running `vl-web`** by hand:

```text
'vl-web' -> '/opt/nvulnlookup/bin/vl-web'
cp: cannot create regular file '/opt/nvulnlookup/bin/vl-web': Text file busy
```

`Text file busy` is the kernel's `ETXTBSY`. Linux refuses to truncate
or overwrite the file backing a currently-executing program, and `cp`
— like `install` — opens the destination with `O_TRUNC`, i.e. it
overwrites in place. The running `vl-web` image is mapped from exactly
`/opt/nvulnlookup/bin/vl-web`, so the write is rejected. The fix is to
**not** overwrite the file in place.

**Option A — stop the service, replace, start (simplest).** With the
service stopped the path is no longer busy, so `install`/`cp` succeed:

```bash
sudo systemctl stop nvulnlookup
sudo install -m 0755 -o root -g root ./vl-web /opt/nvulnlookup/bin/vl-web
sudo systemctl start nvulnlookup
```

**Option B — atomic replace without downtime.** `rename(2)` swaps a
directory entry without touching the inode the running process has
mapped, so it is never `ETXTBSY`. Stage the new build under a temp
name **in the same directory** (a rename is only atomic within one
filesystem), then move it into place and restart:

```bash
sudo install -m 0755 -o root -g root ./vl-web /opt/nvulnlookup/bin/.vl-web.new
sudo mv -f /opt/nvulnlookup/bin/.vl-web.new /opt/nvulnlookup/bin/vl-web
sudo systemctl restart nvulnlookup   # load the new image
```

The old binary keeps running from its now-unlinked inode until the
service is restarted; the `restart` above launches the new image.

Do **not** `rm` the live binary and then `cp` the new one — between the
two commands there is a window with no binary on disk, and a crash
there leaves the host with nothing to (re)start. The temp-file +
`mv -f` rename has no such gap. Confirm the swap after (re)starting:

```bash
/opt/nvulnlookup/bin/vl-web --version
systemctl status nvulnlookup --no-pager
```

> For routine upgrades prefer the Ansible role
> (`ansible-playbook … -e nvulnlookup_version=1.2.66`); it performs the
> atomic swap and the post-deploy version check for you. The manual
> steps above are for break-glass / single-host fixes.

## Build Release

The "release" workflow produces the multi-target binary set
(`vl-web` + `vl-cli` for `x86_64-apple-darwin`,
`aarch64-apple-darwin`, `x86_64-unknown-linux-gnu`, and
`aarch64-unknown-linux-gnu`), the matching tarballs +
SHA-256/SHA-512/SHA-3-512 sidecars, the Debian/RPM packages, and
refreshes the binary fixtures committed to the Ansible roles.
Run these three scripts in order — each one writes the inputs the
next one expects.

> **Working directory.** All paths below are relative to the
> repository root. The scripts are safe to invoke from any cwd
> because they resolve their own `SCRIPT_PATH` first.

### Sequence

| # | Stage | Script | Purpose |
| --- | --- | --- | --- |
| 1 | Cross-compile every target | `vulnerability-lookup-rs/scripts/build_all_targets.sh` | Cross-compilation build for `vulnerability-lookup-rs` (4 production triples).  Produces `target/<triple>/release/vl-web` + `vl-cli` per triple. |
| 2 | Package the release artefacts | `vulnerability-lookup-rs/release/create_release.sh` | Tar each triple's binaries into `release/v<X.Y.Z>/<triple>/<bin>.tar.gz` and emit per-file `.sha-256`, `.sha-512`, `.sha3-512` sidecars + aggregate `SHA-256SUMS.txt` / `SHA-512SUMS.txt` / `SHA3-512SUMS.txt` digests.  Also builds the .deb / .rpm packages. |
| 3 | Update Ansible role binary fixtures | `vulnerability-lookup-rs/scripts/update_ansible_role.sh` | Copy the freshly built binaries + sidecar trios into both `tools/ansible/roles/{nvulnlookup,nvulnlookuptesting}/files/`.  Also refreshes the role `defaults/main.yml` version pin if the workspace version moved. |

```bash
# Stage 1 — cross-compile (zigbuild, ~12-25 min on a 16-core host)
bash vulnerability-lookup-rs/scripts/build_all_targets.sh

# Stage 2 — package + checksum
bash vulnerability-lookup-rs/release/create_release.sh

# Stage 3 — refresh Ansible role binary fixtures
bash vulnerability-lookup-rs/scripts/update_ansible_role.sh
```

Each script self-skips with rc=0 when its own preconditions are
missing (e.g. missing target triple, missing release tarball,
missing `cargo zigbuild`) so a partial host environment surfaces
the gap instead of silently producing a broken release.

### Verify

Required smoke gates (run in this order):

| Stage | Tool | Purpose |
| --- | --- | --- |
| Static-asset GUI capture | `scripts/verify_static_assets_debian13.sh` | Boot a Debian 13 VM via Vagrant, install the role using the just-built binaries, then drive headless Chrome to capture **39 PNGs** of every navbar-reachable page (`/`, `/stats`, `/dashboard`, `/recent`, `/kev`, all dashboards, CNA Scorecard, Info & Annotations submenus).  Output → `documentation/screenshots/gui/`. |
| API reference smoke | `scripts/test_example_reference_implementation_for_api_access.py` | pytest + Hypothesis suite for `scripts/example_reference_implementation_for_api_access.py`.  Validates every endpoint contract a downstream consumer would hit (CSV / TSV / TXT / JSON / array inputs → recent + KEV + EPSS feeds → SARIF + HATEOAS payloads). |

```bash
# Static-asset capture (Vagrant + headless Chrome, ~12-15 min on
# first run; ~5-7 min on a re-run with the box cached)
bash scripts/verify_static_assets_debian13.sh

# API reference test sweep (requires a running vl-web on :8080)
pytest scripts/test_example_reference_implementation_for_api_access.py
```

Optional broader verify — fan out the same static-asset capture
across **six container distros** (Debian 12 / 13 / 14, AlmaLinux
9 / 10, Alpine) under Molecule + Podman:

```bash
bash scripts/verify_static_assets_molecule.sh
```

This produces 39 PNGs × 6 distros = **234 screenshots** under
`documentation/screenshots/gui/*_molecule_<distro>_<ISO>.png` and
takes ~25-40 min on a fresh container cache.

Optional role-test verify — boot a Debian 13 VM, deploy
nvulnlookup with hardening off, and exercise the role's
`tests/test.yml` master playbook with a user-selected toggle set
(default: `cargo_license` + `sqlmap` + `betterleaks` +
`lonkero_scan` + every `service_handling` subtest):

```bash
bash scripts/verify_role_tests_debian13_selected.sh
```

Override the enabled set with `VERIFY_ENABLED_TESTS="..."`
(space-separated toggle slugs without the `nvulnlookup_run_`
prefix). Archive at
`documentation/role_tests/<ISO-8601-utc>/`.

> **Final step is operator-driven.** Tag the release in git
> (`git tag -a v<X.Y.Z>`) and push the tag + the release
> directory once all the gates above are green. CI does NOT
> create the tag automatically — the human signing the release
> always does.

## Self-Update (`vl-cli` and `vl-web`)

Both binaries can upgrade themselves in place from ndaal's own GitLab
release host (`gitlab.com/vPierre/ndaal_public_nvulnlookup`). The
shared `vl-updater` crate downloads the per-triple release tarball
`nvulnlookup-<version>-<triple>.tar.gz`, verifies it against the
release's published `SHA-256SUMS.txt`, extracts the requested binary
from the archive, and atomically swaps the running executable.

The download uses the **same aws-lc-rs / TLS-1.3-only** transport as
the vl-web server — no second crypto provider, no TLS 1.2, no
`reqwest`, no OpenSSL. Redirects are followed but an `http://`
scheme downgrade is refused, and both the manifest and the tarball
download are size- and time-bounded.

### Commands

```bash
# CLI — check only (read-only), or install:
vl-cli self-update --check
vl-cli self-update

# Server — one-shot flags that run BEFORE the listeners bind (an
# update check never boots the server or opens the database):
vl-web --check-update
vl-web --self-update
```

`--check` / `--check-update` prints `… is up to date.` when the
running version is the newest published (or a from-source build ahead
of it), or `A newer release is available: X -> Y` otherwise. An
unreachable host is reported, not treated as an error (exit 0), so a
check never breaks a boot path or a script.

### Cryptographic integrity (CWE-494)

Before the downloaded tarball is allowed to overwrite the running
binary, its SHA-256 is checked against the `SHA-256SUMS.txt` manifest
published *in the same release*. If the manifest is absent, or it
does not list this triple's tarball, or the digest does not match,
the update aborts and the on-disk binary is left untouched. The exact
release tag that was checksummed is the exact release that is
installed (no re-selection window).

**Honest trust model.** The checksum is fetched over the same TLS 1.3
channel from the same release, so it defends against a corrupted,
truncated, asset-swapped, or man-in-the-middled download — it is
**not** a signature. An attacker who could rewrite *both* the tarball
and its `SHA-256SUMS.txt` at the source would defeat it. Detached
ed25519 signing (`self_update`'s `signatures` feature) is a possible
future hardening; today the pipeline ships checksums, not signatures,
so checksum verification is the honest ceiling.

### Policy opt-out

For package-managed or locked-down installs, forbid the binary from
replacing itself with `--no-self-update` or a truthy
`VL_NO_SELF_UPDATE` environment variable (anything but empty or `0`).
Either makes `--self-update` refuse with a non-zero exit; the
read-only `--check` / `--check-update` stays available.

## Quickstart: Filling the Database

A fresh deployment ships an empty database.
Seed it in three deterministic stages — fetch
NDJSON dumps from upstream, compress them for
durable storage, then import + verify into the
local DB. Every stage emits and re-checks
three-family hash sidecars (`.sha-256`,
`.sha-512`, `.sha3-512`) so a downstream
consumer can prove byte-for-byte integrity
without re-running the upstream pipeline.

> **Working directory.** Run the three scripts
> from `vulnerability-lookup-rs/`. Paths in
> the table below are relative to that
> workspace root.

| # | Stage | Script | Purpose |
| --- | --- | --- | --- |
| 1 | Fetch | `vulnerability-lookup-rs/scripts/fetch_dumps.sh` | Security-hardened downloader for the 76 CIRCL/OSV/national NDJSON dumps. Writes the dump trio (`<name>.ndjson` + 3 sidecars) into `dumps/`. Idempotent: skips dumps already up to date and back-fills missing sidecars on re-run. |
| 2 | Compress | `vulnerability-lookup-rs/scripts/compress_dumps.sh` | "Compress each NDJSON dump file individually with 7zip at maximum compression. Each archive is verified after creation (listing + integrity test). Results are stored in `dumps_archive/`." Self-checks every sidecar via `shasum -c` / `sha3sum -c`; refuses partial writes. |
| 3 | Import + verify | `vulnerability-lookup-rs/scripts/import_and_verify_dumps.sh` | "Import all NDJSON dump files into the database, then verify each source's entry count matches the JSON line count. If no dump files exist in `dumps/`, automatically decompress from `dumps_archive/` with integrity verification." Strict mode is default — any partial sidecar set or hash mismatch aborts the run. |
| 4 | Export (reverse) | `vulnerability-lookup-rs/scripts/export_sources_ndaal_dumps.sh` | Exports each DB source back to its own NDJSON dump (`<source>_ndaal_<TIMESTAMP>.ndjson`) via the live `/api/v1/vulnerabilities` API, generates the full **5-sidecar contract** (`.sha-256`/`.sha-512`/`.sha3-512`/`.blake3-512`/`.shake256-512`), and **verifies every dump BEFORE storing it** — non-empty, per-line JSON schema, internal entry-count consistency, and a 25-entry byte-compare against the DB. A dump that fails any check is discarded (never stored). Emits SARIF 2.1.0 + Markdown reports to `documentation/dumps/export/<TIMESTAMP>/`. Requires the vl-web server running; `EXPORT_STRICT=1` exits non-zero on any verification failure; `--source <S>` restricts to one source. |
| 5 | Import (per-source, verified) | `vulnerability-lookup-rs/scripts/import_sources_ndaal_dumps.sh` | Imports each source's NDJSON back into the redb, picking the **newest usable dump via a fallback chain** (newest `dumps/<S>*.ndjson` → older candidate → `dumps_archive/<S>.7z`, decompressed). Validates all **5 sidecars** (mandatory `.sha-256`/`.sha-512`/`.sha3-512` trio + optional `.blake3-512`/`.shake256-512`) and **verifies BEFORE import** — per-line JSON schema, entry count, and **no duplicate ids in-file**; a dump failing any check is rejected and the next candidate tried (never imported). Because redb is single-writer, it manages the lock: stops a running `vl-web`, imports via `vl-cli import-dumps` (idempotent upsert → no DB duplicates), restarts the server, then confirms with a 25-entry DB compare. Emits SARIF 2.1.0 + Markdown to `documentation/dumps/import/<TIMESTAMP>/`. `--source <S>`, `--no-manage-server`, `--no-db-compare`; `IMPORT_STRICT=1` exits non-zero on any failure. |

Run them in sequence:

```bash
cd vulnerability-lookup-rs

# 1. Fetch ~10 GB of NDJSON dumps + sidecars
bash scripts/fetch_dumps.sh

# 2. Compress every dump into dumps_archive/<name>.7z
bash scripts/compress_dumps.sh

# 3. Import + verify (auto-extracts from archive
#    if dumps/ is empty)
bash scripts/import_and_verify_dumps.sh

# 4. (reverse) Export each DB source to its own verified
#    ndaal dump + 5 sidecars + SARIF/Markdown report
#    (needs the vl-web server running). Dumps that fail
#    verification are discarded, never stored.
bash scripts/export_sources_ndaal_dumps.sh
#    one source, fail the run on any verify error:
EXPORT_STRICT=1 bash scripts/export_sources_ndaal_dumps.sh --source nvd
```

Each script self-skips when its prerequisites
are missing (e.g. `7z`, `jaq`, `sha3sum`) so
a partial host environment still gets a clear
error rather than a silent half-run. See
[Bulk Import (CIRCL Dumps)](#bulk-import-circl-dumps)
below for the full per-stage detail
(provenance caveats, strict-vs-bridge mode,
sidecar limitations, example output).

## Configuration

Create `config/generic.json` (optional --
defaults are used if absent):

```json
{
    "website_listen_ip": "::",
    "website_listen_port": 8080,
    "quic_listen_port": 8081,
    "data_dir": "data",
    "loglevel": "INFO",
    "fulltextsearch": false,
    "user_accounts": true,
    "local_instance_name": "",
    "local_instance_uuid": ""
}
```

Or use `config/generic.toml`:

```toml
website_listen_ip = "::"
website_listen_port = 8080
quic_listen_port = 8081
data_dir = "/var/lib/nvulnlookup/data"
loglevel = "INFO"
```

### Configuration Reference

| Field | Default | Description |
| --- | --- | --- |
| `website_listen_ip` | `0.0.0.0` | Bind address (use `::` for dual-stack) |
| `website_listen_port` | `8080` | TCP/TLS port |
| `quic_listen_port` | `8081` | UDP/QUIC port |
| `data_dir` | `data` | Embedded DB directory |
| `loglevel` | `INFO` | Log level (trace/debug/info/warn/error) |
| `website_workers` | `4` | Worker threads |
| `user_accounts` | `true` | Enable user registration |
| `fulltextsearch` | `false` | Enable Meilisearch integration |
| `local_instance_name` | `""` | GNA instance name |
| `local_instance_uuid` | `""` | Instance UUID for sync |

### Feeder Configuration

Per-feeder settings in `config/modules.toml`:

```toml
[feeder.nvd]
enabled = true
loglevel = "INFO"
api_key = "your-nvd-key"

[feeder.github]
enabled = true

[feeder.csaf_siemens]
enabled = true
```

Or INI format (`config/modules.cfg`):

```ini
[feeder:nvd]
enabled = true
api_key = your-nvd-key
```

## TLS Configuration

### Development (Self-Signed)

TLS 1.3 is **always on** -- there is no
plaintext-HTTP mode. When no operator
certificate is configured (see below), a
self-signed certificate for `localhost` /
`127.0.0.1` / `::1` is generated with `rcgen`
on every start-up (45-day validity). This is
the right thing for the default loopback bind;
browsers warn on the self-signed cert, which
is expected for local development.

The default `website_listen_ip` is `127.0.0.1`
(loopback). vl-web has no built-in
authentication in front of its own listener,
so binding a non-loopback address is refused
unless you opt in -- see *Binding a public
address* below.

### Production (operator certificate)

For an internet-facing hostname, supply a real
CA-issued certificate + key. Point at PEM files
via either the CLI flags or the environment
variables (CLI wins):

```bash
# CLI flags
vl-web --tls-cert /etc/ssl/certs/server.pem \
       --tls-key  /etc/ssl/private/server.key

# or environment variables
VL_TLS_CERT=/etc/ssl/certs/server.pem
VL_TLS_KEY=/etc/ssl/private/server.key
```

Both must be set together -- supplying only one
is a start-up error (it never silently falls
back to the self-signed cert). The resolved
certificate drives **both** the TCP (HTTP/1.1 +
HTTP/2) and the QUIC (HTTP/3) listeners. The
start-up log records the source
(`tls_certificate="operator-supplied"` or
`"self-signed"`).

TLS 1.3 only -- no TLS 1.2 fallback.
Elliptic-curve cryptography (ECC) preferred; no
RSA ciphers. The aws-lc-rs provider offers the
X25519MLKEM768 post-quantum hybrid key-exchange
group first.

### Binding a public address

Because vl-web ships no authentication in front
of its listener, a non-loopback bind (`0.0.0.0`,
`::`, or a LAN/public IP) is **refused at
start-up** unless you explicitly opt in:

```bash
vl-web --allow-non-loopback        # or:
VL_ALLOW_NON_LOOPBACK=1 vl-web
```

The recommended internet deployment does *not*
bind a public address directly. Instead, keep
vl-web on `127.0.0.1` and place a reverse proxy
(HAProxy) in front -- see below.

### Reverse proxy (HAProxy)

Run vl-web on the loopback interface and let
HAProxy terminate the public TLS connection, add
authentication / rate-limiting, and forward to
the loopback listener. vl-web keeps TLS on its
own hop (there is no plaintext backend), so the
proxy re-encrypts to vl-web's HTTPS listener.

```text
client ──HTTPS(443)──▶ HAProxy (real cert, auth)
       ──HTTPS(8080)─▶ 127.0.0.1  (vl-web, loopback)
```

Two certificate choices for the loopback hop:

1. **Self-signed backend (simplest).** Leave
   vl-web on its self-signed loopback cert and
   tell HAProxy not to verify the backend
   (`ssl verify none`). Public trust lives
   entirely on HAProxy's front-end cert.
2. **Real backend cert.** Give vl-web an
   (internal-CA) cert via `--tls-cert` /
   `--tls-key` and have HAProxy `verify required`
   against a pinned CA.

Because the browser's `Host` header now carries
the public hostname, add it to vl-web's
anti-DNS-rebinding allowlist with `--allow-host`
(repeatable / comma-separated) or
`VL_ALLOWED_HOSTS`.

Example `haproxy.cfg` (self-signed backend):

```haproxy
global
    log /dev/log local0
    ssl-default-bind-options ssl-min-ver TLSv1.3

defaults
    mode    http
    option  httplog
    timeout connect 5s
    timeout client  30s
    timeout server  30s

frontend vl_public
    bind :443 ssl crt /etc/haproxy/certs/vuln.pem alpn h2,http/1.1
    http-request redirect scheme https unless { ssl_fc }
    http-request set-header X-Forwarded-Proto https
    http-request set-header X-Forwarded-For %[src]
    default_backend vl_web

backend vl_web
    # vl-web serves a self-signed cert on the loopback, so skip
    # backend verification (trust lives on the front end).
    server vlweb 127.0.0.1:8080 ssl verify none alpn h2,http/1.1
```

Then run vl-web bound to loopback with the
public hostname allow-listed:

```bash
VL_ALLOWED_HOSTS=vuln.example.org vl-web
# website_listen_ip defaults to 127.0.0.1
```

> **Notes.** vl-web does not yet consume
> `X-Forwarded-For` for its own access log -- it
> logs the proxy's loopback socket address; the
> header is set for a downstream log processor
> and a future enhancement. HTTP/3 (QUIC, UDP
> :8081) cannot be proxied by HAProxy 2.x --
> expose it only behind a QUIC-aware balancer.

#### WAF (SPOE) must not take ACME renewal down

When the frontend also runs a WAF over SPOE
(the `haproxy` Ansible role installs either
ModSecurity or Coraza as a SPOA), the WAF
filter runs **before** the frontend's own
rules and denies on a SPOA error --
ModSecurity with `504`, Coraza with `500`.
A WAF outage or a single CRS false positive
on `/.well-known/acme-challenge/<token>`
therefore also breaks certificate renewal,
taking down every certificate the frontend
terminates.

Two role defaults close that since v1.2.66:

| Variable | Default | Effect |
| --- | --- | --- |
| `haproxy_waf_exclude_paths` | `[/.well-known/acme-challenge]` | Listed path prefixes bypass the WAF, including the deny-on-SPOA-error rule -- a dead SPOA no longer blocks the ACME HTTP-01 challenge. |
| `haproxy_waf_buffer_request_body` | `true` | Emits `option http-buffer-request` so the whole body is buffered before inspection. |

The exclusion is deliberately narrow. The
ACME challenge path is fetched by the CA over
plain HTTP, carries no user input worth
inspecting, and its availability is a
precondition for the TLS the WAF protects.
Set `haproxy_waf_exclude_paths: []` to inspect
everything -- and accept that a WAF outage
then blocks renewal.

The body buffering matters for detection, not
availability: the SPOE templates forward
`body=req.body`, and `req.body` returns only
what HAProxy has **already** buffered. Without
the option, a large or slow POST is inspected
partially or not at all, so CRS rules over
`ARGS_POST` (the 941/942 SQLi and XSS families)
can be evaded by splitting the body across
packets.

The full ACME + HAProxy + Coraza deployment
(certbot enrolment, the renewal timer, the
port map, and the SPOP wiring) is documented
in `reverse-proxy-and-certificates.md` at the
repository root.

## Network

### Ports

| Port | Protocol | Purpose |
| --- | --- | --- |
| 8080 | TCP/TLS | HTTPS (HTTP/1.1 + HTTP/2) |
| 8081 | UDP/QUIC | HTTP/3 |

Both come from `config/generic.json`
(`website_listen_port` and
`quic_listen_port`), not from `Cargo.toml`;
the compiled fallback is `127.0.0.1:8080` in
`crates/vl-web/src/net_bind.rs`. A healthy
start-up line reads
`listen=127.0.0.1:8080 quic_listen=127.0.0.1:8081`.
A configured QUIC port is not proof of a bound
one -- confirm with `lsof`/`ss` before you
treat HTTP/3 as serving.

The pair is **per project**. If the host also
runs other ndaal services, do not reach for
these numbers on the wrong one:

| Project | HTTP/2 (TCP) | HTTP/3 (QUIC) |
| --- | ---: | ---: |
| **nvulnlookup** (`vl-web`) | **8080** | **8081** |
| csaf-crud | 8180 | 8181 |
| sbom-auditor | 8680 | 8681 |

A test suite or probe pointed at another
project's port does not report "wrong port" --
it reports connection failures that read as
application faults.

### IPv4 and IPv6

The server supports dual-stack. Set
`website_listen_ip` to `::` to bind on both
IPv4 and IPv6. Note that `::` is a non-loopback
bind, so it additionally requires the
`--allow-non-loopback` / `VL_ALLOW_NON_LOOPBACK`
opt-in (see *Binding a public address* above).

### Firewall (ufw)

```bash
ufw allow 8080/tcp comment "nvulnlookup HTTPS"
ufw allow 8081/udp comment "nvulnlookup QUIC"
```

## Data Directory

All persistent data is in `data/`:

```text
data/
  vulnerabilities.redb   # Vulnerability store (redb)
  vlookup.db             # User/model database (SQLite)
```

### Storage backends

`VulnStorage` ships two constructors. Operators only ever
hit the **file-backed** path; the **in-memory** path is a
test-only seam that ships with the binary so future
developers can write cheap unit tests without provisioning
a temp directory.

| Constructor | Backend | Used by | Persistence |
| --- | --- | --- | --- |
| `VulnStorage::new(path)` | file (memory-mapped redb) | `vl-web`, `vl-cli` (production) | survives process restart |
| `VulnStorage::new_in_memory()` | `redb::backends::InMemoryBackend` (`RwLock<Vec<u8>>`) | `cargo test --workspace`, `cargo +nightly miri test` | data drops with the process |

Both constructors share a single internal helper
`fn init_tables(db: &Database) -> Result<()>` that opens
**every** redb table the codebase expects in one
committed write transaction. Adding a new table is a
single-line edit; you cannot accidentally add it to the
file-backed path and forget the in-memory one (or vice
versa) because there is only one such code path.

The in-memory backend is a public, supported part of the
redb crate (`redb::Builder::create_with_backend(...)` —
introduced in redb 4.0). It is byte-format compatible with
the file backend for the operations our tests exercise
(set / get / iterate / range), but it cannot be persisted
to disk — by design.

There is no operational reason to construct an in-memory
`VulnStorage` from a binary at runtime. The
`Bin / Cargo.toml` linker only includes the in-memory
backend bytes (~5 KiB of code) because they live in the
same `vl-core` crate as the file-backed constructor; this
is a non-issue for binary size (`vl-web` release build is
~75 MiB) and adds no runtime cost.

If you ever see an outbound metric or log line that
references "in-memory storage" coming from a production
deployment, that is a bug — please file a CSAF
informational advisory and reset the affected node.

## Bulk Import (CIRCL Dumps)

The fastest way to seed an empty deployment
is to import the 76 CIRCL dump sources. Every
script in the chain emits and verifies three
hash sidecars (`.sha-256`, `.sha-512`,
`.sha3-512`) per artefact so downstream
consumers can prove byte-for-byte integrity
without re-running the source pipeline.

| Script | Stage | Sidecar role |
| --- | --- | --- |
| `fetch_dumps.sh` | download → `dumps/` | writes per-dump sidecars (local fingerprint) |
| `compress_dumps.sh` | `dumps/` → `dumps_archive/` | writes per-archive sidecars + 7z CRC |
| `import_and_verify_dumps.sh` | `dumps_archive/` and/or `dumps/` → DB | verifies sidecars before import |

### Fetching dumps

```bash
# Download all 76 dumps (~10 GB total)
bash scripts/fetch_dumps.sh

# Or auto-discover the live dump list
bash scripts/fetch_dumps.sh --all
```

`fetch_dumps.sh` now writes three sidecar
files alongside every successful download
(or whenever an existing local copy is up
to date but lacks sidecars from an older
fetch run). The summary line reports both
counters:

```text
Downloaded:        76
Skipped:           0 (already up to date)
Sidecars written:  76 (.sha-256/.sha-512/.sha3-512 trio per dump)
Sidecars failed:   0
```

> **Provenance caveat — local fingerprint, not
> upstream attestation.** CIRCL's dump server
> at <https://vulnerability.circl.lu/dumps/>
> does not publish upstream sidecars. The
> three files generated by `fetch_dumps.sh`
> are computed *after* the bytes land on
> disk; they prove the dump has not been
> modified since the download finished, but
> they do **not** certify the upstream bytes
> were authentic. For supply-chain proof,
> additionally pin the TLS certificate of the
> CIRCL endpoint and review the URL list
> before each fetch.

### Compressing dumps

```bash
bash scripts/compress_dumps.sh
```

Each NDJSON dump is compressed with 7zip
(`LZMA2 mx=9`) into `dumps_archive/<name>.7z`
and immediately:

1. validated with `7z l` (listing) and
   `7z t` (per-entry CRC integrity test)
2. fingerprinted with three sidecars
   (`.sha-256`, `.sha-512`, `.sha3-512`)
3. self-verified by re-running
   `shasum -c` / `sha3sum -c` on every
   sidecar — a sidecar that does not
   round-trip aborts the run and the
   partial files are removed

If an archive already exists and is newer
than its source, the script skips
re-compression but **still refreshes any
missing or stale sidecar** before
reporting "up to date".

### Importing & verifying dumps

```bash
bash scripts/import_and_verify_dumps.sh
```

Pipeline (each step gates the next):

1. Resolve dumps. If `dumps/` is empty,
   walk `dumps_archive/*.7z`. For each
   archive, verify the three sidecars
   (`shasum -c` + `sha3sum -c`), then run
   `7z t` for the per-entry CRC check, then
   extract.
2. Verify per-dump sidecars in `dumps/`
   (the `.sha-256`/`.sha-512`/`.sha3-512`
   trio each must verify; partial sets are
   always fatal).
3. Count NDJSON entries per dump (`jaq`).
4. Import via `vl-cli import-dumps`.
5. Compare per-source DB counts to the
   NDJSON line counts (95% tolerance for
   PASS; 50–95% is WARN; <50% is FAIL).

> **Strict mode is the default.** Every
> dump and every archive must ship the full
> three-sidecar set. Partial sets (1 or 2 of
> 3 files present) and any hash mismatch
> are always fatal regardless of mode.
>
> A bridge mode is available for the
> initial migration to the new pipeline:
>
> ```bash
> IMPORT_STRICT_CHECKSUMS=0 \
>     bash scripts/import_and_verify_dumps.sh
> ```
>
> Lenient mode prints a `WARN` for any
> dump or archive missing all three
> sidecars but accepts the artefact and
> continues. Use only when the existing
> dump set predates the new pipeline; CI
> must keep the strict default.

#### Throughput — batched writes (since v1.2.66)

Step 4 above (`vl-cli import-dumps`) now
writes **one redb transaction per 1,000
rows**. It previously opened a fresh
two-phase-commit write transaction per
record -- two fsyncs per CVE -- measured at
about 3 records/second with roughly 80% of
process time inside `fcntl`/`pwrite`.

Measured on a 384,585-record dump set:

| Build | Progress after the run |
| --- | --- |
| Before v1.2.66 | 84% in 34 h |
| v1.2.66 | 100% in 2 h 45 m |

Plan the initial seed of a fresh deployment
against the second row, not the first.

A single bad row aborts the whole redb
transaction, so a failed batch is retried
record-by-record instead of discarding up to
999 good records alongside the one that
failed.

The count the importer **prints** is now
asserted too, not just the rows on disk.
Mutation testing found a surviving `Ok(n) =>
0`: a successful 381,875-record import
reported `Entries imported: 0` while the
database filled correctly, and every test
still passed. Step 5 -- the per-source
comparison of DB counts against NDJSON line
counts -- remains the independent check.

Example output:

```text
SOURCE                              DUMP         DB   RATIO STATUS
nvd                               280431     278012   99.1% PASS
github                             24819      24819  100.0% PASS
csaf_siemens                         891        891  100.0% PASS
...
```

Requires `jaq`, `shasum`, and `sha3sum`:

```bash
cargo install jaq sha3sum
# or: brew install jaq coreutils    (macOS supplies gsha3sum)
# or: apt install libdigest-sha3-perl jq    (Debian 13+)
```

### Provenance and checksum limitations

| Sidecar type | Generated by | Proves | Does NOT prove |
| --- | --- | --- | --- |
| `dumps/<name>.ndjson.sha*` | `fetch_dumps.sh` (after download) | dump unchanged since this fetch | upstream bytes were authentic |
| `dumps_archive/<name>.7z.sha*` | `compress_dumps.sh` (after compression) | archive bytes intact | the NDJSON inside has its own sidecars (it doesn't — see next row) |
| dump sidecars after archive extraction | (none — not shipped inside the .7z) | n/a | n/a — the archive's three sidecars + `7z t` CRC carry the integrity proof for the extracted contents |

Three families per artefact (SHA-256 +
SHA-512 + SHA3-512) give defence in depth
against a single-family cryptanalytic break.
SHA-3 uses the Keccak sponge construction —
a different team, different NIST round, and
different design from SHA-2 — so the sidecar
trio survives even a hypothetical
catastrophic break of the SHA-2 family.

When dumps are extracted from a verified
`.7z` (path 1 of `import_and_verify_dumps.sh`
above), the resulting NDJSON files do **not**
carry their own per-file sidecars. The
script knows this and accepts those dumps
on the strength of the archive-side proof:
all three archive sidecars verified plus
`7z t` integrity test passed → archive
bytes intact + every entry's CRC valid →
extracted bytes match the bytes that were
compressed in the first place. To force
the dump set into the strict shape after
extraction, run a fresh round through
`fetch_dumps.sh` (or the data-source-
specific export script — see below).

## Nuclei Templates Round-Trip

The on-disk nuclei template corpus
(~261 000 YAML files under
`nuclei_fire/nuclei-scanner/nuclei-templates/`)
can be projected into a SQLite **table**
for ad-hoc analysis. The data lives as the
`nuclei_templates` table inside the shared
`data/vlookup.db` (the same SQLite file
vl-web uses for users, organizations,
comments, bundles, sightings, …) — **not**
in a separate database file. Three scripts
cooperate:

| Script | Direction | Default scope |
| --- | --- | --- |
| `import_nuclei_templates.sh` | corpus → `vlookup.db:nuclei_templates` | first 250 alphabetical (overridable) |
| `export_nuclei_data.sh` | `vlookup.db:nuclei_templates` → NDJSON dump + 3 sidecars | every row, deterministic order |
| `import_nuclei_data.sh` | NDJSON dump → `vlookup.db:nuclei_templates` | every line; verifies sidecars first |

vl-web opens `vlookup.db` in WAL mode at
startup, so all three scripts can read /
write the table while the server is
running. The schema migration is purely
additive (CREATE TABLE IF NOT EXISTS,
CREATE INDEX IF NOT EXISTS), so vl-web's
own startup migration logic does not
collide with it.

### Importing from the corpus

```bash
# Default — quick dev-loop slice
bash scripts/import_nuclei_templates.sh

# Bigger slice or full corpus
bash scripts/import_nuclei_templates.sh \
    --limit 10000

# Trusted-folder-only (5 vetted upstream
# repos parsed from nuclei_scanner.sh)
bash scripts/import_nuclei_templates.sh \
    --limit 0 \
    --include-pattern \
'^(projectdiscovery__nuclei-templates|projectdiscovery__fuzzing-templates|projectdiscovery__nuclei-templates-ai|OWASP__www-project-asvs-security-evaluation-templates-with-nuclei|runZeroInc__nuclei-templates)/'

# Refresh the on-disk corpus first
bash scripts/import_nuclei_templates.sh \
    --update-templates --limit 0
```

Each row carries a UUID v4 PK, the nuclei
`info.*` fields, the `classification`
sub-object's CVE / CVSS / CWE values, the
raw YAML (for re-emit), and two trust
columns:

- `nuclei_trust` (0/1) — is the source
  folder in the trusted-source allowlist?
- `nuclei_trust_score` (1–10) — `8` for
  trusted, `7` for `OWASP_*`, `3` for
  every entry in the COMMUNITY allowlist,
  null otherwise.

The trust allowlists are parsed live from
`nuclei_fire/nuclei_scanner.sh` so a
single source of truth governs both the
scanner and this importer.

### Exporting the SQLite table

```bash
bash scripts/export_nuclei_data.sh
# → dumps/nuclei_templates.ndjson
# → dumps/nuclei_templates.ndjson.sha-256
# → dumps/nuclei_templates.ndjson.sha-512
# → dumps/nuclei_templates.ndjson.sha3-512
```

Five-stage pipeline:

1. `SELECT * FROM nuclei_templates ORDER BY
   nuclei_uuid` → NDJSON via `sqlite3 -json`
   piped through `jaq -c '.[]'`. Sorting by
   UUID makes consecutive exports byte-
   identical for unchanged rows, which makes
   the resulting sidecar hashes deterministic
   and `git diff` highlights only the actual
   row-level changes.
2. Atomic write: stage to a sibling tempfile,
   rename into place when complete.
3. Verify export — line count == row count,
   every line parses as JSON, no duplicate
   UUIDs.
4. Generate the three sidecars
   (`shasum -a 256`, `shasum -a 512`,
   `sha3sum -a 512`).
5. Self-verify the sidecars
   (`shasum -c` / `sha3sum -c`).

### Importing an NDJSON dump

```bash
bash scripts/import_nuclei_data.sh
```

Stages (any failure aborts cleanly):

1. **Stage 0 — archive fallback.** If
   `dumps/nuclei_templates.ndjson` is
   missing, the script verifies the three
   archive sidecars on
   `dumps_archive/nuclei_templates.7z`,
   runs `7z t`, confirms the archive entry
   names match the expected basename, and
   extracts to `dumps/`. The
   `INTEGRITY_PROVEN_BY_ARCHIVE` flag is
   set so stage 1 (per-dump sidecar check)
   knows to skip — the dump-file sidecars
   are not shipped inside the `.7z`. Pass
   `--no-archive` to disable the fallback
   and fail fast.
2. **Stage 1 — verify dump sidecars** (skipped
   when stage 0 ran).
3. **Stage 2 — schema bootstrap** (CREATE
   TABLE IF NOT EXISTS).
4. **Stage 3 — bulk INSERT** via SQLite's
   `json_each(readfile(...))` over an
   NDJSON-slurped-to-array temp file. One
   transaction; default mode clears the
   table first, `--append` merges by
   `template_path` UNIQUE.
5. **Stage 4 — post-import consistency.**
   Row count matches NDJSON line count,
   no duplicate UUIDs, no NULL in required
   columns.
6. **Stage 5 — DB-file sidecars.** The
   resulting SQLite database file gets its
   own three-sidecar trio
   (`<db>.sha-256`/`.sha-512`/`.sha3-512`)
   so the loaded artefact is itself
   content-addressable.

### Provenance for the nuclei round-trip

| Sidecar set | Generated by | Trust origin |
| --- | --- | --- |
| `dumps/nuclei_templates.ndjson.sha*` | `export_nuclei_data.sh` | local DB state at export time |
| `dumps_archive/nuclei_templates.7z.sha*` | `compress_dumps.sh` | local archive bytes |
| `data/vlookup.db.sha*` | `import_nuclei_data.sh` (stage 5) | post-import database file state — covers ALL tables in `vlookup.db`, not just `nuclei_templates` (vl-web continues writing concurrently, so this sidecar set has a short half-life and is mainly useful as a "right-after-import" snapshot) |

These sidecars are **content-addressable
proofs of local state, not provenance
chains back to the upstream nuclei
template authors.** The upstream nuclei
templates ship without any cryptographic
attestation; the only provenance signal we
record is which folder under the corpus
the template lived in (`template_path`),
which gates the `nuclei_trust` and
`nuclei_trust_score` columns. To raise the
provenance bar you would need to verify
the GitHub repository signature for each
trusted source at clone time — that is the
job of `nuclei_fire/nuclei_scanner.sh`
upstream of this pipeline, not the
importer.

## Quality Gates

Every CI-blocking check ships through a
single canonical runner:
`scripts/quality_gates.sh`. The complete
gate matrix is documented in `CLAUDE.md`
under "Overall quality loop"; this section
covers the operator-facing surface that
matters in a deployment.

### Invocation

```bash
# Fast loop (developer + CI hot path):
# skips live-server gates and fuzzing.
scripts/quality_gates.sh --fast

# Full sweep (release-day or nightly):
# adds testssl, bruno, sqlmap, sqllogictest,
# loadtest, all DAST scanners, ansible
# molecule.
scripts/quality_gates.sh

# Run ONLY what --fast skips (the live-server
# suites + fuzz); pair on a CI runner with the
# server up.
scripts/quality_gates.sh --rest

# Deeper fuzzing on the full sweep:
scripts/quality_gates.sh --enhance  # fuzz 300s/target
scripts/quality_gates.sh --extreme  # fuzz 900s + nightly kani

# CI strict mode (abort on first failure)
scripts/quality_gates.sh --strict --fast

# Single-gate dispatch (debugging)
scripts/quality_gates.sh --only fmt,clippy
scripts/quality_gates.sh --only web_check
scripts/quality_gates.sh --only sql_query_analyzer
```

### Gate inventory (in execution order)

The first column is the slug accepted by
`--only`. The second column says whether
the gate runs under `--fast`.

| Slug | `--fast` | What it does |
| --- | :---: | --- |
| `fmt` | ✓ | `cargo fmt --all --check` |
| `clippy` | ✓ | `cargo clippy --workspace -- -D warnings` |
| `test` | ✓ | `cargo test --workspace --all-features` (lib + integration + doc) |
| `audit` | ✓ | `cargo audit` (CVE scan against `Cargo.lock`) |
| `deny` | ✓ | `cargo deny check` (licence + duplicates + sources) |
| `machete` | ✓ | `cargo machete --with-metadata` (unused deps) |
| `geiger` | ✓ | per-crate `cargo geiger` unsafe survey |
| `tree_duplicates` | ✓ | `cargo tree --workspace --duplicates` |
| `rust_doctor` | ✓ | rust-doctor maintainability score |
| `kani` | ✓ | `cargo kani` (nightly-only, usually skipped) |
| `vet` | ✓ | `cargo vet check` (supply-chain audits) |
| `semver_checks` | ✓ | `cargo semver-checks check-release` |
| `fuzz` | | `cargo fuzz run` against every fuzz target |
| `linters` | ✓ | yamllint + ryl + markdownlint + rumdl + hadolint + htmlhint + oxlint + ruff + bandit |
| `coverage` | ✓ | `cargo llvm-cov --lcov` |
| `docs_fresh` | ✓ | README/LIESMICH/LISEZMOI/CHANGELOG modified ≤ 24 h |
| `changelog_version` | ✓ | CHANGELOG top entry == workspace version |
| `fonts` | ✓ | CDN-font policy guard (forbid third-party font hosts) |
| `binary_audit` | ✓ | `cargo audit bin` against the release binary |
| `binary_scan` | ✓ | trivy + syft + osv-scanner per release binary |
| `port_scan` | | rustscan + nmap, only 8080/8081/7700 expected |
| `nmap_scan` | ✓ | INVASIVE nmap `-A -p- -sV` service scan of localhost → `documentation/ports/nmap/` (native + jaq SARIF 2.1.0) |
| `rustscan_scan` | ✓ | INVASIVE rustscan all-ports + nmap `-A -sV` service scan of localhost → `documentation/ports/rustscan/` (native + jaq SARIF 2.1.0) |
| `bruno` | | live API contract test |
| `testssl` | | TLS 1.3 / cipher / vuln scan |
| `sqlmap` | ✓ | SQL injection sweep (silent if server down) |
| `sqllogictest` | ✓ | SQLite migration regression suite |
| `loadtest` | | `oha` HTTP/2 load test |
| `nuclei_scanner` | | ProjectDiscovery DAST |
| `lonkero_scanner` | | AI-driven DAST |
| `ffuf_scanner` | ✓ | content-discovery sweep |
| `feroxbuster_scanner` | | recursive content-discovery |
| `schemathesis_scanner` | ✓ | OpenAPI / HATEOAS contract test |
| `csaf_ndaal` | ✓ | CSAF 2.1 publisher feed regression |
| `ansible_molecule` | | `molecule test -s default` for the in-tree role |
| `web_check` | ✓ | lissy93/web-check Podman sweep (HTML + JSON + SARIF) |
| `devguard` | ✓ | `devguard check` + `devguard git health` (4 formats each) |
| `sql_query_analyzer` | ✓ | static SQL-query analysis (4 formats, parallel) |
| `gitleaks_scanner` | ✓ | upstream gitleaks secrets scan (since v0.1.45) |
| `opengrep` | ✓ | multi-language SAST sweep (semgrep fork; 6 lang × 3 formats, since v0.1.45) |
| `html_linters` | ✓ | htmlhint × 8 + oxlint × 10 + fta × 3 formats per run; reports under `documentation/html/<tool>/<ISO>/` (since v0.1.45) |
| `endpoint_lists_drift` | ✓ | read-only drift detector: `VENDOR_SPECS` ↔ testssl/tls/capture_screenshots endpoint arrays (since v0.1.45) |
| `feed_recent_25` | | LIVE — recent-25 probe over every dynamically-discovered source; reports under `vulnerability-lookup-rs/logs/feed_25_<ISO>/` (since v0.1.45) |
| `fuzzing_targets` | | LIVE — full 152-target cargo-fuzz sweep (plus 152 honggfuzz + 124 test-fuzz targets over the same single-source fuzz-harness — three engines) with SARIF 2.1.0 output; reports under `documentation/rust/fuzzing/<ISO>/` (since v0.1.45) |
| `lintscout_scan` | ✓ | `lintscout` — detect linter-ignore directives (`# shellcheck disable=`, `# noqa`, `// eslint-disable-line`, `# pylint: disable=`); 4 formats: text / json / count / sarif (since v0.1.46) |
| `alint_scan` | ✓ | `alint` — language-agnostic repo-structure / filename / content linter; 8 formats: human / json / sarif / github / Markdown / junit / gitlab / agent (since v0.1.46) |
| `mkdlint_scan` | ✓ | `mkdlint` — Markdown / CommonMark style checker; 4 formats: text / json / sarif / github + `--fix-dry-run` autofix preview (and optional writing `--fix` via `--apply-fixes`) (since v0.1.46) |
| `foxguard_scan` | ✓ | `foxguard` — fast local security scanner with 170+ built-in rules across 11 languages; 4 formats: terminal / json / sarif / cbom (CycloneDX 1.6+ Crypto Bill of Materials via `foxguard pqc`) (since v0.1.46) |
| `wardenscan` | ✓ | `warden` (crate `wardenscan`) — GitHub Actions security scanner with 59 rules + auto-fixer; 4 formats: console / json / sarif / Markdown + `warden fix` plan (and optional `warden fix . --apply` via `--apply-fixes`) (since v0.1.46) |
| `cargo_capsec` | ✓ | `cargo-capsec` — static capability audit for Rust (filesystem / network / process / FFI / ambient authority); 3 formats: text / json / sarif (since v0.1.46) |
| `cargo_perf` | ✓ | `cargo-perf` — preventive performance analysis for Rust (async / lock / allocation / iteration anti-patterns); 3 formats: console / json / sarif (since v0.1.46) |
| `rust_guardian` | ✓ | `rust-guardian` — dynamic code-quality enforcement (placeholder code, architectural compliance); 6 formats: human / json / junit / sarif / github / agent (since v0.1.46) |

### Artefact directories (per-tool reports)

Several gates persist multi-format reports
with an ISO-timestamp suffix so consecutive
runs build a per-deployment audit trail. The
canonical directories are:

| Gate | Output dir | Per-run artefacts |
| --- | --- | --- |
| `web_check` | `documentation/web-check/` | `web-check_<ISO>.{json,html,sarif}` |
| `devguard` | `documentation/git/` | `devguard-check_<ISO>.{txt,json,md,sarif}` + `devguard-git-health_<ISO>.{txt,json,md,sarif}` |
| `sql_query_analyzer` | `documentation/sql/sql_query_analyzer/` | `sql-query-analyzer_<ISO>.{txt,json,yaml,sarif}` |
| `gitleaks_scanner` | `documentation/secrets/gitleaks/gitleaks_<ISO>/` | `{local,ndaal}/gitleaks.{json,csv,junit,sarif}` |
| `opengrep` | `documentation/<lang>/opengrep/opengrep_<ISO>/` | `opengrep.{txt,json,sarif}` per language (shell, python, rust, html, json, yaml) |
| `html_linters` | `documentation/html/<tool>/<ISO>/` | per-tool: `htmlhint.{8 formats}` / `oxlint.{10 formats}` / `fta.{3 formats}` + `SUMMARY.txt` |
| `endpoint_lists_drift` | (no artefacts — read-only check) | stdout: per-target drift report, exit 1 on drift |
| `feed_recent_25` | `vulnerability-lookup-rs/logs/feed_25_<ISO>/` | `<source>.json` per live source + `<source>.unknown_fields.log` + `matrix.tsv` + `summary.log` |
| `fuzzing_targets` | `documentation/rust/fuzzing/<ISO>/` | `summary.txt` + `results.tsv` + `report.sarif.json` (SARIF 2.1.0) + `<crate>__<target>.log` per target |
| `lintscout_scan` | `documentation/linter/lintscout/lintscout_<TIMESTAMP>/` | `lintscout.{text,json,count,sarif}` + `SUMMARY.txt` |
| `alint_scan` | `documentation/linter/alint/alint_<TIMESTAMP>/` | `alint.{human,json,sarif,github,markdown,junit,gitlab,agent}` + `SUMMARY.txt` |
| `mkdlint_scan` | `documentation/markdown/mkdlint/mkdlint_<TIMESTAMP>/` | `mkdlint.{text,json,sarif,github,fix-dryrun}` + optional `mkdlint.fix-applied` + `SUMMARY.txt` |
| `foxguard_scan` | `documentation/code/foxguard/foxguard_<TIMESTAMP>/` | `foxguard.{terminal,json,sarif,cbom}` + `foxguard.stderr.log` + `SUMMARY.txt` (every format excludes `.git/`, `skills/`, `documentation/`, `nuclei-templates/`) |
| `wardenscan` | `documentation/linter/wardenscan/wardenscan_<TIMESTAMP>/` | `wardenscan.{console,json,sarif,markdown,fix-plan}` + optional `wardenscan.fix-apply` + `SUMMARY.txt` |
| `cargo_capsec` | `documentation/rust/cargo_capsec/cargo_capsec_<TIMESTAMP>/` | `cargo_capsec.{text,json,sarif}` + `SUMMARY.txt` |
| `cargo_perf` | `documentation/rust/cargo_perf/cargo_perf_<TIMESTAMP>/` | `cargo_perf.{console,json,sarif}` + `SUMMARY.txt` |
| `rust_guardian` | `documentation/rust/rust_guardian/rust_guardian_<TIMESTAMP>/` | `rust_guardian.{human,json,junit,sarif,github,agent}` + `SUMMARY.txt` |

The SARIF emissions in particular drop
straight into GitHub code-scanning,
Sonarcloud, or vscode-sarif-viewer without
post-processing. `web_check` doesn't
natively emit SARIF — the runner transforms
the aggregated JSON into a v2.1.0 document
with one rule per probed endpoint and one
warning-level result per endpoint that
returned an `error` field.

### Tooling install matrix

Every gate has a SKIP path when its tool
is missing, so a fresh dev box doesn't
fail the suite — it just degrades to the
gates that ARE installable. To populate
the full matrix:

```bash
# Rust crates
cargo install \
    cargo-audit cargo-deny cargo-machete \
    cargo-geiger cargo-vet cargo-semver-checks \
    cargo-llvm-cov rust-doctor cargo-fuzz \
    devguard sql_query_analyzer sha3sum jaq

# DAST + content discovery
cargo install --locked feroxbuster schemathesis-cli
brew install nuclei ffuf rustscan nmap

# Static analysis
brew install hadolint shellcheck shfmt yamllint
pip install ansible-lint molecule rumdl ruff bandit

# Container runtime (web_check, ansible_molecule)
brew install podman p7zip coreutils
podman machine init && podman machine start

# Live-server gates
brew install testssl bruno-cli
cargo install oha sqlmap

# JSON tooling
cargo install jaq
```

### Knobs

Per-gate environment variables are
documented inside each runner's header
comment. The most operationally relevant:

| Var | Gate | Purpose |
| --- | --- | --- |
| `IMPORT_STRICT_CHECKSUMS` | `import_and_verify_dumps.sh` | `0` accepts sidecar-less dumps (default `1` is strict) |
| `VL_BASE_URL` | live-server gates + `web_check` | Override `https://localhost:8080` |
| `WEB_CHECK_IMAGE` | `web_check` | OCI image tag (default `ghcr.io/lissy93/web-check:latest`) |
| `WEB_CHECK_TESTS` | `web_check` | Comma-separated subset of API endpoints |
| `DEVGUARD_FAIL_ON` | `devguard` | `warning` (default) / `error` / `none` |
| `DEVGUARD_PATH` | `devguard` | Repo root override (default repo root) |
| `SQA_QUERIES` | `sql_query_analyzer` | Path to SQL queries file |
| `SQA_SCHEMA` | `sql_query_analyzer` | Path to SQL schema file (default: concat migrations) |
| `SQA_LLM_ENABLED` | `sql_query_analyzer` | `1` enables the LLM call (default `0` = `--dry-run`) |
| `QG_FUZZ_SECONDS` | `fuzz` | libFuzzer `-max_total_time` (default 60) |
| `QG_DOC_MAX_AGE_SECONDS` | `docs_fresh` | Threshold (default 86 400 = 24 h) |

## Background Feeders

On startup, 135 feeders run automatically
in the background scheduler:

| Category | Count | Interval | Examples |
| --- | --- | --- | --- |
| CSAF providers | 91 | **1 hour** (since v0.1.44, was 6h) | Siemens, Cisco, Red Hat, Microsoft, Telekom |
| Git-based | 16 | 12 hours | GitHub, CVEListV5, FKIE NVD |
| HTTP API | 17 | 6-12 hours | NVD, CISA KEV, CIRCL KEV, ZDI |
| Enrichment | 7 | 12-24 hours | EPSS, CWE, CAPEC, GCVE, Nuclei |
| New (v0.1.27) | 4 | 12-24 hours | ZDI, Exploit-DB, OSV Golang, GCVE VL |
| Debian Security Tracker | 1 | 1 hour | security-tracker.Debian.org |
| CNA Scorecard | 1 | **1 hour** (since v0.1.31) | RogoLabs/CNAScoreCard |
| Moksha | 1 | **24 hours** (35-min startup delay, since v0.1.47) | Moksha (moksha.dk) |

### CSAF Provider Downloads

Since v0.1.27, CSAF advisories are downloaded
using a native Rust implementation
(`csaf_downloader.rs`) instead of the external
Go `csaf_downloader` binary. This eliminates
the Go/OpenSSL dependency and uses the same
reqwest+rustls stack as all other feeders.

CSAF downloads run with 10 parallel workers
per provider and support incremental updates
via `changes.csv`.

### ndaal CSAF Advisory Inventory

ndaal publishes its own CSAF 2.1 advisories
under `csaf/2026/<NNN>/` — both security
advisories for reachable issues in nvulnlookup
itself and informational advisories that
document dependency bumps.

Advisories added in v0.1.34 (all
`csaf_informational_advisory`, one per crate
bump):

- `ndaal-sa-2026-020` — rusqlite 0.32.1 → 0.39.0
- `ndaal-sa-2026-021` — matchit 0.8.6 → 0.9.2
- `ndaal-sa-2026-022` — rcgen 0.13.2 → 0.14.7
- `ndaal-sa-2026-023` — reqwest 0.12.28 → 0.13.2
- `ndaal-sa-2026-024` — toml 0.8.23 → 1.1.2
- `ndaal-sa-2026-025` — meilisearch-sdk 0.28.0
  → 0.33.0
- `ndaal-sa-2026-026` — sysinfo 0.32.1 → 0.38.4
- `ndaal-sa-2026-027` — pulldown-cmark 0.12.2 →
  0.13.3
- `ndaal-sa-2026-028` — hashbrown 0.15.5 →
  0.17.0
- `ndaal-sa-2026-029` — sha2 0.10.9 → 0.11.0
- `ndaal-sa-2026-030` — rustls / typenum /
  winnow compat bundle
- `ndaal-sa-2026-031` — **redb 2.6.3 → 4.1.0**
  (includes a Migration note — the on-disk
  format changed from v2 to v3 and is NOT
  backward compatible; see the advisory for
  the operator rollout)

Each advisory ships with the full ndaal sidecar
triplet
(`.sha-256`, `.sha-512`, `.sha3-512`) in
hyphenated form. Operators upgrading to
v0.1.34 should at minimum review
`ndaal-sa-2026-031` before restarting a
production instance on top of an existing
redb database file.

### Moksha Feeder (since v0.1.47)

The Moksha feeder imports moksha.dk self-issued
advisories (CVE JSON 5.1 records, `MOKSHA-YYYY-NNNN`,
GCVE-cross-referenced) from the CIRCL
Vulnerability-Lookup dumps. It is scheduled
**35 minutes after application start, then every
24 hours** (staggered so it does not contend with
the CSAF burst at boot).

- **Live source**:
  `https://vulnerability.circl.lu/dumps/moksha.ndjson`
  over TLS 1.3 (reqwest + rustls).
- **Offline fallback**: if the live download fails,
  the feeder verifies the bundled
  `dumps_archive/moksha.7z` against its SHA3-512
  sidecar (`moksha.7z.sha3-512`), decompresses it
  in-process with `sevenz-rust`, and imports that
  copy. The control node therefore stays usable
  without network access.
- **Duplicate prevention**: redb upsert on the
  lowercased advisory id.
- **Cross-linking**: every CVE a Moksha advisory
  references is cross-linked, so the advisory
  surfaces in those CVEs' aggregated JSON and
  enrichment cards.

Records feed the `/dashboards/moksha` dashboard, listed in
the navbar under the **Enrichments & charts** group.

### NVD API Key

Set for higher rate limits (optional):

```bash
export NVD_API_KEY=your-key-here
```

Without a key: 5 requests per 30 seconds.
With a key: 50 requests per 30 seconds.

## VulnCheck KEV (encrypted API token)

VulnCheck publishes an extended Known-Exploited-Vulnerabilities
catalogue (a superset of CISA KEV, with earlier/richer entries). Unlike
CISA KEV, OSV, and the other feeds — which are anonymous public downloads
— the VulnCheck **Community KEV API requires a free account and an API
token** (`Authorization: Bearer <token>`; the token expires after 30 days
of non-use). Because this token is a reusable credential, nvulnlookup
stores it **encrypted at rest**, never in plaintext and never in a config
file.

### 1. Obtain a token

Register for a free VulnCheck Community account and issue a token:

- <https://docs.vulncheck.com/getting-started/register>
- <https://docs.vulncheck.com/getting-started/api-tokens>

nvulnlookup cannot create the account for you.

### 2. Choose the encryption passphrase

The token is sealed with **ChaCha20-Poly1305 AEAD** under a key derived
from an operator **passphrase** via **Argon2id** (RFC 9106, m = 64 MiB,
t = 3, p = 4). The passphrase is supplied through the environment and is
**never stored on disk**:

```bash
export VL_SECRET_PASSPHRASE='a long, unique operator passphrase'
```

The **same** passphrase must be present:

- when you set the token (below), so it can be encrypted, and
- in the `vl-web` server's environment at startup, so the feeder can
  decrypt it.

If the passphrases differ, decryption fails and the feeder simply skips
(no crash, no plaintext leak). Treat the passphrase like any other
secret: inject it via a systemd `EnvironmentFile=` with `0600`
permissions, a secrets manager, or `Environment=` — not a shell history.

### 3. Store the token (encrypted)

```bash
export VL_SECRET_PASSPHRASE='…'          # same value the server will use
vl-cli set-secret --vulncheck-kev '<YOUR_VULNCHECK_TOKEN>'
# -> Stored the encrypted VulnCheck KEV token (app_settings/vulncheck_kev_token).
```

The command derives the key, encrypts the token
(`salt ‖ nonce ‖ ciphertext+tag`, base64), and writes the blob to the
`app_settings` table under the key `vulncheck_kev_token`. Nothing
plaintext is written; the passphrase is not persisted. The command
refuses an empty token and errors clearly if `VL_SECRET_PASSPHRASE` is
unset.

### 4. How the feeder uses it

At startup the VulnCheck KEV feeder reads the encrypted blob from
`app_settings`, decrypts it with `VL_SECRET_PASSPHRASE`, and — if a token
is present — pulls the full VulnCheck KEV catalogue over TLS via the
authenticated bulk backup endpoint. That Bearer-authenticated call returns
a short-lived pre-signed download URL plus a SHA-256; the feeder verifies
the downloaded archive against that hash before unpacking and storing the
exploited-vulnerability entries alongside the CISA / CIRCL / EUVD KEV
sources. If no token is configured, or the passphrase is
absent or wrong, the feeder **self-skips cleanly** and the other KEV
sources are unaffected. In the KEV dashboard the VulnCheck source is
listed immediately to the left of ndaal KEV.

### 5. Rotate or remove the token

Re-running `set-secret --vulncheck-kev` **overwrites** the stored value
(upsert), so rotation is just a re-run with the new token. Rotate the
token whenever it may have been exposed. To disable VulnCheck KEV, delete
the row (`DELETE FROM app_settings WHERE key = 'vulncheck_kev_token';`)
and the feeder reverts to self-skipping.

> **Security note.** The encrypted blob — which embeds the random
> derivation and nonce header — is safe to back up (it is useless
> without the passphrase). The passphrase itself is the only secret:
> losing it means re-issuing and re-storing the token, and leaking it
> (together with the database) exposes the token, so rotate both.

## Monitoring

### Health Endpoint

```bash
curl -sk https://localhost:8080/api/v1/system/health
# {"status":"healthy","storage":"embedded (redb)",
#  "database":"embedded (sqlite)"}
```

### System Info

```bash
curl -sk https://localhost:8080/api/v1/system/info
```

Returns: version, uptime, total vulnerabilities,
source counts, database sizes, memory usage.

### Dashboard

Web UI at `/dashboard` shows:

- CVE publishing statistics (daily rate,
  mean gap, batch rate, top CNAs)
- CVSS severity distribution (3.1/4.0 toggle)
- Feeder activity summary

#### Per-source dashboards (since v0.1.34)

Every CSAF / OSV / KEV / national-CERT source has its own
dashboard under `/dashboards/<slug>` — see the navbar
"Dashboards" dropdown for the live list (76 entries in
v0.1.44, +1 for the new `gsd` row). Each dashboard renders
the source's last 25 entries with HTMX pagination plus a
per-advisory drill-down at
`/dashboards/<slug>/<advisory_id>`. Dashboards are auto-
registered from `routes::vendor_dashboard::VENDOR_SPECS`;
adding a row to that table ships a new dashboard without
template edits.

##### New in v0.1.44 — `gsd` dashboard

A `VendorSpec` row was added for the Cloud Security
Alliance Global Security Database at
`/dashboards/gsd` (alphabetically between `github` and `go`
in the "Vulnerability feed" category). The dashboard is
the first to surface a `maintenance_note` banner: a yellow
`alert alert-warning` block warning operators that the
upstream repo was last updated 2024-04-29 and the
displayed entries are a historical snapshot.

Operational notes:

- On a fresh install the navbar shows the dashboard
  immediately, but the dashboard body may render only
  ~119 rows for the first **2 h 17 m** of process
  uptime — these come from the seed corpus / git-clone
  warm-up. At `process_start + 2h17m` the archive
  fallback fires and the row count jumps to **~172 k**.
- The fallback is one-shot per process. It is gated on
  the current row count: if storage already has more
  than 100 gsd entries the fallback self-skips with
  rc=0, so re-runs against a healthy database are free.
- Before extraction the fallback verifies the
  `dumps_archive/gsd.7z.sha3-512` sidecar against the
  archive contents. A SHA-3-512 mismatch aborts the
  fallback (the existing rows are not touched).
- If either `dumps_archive/gsd.7z` or the sidecar is
  missing on disk, step 0 downloads them from the
  pinned GitLab raw URL at commit
  `1caad822901fd12dd464762fddc9c4cc788fc738` and writes
  them into `dumps_archive/` before SHA verification.
  Sites that air-gap `dumps_archive/` should pre-stage
  both files or pre-mirror the GitLab raw URL.

##### New in v0.1.44 — SHA-validation gate on 9 git feeders

The following 9 git-backed feeders now reject a
`last_update` value that does not look like a 40-character
lowercase-hex SHA before taking the
`changed_files_since(prev_sha, HEAD)` incremental path:
`gsd`, `bitnami_vulndb`, `cnvd`, `drupal`, `cvelistv5`,
`fstec`, `emb3d`, `github`, `osv_golang`.

**Symptom of the bug this fixes.** A feeder that has run
at least once shows a populated `last_update` value
(usually an RFC-3339 timestamp from an earlier upgrade
that stored timestamps instead of SHAs) but its source
table holds only the seed row (`db_size: 1`). Until the
gate, the feeder would call `changed_files_since` with a
timestamp where a SHA was expected; the upstream API
returns an empty diff and the source stays stuck on the
seed corpus indefinitely.

The fix routes any non-SHA `last_update` value through the
full re-import path on the next feeder cycle, then writes
back a real SHA so subsequent cycles are incremental
again. No operator action is required — the recovery is
automatic on the first feeder cycle after upgrade. Watch
for the log line
`feeder=<name> last_update=<value> reason="not a 40-char
git SHA" → full re-import` during the rollover.

#### Special-case dashboards

Five dashboards live outside the auto-generated `VENDOR_SPECS`
mechanism because they have custom URL shapes or carry data
that's not a 1:1 vendor-source mapping:

| Slug | Since | Source |
| --- | --- | --- |
| `/dashboards/capec-enrichment` | v0.1.36 | `crates/vl-feeders/src/feeders/capec_dashboard.rs` |
| `/attacks/cwe` | v0.1.36 | `crates/vl-feeders/src/feeders/cwe_dashboard.rs` |
| `/dashboards/debian` | v0.1.31 | `crates/vl-feeders/src/feeders/debian_dashboard.rs` |
| `/dashboards/epss` | v0.1.41 | `crates/vl-feeders/src/feeders/epss_dashboard.rs` |
| `/dashboards/gcve-enrichment` | v0.1.36 | `crates/vl-feeders/src/feeders/gcve_dashboard.rs` |
| `/dashboards/nuclei_templates` | v0.1.41 | `crates/vl-feeders/src/feeders/nuclei_dashboard.rs` |
| `/dashboards/kev-ransomware` | **v0.1.42** | `crates/vl-feeders/src/feeders/kev_ransomware.rs` (Greynoise feed) |
| `/dashboards/cve-vs-github` | **v0.1.42** | `crates/vl-feeders/src/feeders/cve_vs_github_dashboard.rs` (CVSS-deviation aggregator) |

Operational notes:

- Each dashboard's data lives in its own redb table (e.g.
  `KEV_RANSOMWARE_DASHBOARD`, `CVE_VS_GITHUB_DASHBOARD`) and
  is recomputed at the end of every feeder cycle (24 h
  cadence). Empty bodies on a fresh deployment usually mean
  the aggregator has not yet completed its first sweep —
  check `journalctl -u nvulnlookupd | grep -i dashboard` to
  confirm the cycle ran.
- Raw aggregate JSON is exposed at
  `/api/v1/<dashboard-slug>/{key}` for every dashboard with
  a `key` allow-list (see API_Reference.md for the per-
  dashboard key sets).

#### Per-CVE enrichment cards (since v0.1.42)

Every `/vulnerability/{id}` page now renders one card per
available enrichment source, plus an aggregated bundle card.
Cards link to:

- `/api/v1/vulnerability/{id}/enrichment` — bundle (every
  available surface in one JSON)
- `/api/v1/vulnerability/{id}/enrichment/{source}` —
  per-source (14 slugs: `capec`, `debian-security`, `gcve`,
  `epss`, `cisa-kev`, `nuclei`, `github`, `go`, `maven`,
  `npm`, `nuget`, `packagist`, `pub-dev`, `python`)

Sources without data for the requested CVE are filtered out
of the cards section AND return `404 Not Found` from the
per-source endpoint, so the operator can distinguish
"unindexed" from "schema-illegal source slug".

### Log Monitoring

```bash
# Follow logs
journalctl -u nvulnlookupd -f

# Filter feeder activity
journalctl -u nvulnlookupd | grep "Feeder"
```

## Backup and Recovery

### Verified database snapshots (recommended)

`save_app_data.sh` produces a **verified,
sidecar-signed snapshot of the databases**
(`vlookup.db` + `vulnerabilities.redb`; the
`feeders/` cache is intentionally excluded). It
gracefully stops vl-web for a consistent copy,
proves every copied file is byte-for-byte the
source (`cmp`), writes `.sha-256` / `.sha-512` /
`.sha3-512` sidecars per file, and only then
atomically replaces `dumps_data/`:

```bash
bash scripts/save_app_data.sh
# → dumps_data/{vlookup.db,vulnerabilities.redb} + sidecars
```

Compress the snapshot for archival (7z LZMA2
mx=9, per-file sidecars + validation, mirrors
`compress_dumps.sh`):

```bash
bash scripts/compress_app_data.sh
# → dumps_data_archive/<file>.7z + sidecars
```

Restore is the inverse: it stops the app,
validates each file's sidecars and a `cmp`
against the snapshot (primary) — or verifies the
`.7z` sidecars + 7z integrity then extracts
(fallback from `dumps_data_archive/`) — overlays
the validated databases in place so the
`feeders/` cache survives, then starts the app
and health-checks it:

```bash
bash scripts/restore_app_data.sh
# RESTORE_START_APP=0 restores without starting the app
```

Each script is canonical ndaal bash (lint-clean,
sibling `.bats`) and self-skips cleanly when a
prerequisite is missing.

### Backup (simple copy)

```bash
# Stop server (optional for consistency)
systemctl stop nvulnlookupd

# Copy data directory
cp -r data/ backup/data-$(date +%Y%m%d)/

# Restart
systemctl start nvulnlookupd
```

### Backup (7zip compressed)

Compress the entire `data/` directory with
maximum 7zip compression. Archive is verified
(listing + integrity) after creation:

```bash
bash scripts/compress_data.sh
# Output: data_archive/data-<timestamp>.7z
# LZMA2 mx=9 mfb=273 md=1536m myx=9
```

To verify an existing archive:

```bash
7z l data_archive/data-*.7z   # list contents
7z t data_archive/data-*.7z   # integrity test
```

### Backup (dumps archive)

Compress individual NDJSON dump files:

```bash
bash scripts/compress_dumps.sh
# Output: dumps_archive/<source>.7z
```

### Recovery

From a raw copy:

```bash
systemctl stop nvulnlookupd
rm -rf data/
cp -r backup/data-YYYYMMDD/ data/
systemctl start nvulnlookupd
```

From a 7zip archive:

```bash
systemctl stop nvulnlookupd
rm -rf data/
7z x data_archive/data-<timestamp>.7z -o./
systemctl start nvulnlookupd
```

### Disaster recovery — rebuild the redb from per-source dumps

When the live redb (`data/vulnerabilities.redb`) is lost or
corrupted **and there is no `dumps_data` / `dumps_data_archive`
app-snapshot** to restore from (see
[Verified database snapshots](#verified-database-snapshots-recommended)
above), rebuild the vulnerability store from the per-source NDJSON
dumps. The canonical tool is
[`vulnerability-lookup-rs/scripts/import_sources_ndaal_dumps.sh`](../scripts/import_sources_ndaal_dumps.sh).

redb is single-writer, so the script manages the lock end-to-end:

1. Stops a running `vl-web` to free the redb write lock (or aborts
   with "stop vl-web first" under `--no-manage-server`).
2. For each source, selects the **newest usable dump via a fallback
   chain**: newest `dumps/<source>*.ndjson` candidate → older
   candidate → `dumps_archive/<source>.7z` (decompressed). When the
   live redb is gone and no `dumps/` files exist, the
   `dumps_archive/*.7z` tier is what rebuilds the database.
3. Validates the cryptographic sidecars and **verifies each dump
   BEFORE import** — per-line JSON schema, entry count, and no
   duplicate ids in-file. A dump failing any check is rejected and
   the next candidate tried (never imported).
4. Stages each chosen dump as `<source>.ndjson` (so `vl-cli` derives
   the source from the file stem) and runs **one**
   `vl-cli import-dumps --dir <stage>` for all staged sources
   (idempotent upsert → no DB duplicates).
5. Restarts `vl-web`, health-checks it, then gates on a 25-entry DB
   compare per source. Emits SARIF 2.1.0 + Markdown to
   `documentation/dumps/import/<TIMESTAMP>/`.

```bash
cd vulnerability-lookup-rs

# Rebuild every source's store from the newest verified dump
# (falls back to dumps_archive/<source>.7z when dumps/ is empty)
bash scripts/import_sources_ndaal_dumps.sh

# One source only, fail the run on any verification error:
bash scripts/import_sources_ndaal_dumps.sh --source nvd --strict
```

Useful flags: `--source <S>` (one source), `--no-manage-server`
(refuse to stop/start `vl-web`; if it is running, abort — if
stopped, import and skip the DB compare), `--no-db-compare` (skip the
post-import compare), `--strict` / `IMPORT_STRICT=1` (exit non-zero on
any failure).

**Standalone manual fallback** (no script): stop `vl-web`, decompress
each archived dump to a staging directory, run a single
`import-dumps`, then restart:

```bash
systemctl stop nvulnlookupd        # free the redb write lock
mkdir -p /tmp/vl-restore
for a in dumps_archive/*.7z; do
    7z x -y -o/tmp/vl-restore "$a"  # → /tmp/vl-restore/<source>.ndjson
done
cd vulnerability-lookup-rs
./target/release/vl-cli import-dumps --dir /tmp/vl-restore
systemctl start nvulnlookupd
```

### Database Reset

Two options, depending on the scope of the reset.

**Surgical (keeps users, sightings, audit log)** — clear only the
vulnerability store and re-populate from the committed NDJSON dumps:

```bash
cargo run -p vl-cli -- clear-db
cargo run -p vl-cli -- import-dumps --dir dumps
```

**Full cold reset (destroys every user + sighting + audit-log row)** —
see
[`vulnerability-lookup-rs/scripts/delete_all_data.sh`](../scripts/delete_all_data.sh).
The script stops `vl-web`, removes the six known files under `data/`
(each listed by name, existence-checked, no wildcards), restarts
the release build with `--features quic`, waits for
`/api/v1/system/health` to respond, verifies that
`vulnerabilities.redb` was freshly recreated (mtime ≤ 120 s), and
confirms the heavy feeders
(`cna_scorecard`, `debian_security_tracker`, `cvelistv5`,
`cwe_enrichment`, `capec`) are all at ≤ 5 rows so that the delete
actually took.

```bash
vulnerability-lookup-rs/scripts/delete_all_data.sh
# or stop + delete without restart:
vulnerability-lookup-rs/scripts/delete_all_data.sh --no-start
```

Env knobs: `DATA_DIR`, `VL_BASE_URL`, `MAX_ENTRIES` (total ceiling,
default 5000), `MAX_MAJOR_ENTRIES` (per-heavy-source ceiling,
default 5), `STARTUP_TIMEOUT` (seconds, default 90),
`BUILD_FEATURES` (default `quic`).

## Systemd Service

```ini
[Unit]
Description=nvulnlookup vulnerability server
After=network.target
Documentation=https://gitlab.com/vPierre/ndaal_public_nvulnlookup

[Service]
Type=simple
User=nvulnlookup
Group=nvulnlookup
WorkingDirectory=/opt/nvulnlookup
ExecStart=/opt/nvulnlookup/vl-web
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
Environment=RUST_LOG=info

# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/nvulnlookup/data
ReadWritePaths=/var/log/nvulnlookup
PrivateTmp=true

[Install]
WantedBy=multi-user.target
```

## Resource Requirements

| Resource | Minimum | Recommended |
| --- | --- | --- |
| CPU | 2 cores | 4 cores |
| RAM | 2 GB | 8 GB |
| Disk | 5 GB | 50 GB |

Disk usage depends on feeder count and
history retention. The redb database grows
as vulnerabilities accumulate; expect
~20 GB with all 135 feeders active.

## CLI Commands

```bash
# Database management
vl-cli db init          # Run migrations
vl-cli db count         # Show entry count
vl-cli db reindex       # Rebuild search indexes
vl-cli db backup -o f   # Backup SQLite

# User management
vl-cli create-admin --login admin \
    --name Admin --email a@b.com
vl-cli user-list

# Data import
vl-cli import-dumps --dir dumps
vl-cli clear-db         # Reset vuln DB
```

> `vl-cli import <source>` is a stub — it validates the source name
> against the feeder config but does not run a feeder cycle. The
> running `vl-web` tokio scheduler is the only component that
> actually executes feeders. Use
> [`feed_25_recent_over_all_sources.sh`](#feed-sweep--feed_25_recent_over_all_sourcessh)
> to verify coverage once the scheduler has run.

### Rebuilding the search indexes (`db reindex`)

`vl-cli db reindex` rebuilds **both** search
indexes over every stored vulnerability: the
redb token index, and — since v1.2.66 — the
tantivy full-text index under
`<data dir>/tantivy`. Tantivy is what the
search ladder prefers, so a deploy path that
built only the token index left the full-text
engine empty and every query fell through it;
the rebuild silently changed nothing a user
could see.

Both indexes populate on write, so rows that
predate an index are invisible to indexed
search until this runs. Run it after a bulk
import, and after any upgrade that introduces
a new index. It is safe to re-run and safe to
interrupt: it commits in batches, and
re-indexing a row is a no-op. It prints a
record count and an elapsed time per index.

## Operational Scripts

Canonical entry point:
[`scripts/quality_gates.sh`](../../scripts/quality_gates.sh) at
**repo root** — every CI gate is wired through it.
See `scripts/quality_gates.sh --help`.

### Bash script standards

Every bash script under `scripts/` and `tests/scripts/` (and every
new script added below) starts with the same hardened header so a
script that fails fails *loudly* and a script that writes files
writes them with safe permissions. When you copy-paste an existing
script as a starting point, keep this block intact:

```bash
# Enable strict mode
set -o errexit  # Exit on error
set -o errtrace # Exit on error in functions
set -o nounset  # Exit on undefined variables
set -o pipefail # Exit on pipe failures
# set -o xtrace # Uncomment for debugging

# Set safe field separator
# nosemgrep: ifs-tampering
IFS=$'\n\t'

# Sets the file creation mask to 077, meaning new files get permissions 600
# (read/write for owner only) and directories 700 (read/write/execute for owner only).
# Enhances security by ensuring new files and directories are only accessible
# to the owner, preventing unauthorized access.
umask 077
```

Why each line is there:

- `errexit` — abort the script on any unhandled non-zero exit.
- `errtrace` — propagate `errexit` into functions, subshells, and
  `( ... )` blocks so failures inside helpers are not swallowed.
- `nounset` — reject any unset variable expansion; catches typos
  like `${USER_ID}` vs `${USER_id}` at runtime.
- `pipefail` — a pipeline's exit code is the *first* failing
  stage's, not the last stage's.  Without this, `cmd1 | tee log`
  always returns `0` even when `cmd1` crashes.
- `IFS=$'\n\t'` — drop space from the word-splitter so filenames
  with spaces don't get torn apart in `for f in $list`. The
  `# nosemgrep: ifs-tampering` annotation tells our Semgrep
  config this is the intentional safe form, not an attacker-
  controlled IFS hijack.
- `umask 077` — every file the script creates lands at mode
  `0600`, every directory at `0700`. Prevents the common
  bug of leaving a temp log file world-readable when it
  contains an API token, an SBOM with internal hostnames, or
  a fresh self-signed key.

Lint gates that enforce this header:

- `shfmt -d -i 0 -bn -ci -sr` — formatting parity check.
- `shellcheck -o all` — strict mode (every optional rule on);
  any finding is actionable. Disable with a file-scope
  `# shellcheck disable=SCxxxx` directive **before** the first
  command, with a one-line rationale.
- `bash -n script.sh` — pure parser check, no execution.

All three are run by `scripts/quality_gates.sh` under the
`linters` gate (and as part of `scripts/run_qa.sh` for the
quick local pass).

### Testing bash scripts with bats-core

Every committed `*.sh` in this repo ships a sibling
[bats-core](https://github.com/bats-core/bats-core) test file
(`*.sh` → `*.bats`) living next to it in the same directory. The
sibling test is **structural**: it verifies CLAUDE.md compliance
(strict-mode header, traps, SPDX, locale/umask block, anchors,
verbose flags, …) by `grep`-ing the script source — it does **not**
execute the script's side effects (no builds, network fetches, or
live-server probes). The canonical template lives at
`skills/bats/assets/template.bats`; the full contract is documented
in `skills/bats/SKILL.md`.

#### Install bats-core

```bash
# macOS (Homebrew)
brew install bats-core

# Debian / Ubuntu
sudo apt-get install -y bats

# From source (any platform) — pins a known version
git clone https://github.com/bats-core/bats-core.git
cd bats-core && sudo ./install.sh /usr/local

# Verify
bats --version          # e.g. Bats 1.13.0
```

#### Test a single script

Run a script's sibling `.bats` directly:

```bash
# Human-readable (pretty) output
bats vulnerability-lookup-rs/tests/scripts/test_opengrep.bats

# TAP output (machine-parseable, good for CI)
bats --tap vulnerability-lookup-rs/tests/scripts/test_opengrep.bats
```

Always run the sibling `.bats` after **every** create/update of a
`*.sh`, alongside the `bash -n` / `shfmt -d` / `shellcheck -o all`
triple. All tests must pass before commit.

#### Sweep every `.bats` in the repo

`vulnerability-lookup-rs/tests/scripts/test_bats.sh` discovers and
runs every `.bats` in the workspace, archiving TAP / JUnit XML /
stderr plus a `SUMMARY.tsv` and `summary.txt` rollup under
`documentation/shell/bats/<ISO-8601-utc>/`. Each child `.bats` runs
under `timeout(1)` (default 60 s, override with
`BATS_PER_FILE_TIMEOUT=…`) so a hung probe cannot stall the sweep,
and it self-skips with rc=0 when `bats` is not on `PATH` (so it
never breaks a CI host that lacks the tool):

```bash
bash vulnerability-lookup-rs/tests/scripts/test_bats.sh
```

It is also wired into `scripts/quality_gates.sh`.

#### Example output

bats emits TAP: `ok N <name>` for a pass, `not ok N <name>` for a
failure, and `ok N <name> # skip <reason>` for an overlay test that
does not apply to the script under test. Abbreviated run of
`test_opengrep.bats` (37 tests):

```text
1..37
ok 1 test_opengrep.sh exists and is executable
ok 2 test_opengrep.sh passes bash -n syntax check
ok 3 test_opengrep.sh passes shfmt format check
ok 4 test_opengrep.sh passes shellcheck -o all
ok 5 test_opengrep.sh has the canonical 3-line SPDX header
ok 6 test_opengrep.sh installs the canonical CLAUDE.md trap set
ok 7 test_opengrep.sh enables errexit / errtrace / nounset / pipefail / inherit_errexit
...
ok 15 test_opengrep.sh exports deterministic LC_ALL / LANG / LC_COLLATE / TZ before umask
ok 17 test_opengrep.sh sets canonical IFS, umask 077, and defensive shopt options
...
ok 23 test_opengrep.sh self-skips cleanly ... # skip opengrep has network + multi-minute scan side effects
ok 25 mkdir invocations use -p -v
ok 26 chmod invocations use -v # skip script does not use chmod
ok 34 TIMESTAMP declared with path-safe (hyphens) + readonly + printf trio
ok 35 TIMESTAMP_DISPLAY declared with SARIF (colons) + readonly + printf trio # skip script does not declare a TIMESTAMP_DISPLAY variable
ok 37 script uses canonical SCRIPT_PATH (not SCRIPT_DIR or script_dir)
```

A clean run ends with every line beginning `ok`; any `not ok`
fails the gate. `# skip` lines count as passes — they record that
an overlay test correctly recognised the script does not use that
construct.

#### Standard template tests and their purpose

The canonical template ships **36 active tests** (plus an optional
8-test CLI overlay). A script may add extra `@test` blocks for its
own contracts, but must never drop a template test.

**23 structural tests** (always run):

| # | Test | Purpose |
| --- | --- | --- |
| 1 | exists & executable | the `.sh` is present and has the executable bit |
| 2 | `bash -n` | parses without syntax errors (no execution) |
| 3 | `shfmt -d` | matches the canonical formatter (`-i 0 -bn -ci -sr`) |
| 4 | `shellcheck -o all` | clean under every optional rule group |
| 5 | SPDX header | the canonical 3-line Apache-2.0 / ndaal header |
| 6 | trap set | `ndaal_cleanup` EXIT, `ndaal_on_error` ERR, HUP/INT |
| 7 | strict-mode flags | `errexit`/`errtrace`/`nounset`/`pipefail`/`inherit_errexit` |
| 8 | commented `set -o` quartet | the documented (not bare) strict-mode block |
| 9 | `# Strict mode` header | the section-header marker is present |
| 10 | no bare `set -o errexit` | rejects the un-commented condensed form |
| 11 | xtrace-OFF rationale | the secret-leakage note + `DEBUG=1` example |
| 12 | no unconditional xtrace | bans `set -x` / `set -o xtrace` / `set -euxo` |
| 13 | no `BASH_XTRACEFD` redirect | anti-evasion guard for the xtrace ban |
| 14 | bash ≥ 4.4 guard first | the version check precedes `set -o errexit` |
| 15 | locale before umask | `LC_ALL`/`LANG`/`LC_COLLATE`/`TZ` exports precede `umask` |
| 16 | comment-block headers | the canonical CLAUDE.md section markers |
| 17 | IFS / umask / shopt | `IFS=$'\n\t'`, `umask 077`, `nullglob`, `shift_verbose` |
| 18 | tmpdir + cleanup fns | `NDAAL_TMPDIR` + `ndaal_cleanup()` + `ndaal_on_error()` |
| 19 | path anchors | `SCRIPT_NAME`/`SCRIPT_PATH`/`SCRIPT_PATH_WITH_NAME`/`REPO_ROOT`, each `readonly` |
| 20 | `print_script_info` defined | the canonical footer function exists |
| 21 | hardened footer | footer disables ERR trap + uses `cd -P --` / `dirname --` |
| 22 | 2-line exit footer | blank line then explicit `exit` |
| 23 | self-skip rc=0 | the script exits 0 when its tool is absent (dropped/skipped for scripts with real side effects) |

**Overlay tests** (each SKIPS cleanly when not applicable, except
the SCRIPT_DIR ban which always runs):

| Group | Tests | Purpose |
| --- | --- | --- |
| Verbose flags | 5 | `mkdir -p -v`, `chmod -v`, `rm -f -v`, `mv -v`, `cp -f -p -v` — every filesystem mutation stays auditable in the run log |
| VERSION | 4 | a top-level `VERSION` is a dotted-decimal literal, marked `readonly` (split form), and printed via the canonical `printf … >&2` |
| TIMESTAMP | 2 | `TIMESTAMP` (path-safe hyphens) and `TIMESTAMP_DISPLAY` (SARIF colons) each carry the full declaration + `readonly` + `printf` trio |
| Function-local timestamp | 1 | a helper's `local timestamp` uses the SARIF colon form + split `readonly` + canonical printf |
| SCRIPT_DIR ban | 1 | hard-fails on off-pattern `SCRIPT_DIR` / `script_dir` (use the canonical anchors instead) |
| CLI overlay (optional) | 8 | for scripts exposing `--help`/`-h`/`-H`/`--version`/`-V`: each flag exits 0 under a `timeout`, prints `USAGE:`, and `parse_cli_options` short-circuits before `main` with no side effects |

When an overlay genuinely cannot hold for a vendored upstream
script you must not rewrite, skip just that test with
`skip "rationale (issue #NNN)"` and note the exception in the
`.bats` header comment.

### Complete catalog — `vulnerability-lookup-rs/scripts/`

Every script listed below is CLAUDE.md-compliant (strict mode,
`IFS=$'\n\t'`, array expansion where CLI args are dynamic,
shellcheck clean) and lands reports under
`documentation/<name>/<ISO>/` or `logs/<name>_<ISO>/`
depending on whether the output is audit-worthy or transient.

| Script | Purpose | Typical usage |
| --- | --- | --- |
| `build_all_targets.sh` | Cross-compiles all three release triples (x86_64/aarch64 Linux + macOS) via `cargo-zigbuild`. | `./build_all_targets.sh` |
| `build_secure.sh` | Security-hardened release build (PIE / RELRO / stripped, `-C relocation-model=pie`), SBOM, SHA-256 + SHA3-512 per binary. | `./build_secure.sh` |
| `compress_data.sh` | Snapshot `data/vulnerabilities.redb` + `data/vlookup.db` into a timestamped `.7z` archive before destructive ops. | `./compress_data.sh [out.7z]` |
| `compress_dumps.sh` | Re-archive every `dumps/<source>.ndjson` into `dumps_archive/<source>.7z` (mx=9). Skips files unchanged since the previous snapshot. | `./compress_dumps.sh` |
| `cvelist_to_csv.sh` | Convert CVE List v5 JSON dumps to CSV for spreadsheet ingest. | `./cvelist_to_csv.sh <dir> [--out file.csv]` |
| `delete_all_data.sh` | Cold-reset runtime state — stop vl-web, explicitly remove each file under `data/` (no wildcards), restart, verify redb mtime ≤ 120 s + heavy feeders at ≤ 5 rows. **Destroys users, sightings, audit log.** | `./delete_all_data.sh` (add `--no-start` to stop+delete only) |
| `feed_25_recent_over_all_sources.sh` | Read-only sweep — for every source in `/api/v1/vulnerabilities/sources`, fetch 25 recent entries + run `test_unknown_fields.sh` per source. Dynamic source discovery. | `./feed_25_recent_over_all_sources.sh` or `--dry-run` |
| `fetch_dumps.sh` | Pull upstream NDJSON dumps from the CIRCL / ndaal release feeds into `dumps/`. Multi-GB — gate behind `RUN_DATA_LIFECYCLE=1` in CI. | `./fetch_dumps.sh [--source <name>]` |
| `generate_db_schema_docs.sh` | Regenerate `documentation/db_schema.md` from `storage.rs` (every `TableDefinition`) + SQL migrations. Adds live `.schema` snapshot when `data/vlookup.db` exists. | `./generate_db_schema_docs.sh [out.md]` |
| `generate_role_tests.py` | Programmatic source of the 46 `test_*.yml` wrappers under both Ansible roles. Rerun after adding a new helper script. | `python3 generate_role_tests.py` |
| `import_and_verify_dumps.sh` | Import every `dumps/*.ndjson` via `vl-cli import-dumps` and verify post-import counts match the dump's line count. | `./import_and_verify_dumps.sh [--dir dumps]` |
| `run_all_tests.sh` | Phased bash test runner — mirrors the 8-phase Ansible `tests/test.yml`. Env gates: `RUN_CLEAN_STATE`, `RUN_BUILD_ALL_TARGETS`, `RUN_DATA_LIFECYCLE`, `RUN_LIVE_FEED`, `RUN_SCAN_DUMPS`, `RUN_UI_BROWSER`, `RUN_BENCHMARK`. | `./run_all_tests.sh` (default: ~5 min) |
| `run_qa.sh` | Single-shot QA gate — fmt + clippy + shellcheck + yamllint + markdownlint + ryl + rumdl + ruff + bandit. Exits non-zero on any red. | `./run_qa.sh` |
| `scan_dumps_dumps_archive_with_clamav_yara.sh` | ClamAV (`--max-filesize=1900M`) + YARA-Forge full (11 633 rules) over `dumps/` and `dumps_archive/`. | `./scan_dumps_dumps_archive_with_clamav_yara.sh [--skip-update]` |
| `update_ansible_role.sh` | Copy release binaries + static assets into **both** `nvulnlookup` and `nvulnlookuptesting` roles; plant the `files/certs/` placeholder README + `.gitkeep`. Env: `ROLES=...` to override role list, `CERTS_SRC=/path` to seed real certs. | `./update_ansible_role.sh` |

### Complete catalog — `vulnerability-lookup-rs/tests/scripts/`

Higher-level integration tests that assume a **running server**.
All CLAUDE.md-compliant; every one is wrapped by a
`tests/test_*.yml` Ansible playbook.

| Script | Purpose |
| --- | --- |
| `test_ansible_role_assets.sh` | Sanity-check the `files/` layout of both Ansible roles (binary sizes, static count, certs placeholder present). |
| `test_api_bash.sh` | bash-driven API smoke suite — 20+ endpoint assertions. |
| `test_api_python.py` | Python counterpart — richer JSON-schema checks via `jsonschema`. |
| `test_benchmark.sh` | Throughput / latency benchmark wrapper around `oha`. |
| `test_csaf_ndaal.sh` | OASIS **CSAF 2.1** publisher-feed regression test for the in-tree `csaf/2026/*` advisories: required-field coverage, schema-version (`csaf_version` + `metadata_version` == `2.1`), publisher canonical name, GitLab raw-feed reachability. Wired into `quality_gates.sh --fast` as gate 9m. |
| `test_cve_api_probe.sh` | Probe every CVE-returning endpoint (`/api/v1/vulnerability/{id}`, `/api/v1/vulnerabilities/{recent,sources,search}`, enrichment, KEV) for response-shape + HATEOAS compliance. Moved from `scripts/cve_api_probe.sh`. |
| `test_dump_import_feed_cycle.sh` | End-to-end dump-export → import → feeder-cycle loop. |
| `test_enrichment_api.sh` | EPSS / KEV / CWE / CAPEC / GCVE enrichment endpoint checks. |
| `test_ghsa_cve_linking.sh` | GHSA ↔ CVE cross-reference resolution. |
| `test_hateoas_compliance.sh` | RFC 8288 link-relation compliance — `_links.self` matches request URI. |
| `test_live_feed_cycle.sh` | Live feeder cycle against a running server (network-heavy). |
| `test_port_scan.sh` | rustscan + nmap exact-match listener-surface guard. Asserts only configured ports respond (8080 TCP, 8081 UDP, 7700 TCP). Moved from `scripts/port_scan.sh`. |
| `test_sqlmap.sh` | Automated SQL-injection scan via sqlmap. |
| `test_testssl_endpoints.sh` | Full `testssl.sh` 5-format report per configured listener. Fails CI on any MEDIUM-or-above finding. Moved from `scripts/testssl_endpoints.sh`. |
| `test_tls_endpoints.sh` | Low-level TLS 1.3 handshake + ALPN probes (openssl s_client). |
| `test_ui_browser.sh` | Headless-browser UI smoke via Playwright. |
| `test_unknown_fields.sh` | Detect broken data mappings — flags `"unknown"` in Title / Severity / CVSS / Source / Updated. |
| `test_zap_scan.sh` | OWASP ZAP baseline / full / api modes (container or native) against the running TLS listener. Env: `ZAP_JVM_HEAP=768m`, `ZAP_FAIL_ON_MEDIUM=1`. Moved from `scripts/zap_scan.sh`. |

---

### Per-task helpers (detailed)

### Quality-gate runner — `scripts/quality_gates.sh`

> **Renamed in v0.1.37**: the canonical entry point is now
> `scripts/quality_gates.sh` (underscore, glob-friendly). The old
> `scripts/quality-gates.sh` filename has been retired; every active
> reference in the repo has been swept. Historical compliance
> reports under `documentation/compliance/v0.1.{29,34,35}*` keep
> the old name on purpose — they are point-in-time audit records.

**41 gates** in order, broken into ten thematic blocks:

- **Pre-vet preflight (0, 0a)** — `update_audits_toml`, `ansible_cfg`
- **Rust toolchain (1-6)** — `fmt`, `clippy`, `test`, `audit`,
  `deny`, `machete`, `geiger`, `tree_duplicates`, `rust_doctor`,
  `kani`, `vet`, `semver_checks`, `fuzz`
- **Lint + doc (7-7c)** — `linters`, `coverage`, `docs_fresh`,
  `changelog_version`
- **Binary + port (8-8c)** — `fonts`, `binary_audit`, `binary_scan`,
  `port_scan`
- **Live-server (9a-9e)** — `bruno`, `testssl`, `sqlmap`,
  `sqllogictest`, `loadtest`
- **DAST scanners (9f-9j)** — `nuclei_scanner`, `lonkero_scanner`,
  `ffuf_scanner`, `feroxbuster_scanner`, `schemathesis_scanner`
- **Integration (9m-9o)** — `csaf_ndaal`, `ansible_molecule`,
  `web_check`
- **Repo-quality (9p-9q)** — `devguard`, `sql_query_analyzer`
- **Secrets scanners (10-11)** — `betterleaks_scanner`,
  `leaktor_scanner`
- **Blast-radius + Rust tooling sweep (12-31)** — `cargo_impact`,
  plus the gates 13-31 introduced in the post-v0.1.38 hardening
  cycle (see CHANGELOG): `cargo_nextest`, `cargo_cyclonedx`,
  `typos`, `cargo_msrv`, `cargo_udeps`, `cargo_public_api`,
  `cargo_outdated`, `cargo_supply_chain`, `cargo_features_manager`,
  `cargo_spellcheck`, `committed`, `cargo_dylint`, `cargo_mutants`
  (LIVE), `miri` (LIVE), `cargo_careful` (LIVE), `cargo_bloat`
  (LIVE), `cargo_llvm_lines` (LIVE), `cargo_bench` (LIVE),
  `cargo_flamegraph` (LIVE).

LIVE_GATES (skipped under `--fast`): `port_scan`, `bruno`,
`testssl`, `loadtest`, `nuclei_scanner`, `lonkero_scanner`,
`feroxbuster_scanner`, `ansible_molecule`, `betterleaks_scanner`,
`leaktor_scanner`, `cargo_mutants`, `miri`, `cargo_careful`,
`cargo_bloat`, `cargo_llvm_lines`, `cargo_bench`,
`cargo_flamegraph`.

```bash
scripts/quality_gates.sh              # run every gate, summary
scripts/quality_gates.sh --strict     # abort on first red (CI)
scripts/quality_gates.sh --fast       # skip live-server + fuzz
scripts/quality_gates.sh --no-fuzz    # everything except cargo-fuzz
scripts/quality_gates.sh --only fmt,clippy,test
```

#### v0.1.37+ gates — what's new

##### 7b. `docs_fresh` — documentation drift guard

Fails when any of the four canonical documentation files has
NOT been touched within the last 24 h, measured against **both**
the git commit timestamp AND the filesystem mtime — a file passes
if either source is fresh. Files checked:

- `README.md`, `LIESMICH.md`, `LISEZMOI.md` (root)
- `vulnerability-lookup-rs/CHANGELOG.md`

Override the threshold via `QG_DOC_MAX_AGE_SECONDS` (default
86 400 s = 24 h). Belt-and-braces semantics keep the gate
green during a fresh `git checkout` (filesystem mtime resets,
git ts survives).

**How to repair**: edit the affected doc + recommit so the
git commit timestamp updates. A trivial typo fix is fine —
the goal is to flag stale docs at release time.

##### 7c. `changelog_version` — Cargo.toml ↔ CHANGELOG sync

Parses `vulnerability-lookup-rs/Cargo.toml` `[workspace.package]
version = "X.Y.Z"` and the first `## v<X.Y.Z>` heading from
`vulnerability-lookup-rs/CHANGELOG.md`. Fails on mismatch.

**How to repair**: add the missing CHANGELOG entry header
matching the bumped Cargo.toml version, e.g.:

```markdown
## v0.1.37 — yyyy-mm-dd

- ...
```

##### 8c. `port_scan` — listener-surface guard

Delegates to `vulnerability-lookup-rs/tests/scripts/test_port_scan.sh`,
which scans `127.0.0.1`
with rustscan (TCP) + nmap -sU (UDP) + nmap --top-ports 1000
(unexpected-port sweep) and asserts that ONLY the three expected
ports respond:

- **8080** TCP — vl-web HTTPS (HTTP/1.1 + HTTP/2)
- **8081** UDP — vl-web QUIC (HTTP/3)
- **7700** TCP — Meilisearch

Expected ports come from `vulnerability-lookup-rs/config/
generic.json` (`website_listen_port`, `quic_listen_port`) plus
the static Meilisearch default 7700.

Per-run artefacts: SARIF (rustscan / nmap_tcp / nmap_udp) +
human-readable Markdown + raw scanner output, all under
`vulnerability-lookup-rs/documentation/ports/<ISO-8601-Z>/`.

Listed in `LIVE_GATES` so `--fast` skips it (the scan needs
the server bound on its expected ports to PASS). Env knobs:
`PS_HOST`, `PS_TOP_PORTS`, `PS_SKIP_UDP`, `PS_MEILI_PORT`.

#### v0.1.38+ gates — what's new (post-release hardening)

The post-v0.1.38 quality cycle added 19 new gates (13-31) plus
two preflight gates (0, 0a) — see CHANGELOG § "Post-release quality
hardening" for the full breakdown. Operator-relevant highlights:

##### 0. `update_audits_toml` — Google supply-chain cache refresh

Runs **before every other gate** so a transient DNS / GitHub
outage on the upstream Google supply-chain audits.toml does NOT
take down vet (gate 5e). Hardened-curl pipeline (TLS 1.2+,
retry-all-errors, max-time 60 s) writes the file to
`<repo-root>/audits.toml` AND
`vulnerability-lookup-rs/audits.toml`.

```bash
# Override the upstream URL or destination paths
AUDITS_URL=https://internal-mirror.example.com/audits.toml \
AUDITS_DEST_NAMES="audits.toml ops/cache/audits.toml" \
    bash scripts/update_audits_toml.sh

# Skip the network fetch entirely (use cached copy)
UPDATE_AUDITS_OFFLINE=1 bash scripts/update_audits_toml.sh
```

Self-skips cleanly when curl is missing or the upstream is
unreachable after retry — vet falls back to the previously-cached
copy in either case.

##### 0a. `ansible_cfg` — project Ansible.cfg

Renders the canonical ndaal project `ansible.cfg` from an embedded
heredoc to `<repo-root>/ansible.cfg` AND
`vulnerability-lookup-rs/ansible.cfg`, then validates each via
`ansible-config dump --only-changed`. Pre-creates
`~/.ansible/{log,facts_cache,tmp,cp}` at 0700 so the cfg's
`log_path` does not warn on first use.

##### 13-31. Rust tooling sweep

Tier 1 (runs under `--fast`): `cargo_nextest` (parallel test
runner), `cargo_cyclonedx` (Rust-native CycloneDX SBOM), `typos`
(typo-cli), `cargo_msrv` (verify pinned rust-version),
`cargo_udeps` (nightly, complementary to machete),
`cargo_public_api` (API surface snapshots),
`cargo_outdated` (newer-version-available report),
`cargo_supply_chain` (publisher visibility),
`cargo_features_manager` (feature-flag audit),
`cargo_spellcheck` (doc-comment spelling),
`committed` (Conventional Commits linter),
`cargo_dylint` (custom lints).

Tier 2 (LIVE_GATES, skipped under `--fast`):
`cargo_mutants` (mutation testing), `miri` (UB detector,
nightly), `cargo_careful` (hardened std test, nightly),
`cargo_bloat` (binary size), `cargo_llvm_lines`
(monomorphisation cost), `cargo_bench` (Criterion benchmarks),
`cargo_flamegraph` (perf profile).

Each gate self-skips cleanly when the underlying tool is not on
PATH; install one-liners are documented in the CHANGELOG entry.

##### Updated — clippy.toml consolidation

The 5 per-crate `crates/*/clippy.toml` files were removed; their
settings folded into the workspace-level
`vulnerability-lookup-rs/clippy.toml`. Per-crate clippy.toml
files SHADOW (do not merge with) the workspace one, which had
been silently breaking workspace-level `allowed-duplicate-crates`
and `allow-*-in-tests` flags for any per-crate clippy invocation.

After the consolidation, integration test files at
`crates/*/tests/*.rs` carry an explicit
`#![allow(clippy::expect_used, ...)]` block (with documented
reason) covering the test-only patterns that
`allow-*-in-tests` cannot reach because integration tests live
outside any `#[cfg(test)]` module.

##### New — pre-vet preflight chain under `--fast`

The full `--fast` ordering is now:

```text
0   update_audits_toml      (Google audits cache refresh)
0a  ansible_cfg             (write + validate ansible.cfg)
1   fmt
2   clippy
3   test
4   audit
5   deny / 5a machete / 5b geiger / 5b-tree tree_duplicates
5c  rust_doctor
5d  kani (--only or QG_RUN_KANI=1; otherwise SKIP)
5e  vet
5f  semver_checks
6   fuzz (skipped under --fast or --no-fuzz)
7-8 linters / coverage / docs_fresh / changelog_version / fonts
8a-8c binary_audit / binary_scan / port_scan (LIVE)
9-12 (live + DAST + integration + secrets + cargo_impact)
13-24 (Rust tooling sweep — fast tier)
25-31 (Rust tooling sweep — live tier; skipped under --fast)
```

##### Refactored — Gates 1-5f as standalone runner scripts

Every cargo-tooling gate now ships with a dedicated runner under
`vulnerability-lookup-rs/tests/scripts/test_<slug>.sh` that
operators can invoke directly without going through the qg loop.
Same self-skip semantics + canonical bash header as every other
runner. The 12 new runners introduced in the post-v0.1.38
hardening cycle:

| Gate | Slug | Runner | What it does |
| --- | --- | --- | --- |
| 1 | `fmt` | `test_cargo_fmt.sh` | `cargo fmt --all --check` |
| 2 | `clippy` | `test_cargo_clippy.sh` | `cargo clippy --workspace --all-targets --all-features -- -D warnings` |
| 3 | `test` | `test_cargo_test.sh` | `cargo test --workspace --all-features` (lib+integration) AND `--doc` pass |
| 4 | `audit` | `test_cargo_audit.sh` | `cargo audit --deny warnings/unsound/unmaintained/yanked` with audit.toml ignores |
| 5 | `deny` | `test_cargo_deny.sh` | `cargo deny check` (advisories + bans + licenses + sources) |
| 5a | `machete` | `test_cargo_machete.sh` | `cargo machete --with-metadata` |
| 5b | `geiger` | `test_cargo_geiger.sh` | per-crate transitive-unsafe survey, JSON archive |
| 5b-tree | `tree_duplicates` | `test_cargo_tree_duplicates.sh` | `cargo tree --duplicates` (advisory; QG_TREE_DUPLICATES_STRICT=1 to gate) |
| 5c | `rust_doctor` | `test_rust_doctor.sh` | `rust-doctor .` workspace health-score capture |
| 5d | `kani` | `test_cargo_kani.sh` | `cargo kani --workspace` (gated behind QG_RUN_KANI=1) |
| 5e | `vet` | `test_cargo_vet.sh` | `cargo vet check` |
| 5f | `semver_checks` | `test_cargo_semver_checks.sh` | `cargo semver-checks check-release --workspace` |

Standalone invocation:

```bash
cd vulnerability-lookup-rs
bash tests/scripts/test_cargo_fmt.sh        # run just fmt
bash tests/scripts/test_cargo_audit.sh      # run just audit
bash tests/scripts/test_cargo_machete.sh    # ...
QG_RUN_KANI=1 bash tests/scripts/test_cargo_kani.sh  # opt in to kani
```

Each runner captures output under
`documentation/<category>/<tool>_<ISO>/` so cross-run diffing has
a stable artefact path.

#### v0.1.44+ gates — what's new

The v0.1.44 quality cycle moved the running-gate count from **92
→ 98 (+6)**. All six additions land in `--fast` except
`cargo_mend`, which only runs under `--full` because it needs
network access to query crates.io. The six new gates plug the
remaining `cargo-*` audit surface (semver / no-std / outdated /
diet / dep-tree drift / unmaintained-bump suggestions) — see the
CHANGELOG § "v0.1.44 — quality-gate expansion" for the per-gate
breakdown.

##### Ansible role binaries — v0.1.44 refresh

`scripts/update_ansible_role.sh` was re-run as part of the
v0.1.44 build, refreshing the per-binary fixtures under
`tools/ansible/roles/{nvulnlookup,nvulnlookuptesting}/files/`
plus the matching 5-algorithm sidecars (`.sha-256`,
`.sha-512`, `.sha3-512`, `.blake3-512`, `.shake256-512`) and
the new RPM packages. RPM filename pattern (one per arch):

```text
vl-cli-0.1.44-1.aarch64.rpm
vl-cli-0.1.44-1.x86_64.rpm
```

Both `.rpm` files ship with their full 5-algorithm sidecar
trio. Re-verify a deploy with:

```bash
( cd tools/ansible/roles/nvulnlookup/files \
  && sha3sum -a 512 -c vl-cli-linux-amd64.sha3-512 )
```

### Smoke testing the running server

Two opt-in tests verify the listener health from outside the
process:

- **`tests/scripts/test_cargo_xss.sh`** — installs `cargo-xss-
  testing` on demand and runs it against `vl-web`'s docs.rs
  rendering for XSS-class issues. Pass criterion: zero findings.
  Skips cleanly when the binary is missing (set `XSS_REQUIRE=1`
  to flip to hard-fail).
- **`crates/vl-web/tests/test_rprobe_smoke.rs`** —
  library-mode `rprobe::tls_analyzer::TlsAnalyzer::analyze`
  call against the live HTTPS listener. Asserts TLS 1.3
  negotiation per CLAUDE.md "Encryption Data-in-Transit".
  Marked `#[ignore]`; opt in with:

  ```bash
  cargo test -p vl-web --test test_rprobe_smoke -- --ignored
  ```

  Override the target via `VL_RPROBE_TARGET` (default
  `https://127.0.0.1:8080`).

### Static-asset verification (host-side, end-to-end)

Two host-side scripts under `scripts/` (repo root) deploy the
freshly built `vl-web` binary into a clean Linux target via the
`tools/ansible/roles/nvulnlookup/` Ansible role and then
screenshot every navbar-reachable page through headless Chrome
on the host. The output proves that the `include_dir!`-embedded
static assets (CSS, fonts, images, etc.) render correctly under
the SHA-3-512-verified, SystemD-managed deployment path that
operators actually use.

Both scripts share the same screenshot output directory:

```text
documentation/screenshots/gui/<route>_<suffix>_<ISO-8601-utc>.png
```

…where `<suffix>` is empty for the Vagrant-Debian-13 run and
`molecule_<os>` for each per-distro container in the Molecule
sweep.

#### `scripts/verify_static_assets_debian13.sh` — single Debian 13 VM

Boots a fresh Debian 13 (`cloud-image/debian-13`) Vagrant VM,
applies the role through the bundled `.deb` install path, waits
for `https://localhost:18443` (forwarded → guest:8080) to come
up, captures **39 screenshots** through a headless Chrome on the
host, then destroys the VM.

| Step | Detail |
| --- | --- |
| **Provisioner** | Vagrant + VirtualBox (vagrant-disksize plugin) |
| **Guest OS** | Debian 13 trixie x86_64 |
| **Install path** | bundled `.deb` package + SHA-3-512 sidecar verify (pre + post deploy) |
| **Listener** | `https://localhost:18443` → guest `:8080` (NAT) |
| **Capture tool** | Headless Chrome (host) |
| **Page coverage** | 5 top-level (`/`, `/stats`, `/dashboard`, `/recent`, `/kev`) + 24 `/dashboards/<slug>` + 1 `/cna-scorecard` + 5 Info submenu (`/about`, `/license`, `/system-info`, `/privacy`, `/security`) + 4 user/annotations (`/sightings`, `/annotations`, `/annotations?tab=kev`, `/annotations?tab=notifications`) = **39 PNGs** |
| **Wall-clock** | ~25–30 min on a warm Vagrant box cache |
| **Teardown** | VM destroyed unconditionally on script exit (cleanup trap) |

```bash
# Run from repo root
bash scripts/verify_static_assets_debian13.sh
```

The runtime workdir lands under
`scripts/.vagrant-static-verify/` (Vagrantfile, Ansible
inventory + playbook, `run.log`). Per-run artefacts only —
the directory is `.gitignore`d.

Exit codes:

| Code | Meaning |
| --- | --- |
| 0 | All 39 PNGs captured + VM destroyed |
| ≠ 0 | Either the role failed, the listener never came up, or one or more screenshot captures failed.  See the inline `[ERROR]` lines + the per-run `run.log` |

#### `scripts/verify_static_assets_molecule.sh` — six-OS Podman matrix

Same screenshot loop, but instead of a single VM the script
runs **six systemd-enabled Podman containers in series** (one
per distro), so a single sweep proves the role + binary work
identically across the supported Linux distribution set.

| Distro key | Image | Init | Host port |
| --- | --- | --- | --- |
| `debian12` | `debian:bookworm` | systemd | 18012 |
| `debian13` | `debian:trixie` | systemd | 18013 |
| `debian14` | `debian:testing` | systemd | 18014 |
| `rhel9` | `almalinux:9` | systemd | 18019 |
| `rhel10` | `almalinux:10` | systemd | 18020 |
| `alpine` | `alpine:3.21` | OpenRC | 18025 |

Each distro gets its own freshly built Podman image rendered
from one of the per-distro Dockerfile templates next to the
script (`Dockerfile-debian.j2`, `Dockerfile-rhel.j2`,
`Dockerfile-alpine.j2`). Output PNGs land with the OS suffix
embedded in the filename:

```text
<route>_molecule_<os>_<ISO-8601-utc>.png
```

For example:

```text
home_molecule_debian13_20260506T114439Z.png
about_molecule_alpine_20260506T133012Z.png
```

| Step | Detail |
| --- | --- |
| **Container runtime** | Podman + `podman-machine` on macOS host |
| **Image build** | per-distro Jinja2 Dockerfile rendered inline by the script |
| **Install path** | bundled `.deb` (Debian) / `.rpm` (RHEL) / generic Linux ELF (Alpine) |
| **Capture tool** | Same headless Chrome on the host as the Debian-13 verify |
| **Page coverage** | identical 39-page set, multiplied by 6 distros = **234 PNGs / sweep** |
| **Wall-clock** | ~3–4 hours total (Ansible role + Chrome capture per distro) |
| **Teardown** | each container removed at end of its block; cleanup trap removes any leftover container on early exit |

```bash
# Run from repo root
bash scripts/verify_static_assets_molecule.sh
```

Tip: the script logs every Ansible task heading + every
captured-screenshot path with an ISO-8601 timestamp, so a
`tail -F /tmp/verify-molecule.log | grep --line-buffered TASK`
on a parallel terminal gives a live progress feed.

##### Pre-flight checklist

Both scripts assume a host with the following toolchain:

- macOS Sequoia x86_64 (the canonical dev host) **or** Debian 13
- `vagrant` + the `vagrant-disksize` plugin installed (debian13
  script only)
- `podman` + a running `podman machine` (Molecule script only)
- A freshly built release binary at `target/release/<triple>/vl-web`
  (produce via `vulnerability-lookup-rs/scripts/build_all_targets.sh`)
- A freshly staged Ansible role under
  `tools/ansible/roles/nvulnlookup/files/` (produce via
  `vulnerability-lookup-rs/scripts/update_ansible_role.sh`)

If any of those preconditions are missing the script either
fails fast with a clear `[ERROR]` line or the role itself
errors during the SHA-3-512 sidecar verify.

##### When to run

| Trigger | Run which |
| --- | --- |
| Pre-tag release smoke test on Debian 13 only | `verify_static_assets_debian13.sh` |
| Pre-tag full-matrix verification across all supported distros | `verify_static_assets_molecule.sh` |
| Investigating a reported render glitch on a specific distro | `verify_static_assets_molecule.sh` (focused tail of the log on the distro of interest) |
| Embedded asset (CSS / font / image) sanity after a `crates/vl-web/src/static/` change | either, but Molecule first because container reuse is faster than Vagrant boot |

### Cold reset — `delete_all_data.sh`

Stops `vl-web`, explicitly removes every file under `data/`
(no wildcards, per-file existence check), restarts with
`--features quic`, verifies the reset actually took. See the
[Database Reset](#database-reset) section above for the full
semantics.

### Feed sweep — `feed_25_recent_over_all_sources.sh`

Read-only verification that every source the running server
reports via `/api/v1/vulnerabilities/sources` has enough rows
to satisfy the dashboards. Discovery is dynamic, so new feeders
are picked up automatically.

```bash
# Default: fetch 25 recent entries per source, run
# test_unknown_fields.sh after each, write matrix.tsv.
vulnerability-lookup-rs/scripts/feed_25_recent_over_all_sources.sh

# Dry-run — list sources only, no HTTP calls.
vulnerability-lookup-rs/scripts/feed_25_recent_over_all_sources.sh --dry-run
```

Env knobs: `VL_BASE_URL`, `TARGET_ENTRIES` (default 1 — small
sources like `csaf_ndaal` publish ≤ 15 advisories total),
`PER_SOURCE_LIMIT` (default 25), `HTTP_TIMEOUT` (default 15 s),
`SKIP_SOURCES`, `STRICT`.

Artefacts land in `logs/feed_25_<ISO>/`:
`summary.log`, `matrix.tsv`, `<source>.json`,
`<source>.unknown_fields.log`.

### Malware / YARA scan — `scan_dumps_dumps_archive_with_clamav_yara.sh`

Runs `freshclam` against an unprivileged cache dir
(`.cache/clamav-db/`), fetches the latest YARA-Forge **full**
bundle from <https://github.com/YARAHQ/yara-forge/releases>,
and scans both `dumps/` and `dumps_archive/` with ClamAV and
YARA.

ClamAV limits are raised well above the defaults so our
100–200 MB NDJSON dumps aren't silently skipped:
`--max-filesize=1900M`, `--max-scansize=1900M`,
`--max-recursion=32`, `--max-files=100000`.
`--alert-encrypted` flags password-protected archives.

```bash
vulnerability-lookup-rs/scripts/scan_dumps_dumps_archive_with_clamav_yara.sh
# Skip the freshclam / yara-forge download when the caches
# are already populated:
vulnerability-lookup-rs/scripts/scan_dumps_dumps_archive_with_clamav_yara.sh --skip-update
```

**Expected YARA output under `dumps/`:** many matches on
CVE-advisory descriptive text (Log4Shell JNDI string,
ransomware contact emails, tool names like `samdump.dll`, …).
These are false positives from YARA doing its job — the
advisories contain IoCs by design. For an automated gate,
add an allowlist for rule names that match known CVE text
patterns; see
[`logs/scan_dumps_*/yara-*-dumps.log`](../logs/) for the
current match set.

### DB schema docs — `generate_db_schema_docs.sh`

Regenerates
[`documentation/db_schema.md`](db_schema.md) from
`crates/vl-core/src/storage.rs` (redb — 19 tables) plus
`crates/vl-models/src/migrations/*.sql` (SQLite — 58
objects). Also appends a live `.schema` snapshot when
`data/vlookup.db` exists.

```bash
vulnerability-lookup-rs/scripts/generate_db_schema_docs.sh
# custom output path:
OUT=/tmp/schema.md vulnerability-lookup-rs/scripts/generate_db_schema_docs.sh
```

### Test runners at repo root

- [`test/bruno/run.sh`](../../test/bruno/run.sh) — Bruno API
  test suite (47 `.bru` files across 6 sub-collections,
  every HTTP endpoint covered). Invoked by
  `scripts/quality_gates.sh` gate 9a.
- [`test/testssl/run.sh`](../../test/testssl/run.sh) —
  testssl.sh 5-format report (`report.json`, `.pretty.json`,
  `.csv`, `.html`, `.log`). Gate 9b. Fails on any
  MEDIUM-or-above finding.

## Bash Script Inventory

<!-- markdownlint-disable MD013 MD033 MD044 -->

Per-script reference for every first-party committed bash script in
the repository, grouped by directory. Each entry shows the relative
path, a one-line purpose (the script's `# @brief`), the standard
invocation, and — when the header carries a shdoc `# @description`
block — the verbatim multi-line description extracted from the source.

This chapter is generated by
`scripts/generate_admin_guide_script_inventory.py` from the on-disk
script headers, so it stays in sync with the tree. Vendored trees
(`tools/ansible/collections/`, `skills/` bundles, `yara_rules/`) are
excluded. `markdownlint` MD013 / MD033 / MD044 are suppressed for the
chapter scope.

### Repo-root scripts

#### `checkin_git.sh`

- **Purpose:** Codebase-wide ShellCheck dispensations (CLAUDE.md "Quality check" policy):
- **Usage:** `bash checkin_git.sh [arguments...]`

#### `convert_markdown_to_docx_with_marxdown.sh`

- **Purpose:** Convert Markdown files to Word DOCX format using marxdown.
- **Usage:** `bash convert_markdown_to_docx_with_marxdown.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Scans the given directories (default: documentation/ and tools/ansible/)
  for Markdown (.md) files and converts each to Word .docx format via
  marxdown. The original Markdown source is always preserved. Idempotent:
  re-running overwrites previously generated .docx files deterministically.
  Output files are placed next to the source or inside the -t/--target dir.

  marxdown is a Rust crate whose `marxdown` binary is gated behind the
  non-default `clap` feature; a plain `cargo install marxdown` installs
  only `write_default_style`. Install with:
      cargo install marxdown --features clap
```

</details>

#### `convert_markdown_to_docx_with_pandoc.sh`

- **Purpose:** Convert Markdown files to Word DOCX format using pandoc.
- **Usage:** `bash convert_markdown_to_docx_with_pandoc.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Scans the given directories (default: documentation/ and tools/ansible/)
  for Markdown (.md) files and converts each to Word .docx format via
  pandoc. The original Markdown source is always preserved. Idempotent:
  re-running overwrites previously generated .docx files deterministically.
  Output files are placed next to the source or inside the -t/--target dir.
```

</details>

#### `convert_markdown_to_odt_with_pandoc.sh`

- **Purpose:** Convert Markdown files to LibreOffice ODT format using pandoc.
- **Usage:** `bash convert_markdown_to_odt_with_pandoc.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Scans the given directories (default: documentation/ and tools/ansible/)
  for Markdown (.md) files and converts each to LibreOffice .odt format via
  pandoc. The original Markdown source is always preserved. Idempotent:
  re-running overwrites previously generated .odt files deterministically.
  Output files are placed next to the source or inside the -t/--target dir.
```

</details>

#### `markdown2pdf.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash markdown2pdf.sh [arguments...]`

#### `setup_vagrant_four_vms_with_auditd.sh`

- **Purpose:** Author: Pierre Gronau (Enhanced by Gemini)
- **Usage:** `bash setup_vagrant_four_vms_with_auditd.sh [arguments...]`

#### `setup_vagrant_four_vms_with_auditd_for_nvulnlookup.sh`

- **Purpose:** Author: Pierre Gronau (Enhanced by Gemini)
- **Usage:** `bash setup_vagrant_four_vms_with_auditd_for_nvulnlookup.sh [arguments...]`

#### `setup_vagrant_systemd_gate_vms.sh`

- **Purpose:** Run the systemd unit gate end-to-end inside two Debian 13 VMs — one
- **Usage:** `bash setup_vagrant_systemd_gate_vms.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Companion to setup_vagrant_four_vms_with_auditd.sh, reusing its VM
  conventions (cloud-image boxes, 192.168.56.x private network, fixed SSH
  port map, generated Vagrantfile) for a different purpose: proving that
  skills/systemd/scripts/test_systemd_units.sh behaves identically on both
  container engines, on a real Linux kernel.

  WHY VMs AT ALL, when the gate already runs containers on the host?

  Two things cannot be tested from macOS:

    1. The DOCKER code path.  `brew install docker` installs the client
       only; there is no Docker daemon on macOS without Docker Desktop or
```

</details>

### `scripts/` — repo-level orchestrators

#### `scripts/analyze_skills_agents_with_oxidized_agentic_audit.sh`

- **Purpose:** Audit every repo AI skill + agent collection with oxidized-agentic-audit.
- **Usage:** `bash scripts/analyze_skills_agents_with_oxidized_agentic_audit.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `oxidized-agentic-audit scan-all` over every skill (`SKILL.md`) and
  agent (`AGENT.md`) collection in the repository, EXCLUDING the `.claude/`
  and `documentation/` trees, and writes the results in EVERY available
  output format (pretty / json / sarif) under
  `documentation/ai/oxidized_agentic_audit/`.  `scan-all` recurses, so each
  top-level collection root covers every nested skill/agent beneath it.
  Report-only by default (exit 0); `--strict` makes the auditor fail on
  warnings.
```

</details>

#### `scripts/bump_version.sh`

- **Purpose:** Bump the nvulnlookup workspace version at every declaration site.
- **Usage:** `bash scripts/bump_version.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  Rewrites the nvulnlookup version wherever it is DECLARED and propagates it
  across the repository, then stops -- nothing is committed and no binary is
  rebuilt. Declaration sites: the `vulnerability-lookup-rs/Cargo.toml`
  `[workspace.package]` version plus the internal `[workspace.dependencies]`
  crate pins, `Cargo.lock`, the Bruno `app_version`, the Ansible role
  defaults / playbook / install tasks, the macOS installer `SCRIPT_VERSION`s,
  and a fresh `## vX.Y.Z` section prepended to both `CHANGELOG.md` files.
  Only version *declarations* are rewritten (anchored, regex-quoted), so
  historical prose is never touched. Compiled release binaries under
```

</details>

#### `scripts/check_advisory_test_refs.sh`

- **Purpose:** Enforce the "every security advisory references its pinning test"
- **Usage:** `bash scripts/check_advisory_test_refs.sh [arguments...]`

#### `scripts/check_coverage_floors.sh`

- **Purpose:** Enforce PER-PATH line-coverage floors over a cargo-llvm-cov LCOV
- **Usage:** `bash scripts/check_coverage_floors.sh [arguments...]`

#### `scripts/check_exit_code_convention.sh`

- **Purpose:** Report *.sh sites whose bare `exit N` contradicts the ndaal
- **Usage:** `bash scripts/check_exit_code_convention.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
       find walk of this repo descends into multi-GB `target/` and
       `data/` trees and times out, and a gate that times out reports a
       false pass).  Classification runs in a single awk pass that keeps
       a 6-line ring buffer of preceding source lines.
```

</details>

#### `scripts/check_mutation_budget.sh`

- **Purpose:** Enforce a per-target cargo-mutants score BUDGET so mutation testing
- **Usage:** `bash scripts/check_mutation_budget.sh [arguments...]`

#### `scripts/compliance_audit.sh`

- **Purpose:** Audit the repo against CLAUDE.md + skills/rust.md.
- **Usage:** `bash scripts/compliance_audit.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

compliance_audit.sh -- audit the repo against CLAUDE.md + skills/rust.md

Runs every mechanical check the two policy docs require (FQCN Ansible,
bash strict-mode header, Typography/no-CDN fonts, Bruno folder layout,
fuzz target count, CSAF sidecar parity, release sidecar parity, supply-
chain/, quality_gates.sh wiring, loadtest runner, translated READMEs,
```

</details>

#### `scripts/create_sbom_with_cargo_sbom.sh`

- **Purpose:** Generate a cargo-sbom SBOM in every supported format + a jaq-derived
- **Usage:** `bash scripts/create_sbom_with_cargo_sbom.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite.  Runs `cargo sbom` over the
  detected Cargo workspace manifest, emits one SBOM per --output-format value
  the installed cargo-sbom supports (enumerated from --help), plus a
  jaq-derived, schema-validated SARIF 2.1.0 (cargo-sbom has no native SARIF
  reporter) under <target>/sbom/cargo_sbom, normalises the volatile SBOM
  fields (serialNumber / timestamps / documentNamespace / creationInfo.created)
  so two runs are byte-identical, and proves that determinism with a
  BEFORE/AFTER package-list diff in the autofix slot (SBOM generation has no
  --fix).  Report-only by default; CARGO_SBOM_STRICT=1 fails on a
  missing/empty format or invalid SARIF.  Self-skips (exit 0) when
  `cargo-sbom` is not on PATH or no Cargo manifest is found.  See the sibling
  `create_sbom_with_cargo_sbom.bats` for the full contract.
```

</details>

#### `scripts/create_sbom_with_cdxgen.sh`

- **Purpose:** Generate an SPDX 3.x cdxgen SBOM + a jaq-derived SARIF 2.1.0 package
- **Usage:** `bash scripts/create_sbom_with_cdxgen.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite.  Runs OWASP `cdxgen` over the
  whole repo EXCEPT .git/, skills/, documentation/, nuclei-templates/,
  .claude/, .vagrant/, and CLAUDE.md, emits a single SPDX 3.x JSON SBOM
  (sbom-spdx-3.json) via a two-step process: generate CycloneDX JSON with
  cdxgen, then convert to SPDX 3.0.1 using cdx-convert, plus a jaq-derived,
  schema-validated SARIF 2.1.0 (cdxgen has no native SARIF reporter) under
  <target>/sbom/cdxgen, normalises the volatile SBOM fields (the per-run
  document UUID + the CreationInfo `created` timestamp) so two runs are
  byte-identical, and proves that determinism with a BEFORE/AFTER
  package-list diff in the autofix slot (SBOM generation has no --fix).
  Report-only for FINDINGS; CDXGEN_STRICT=1 additionally fails on an invalid
  SARIF or a non-empty idempotency diff.  Three distinct outcomes: cdxgen not
```

</details>

#### `scripts/create_sbom_with_syft.sh`

- **Purpose:** Generate a 14-format Syft SBOM + a jaq-derived SARIF 2.1.0 package
- **Usage:** `bash scripts/create_sbom_with_syft.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite.  Runs `syft dir:<scan_root>`
  over the whole repo EXCEPT .git/, skills/, documentation/,
  nuclei-templates/, .claude/, .vagrant/, and CLAUDE.md, emits all 14
  mandatory SBOM formats plus a jaq-derived, schema-validated SARIF 2.1.0
  (syft has no native SARIF reporter) under <target>/sbom/syft, normalises
  the volatile SBOM fields (serialNumber / timestamps / documentNamespace /
  descriptor version) so two runs are byte-identical, and proves that
  determinism with a BEFORE/AFTER package-list diff in the autofix slot (SBOM
  generation has no --fix).  Report-only by default; SYFT_STRICT=1 fails on a
  missing/empty format or invalid SARIF.  Self-skips (exit 0) when `syft` is
  not on PATH.  See the sibling `create_sbom_with_syft.bats` for the full
  contract.
```

</details>

#### `scripts/create_screenshots_from_local_running_app.sh`

- **Purpose:** Capture light + dark theme PNG screenshots of every navbar page on the local vl-web.
- **Usage:** `bash scripts/create_screenshots_from_local_running_app.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Headless-Chrome screenshot harness for the LOCAL running vl-web. Probes
  the server health endpoint, derives the page list (top-level routes,
  VENDOR_SPECS-driven dashboards parsed from vendor_dashboard.rs, Attacks /
  Info / Annotations menus, plus a reference vulnerability page), then
  captures two full sets — light (default) and dark (forced via a one-off
  Manifest-V3 extension that seeds localStorage['vl-theme']='dark'). Writes
  timestamp-free PNGs to vulnerability-lookup-rs/documentation/graphics/
  {light,dark}/ for stable in-place referencing from the docs.
  Tunable via env: BASE_URL, CHROME_BIN, OUTPUT_ROOT, WINDOW_WIDTH,
  WINDOW_HEIGHT, CHROME_TIMEOUT_MS, PER_SCREENSHOT_TIMEOUT_SEC, VERBOSE.
  Requires curl, a Chrome/Chromium binary, and a running vl-web.
```

</details>

#### `scripts/deploy_release_to_remote.sh`

- **Purpose:** SSH-deploy one freshly-built vl-web binary to a remote nvulnlookup.
- **Usage:** `bash scripts/deploy_release_to_remote.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

deploy_release_to_remote.sh — push one freshly-built vl-web binary to a
remote nvulnlookup host over SSH, swap it in safely, and verify.

Flow (mirrors the nvulnlookup Ansible role's deploy contract):
  1. SSH to the destination FQDN / IP (key-based, BatchMode).
  2. Stop the systemd service (default: nvulnlookupd).
```

</details>

#### `scripts/enrich_publisher_metadata.sh`

- **Purpose:** CSAF 2.1 Draft 2+ branding enricher for ndaal advisories.
- **Usage:** `bash scripts/enrich_publisher_metadata.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.
```

</details>

#### `scripts/generate_dashboard_collections.sh`

- **Purpose:** Phase 5 of the dashboard fan-out.
- **Usage:** `bash scripts/generate_dashboard_collections.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

generate_dashboard_collections.sh — Phase 5 of the dashboard fan-out.

Generates a 9-file Bruno collection per VENDOR_SPECS slug from the
canonical `ndaal/` template.  Idempotent: re-runs on a clean tree
produce zero byte-changes.

```

</details>

#### `scripts/generate_dev_tls_cert.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash scripts/generate_dev_tls_cert.sh [arguments...]`

#### `scripts/gitlab_cleanup_artifacts.sh`

- **Purpose:** Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
- **Usage:** `bash scripts/gitlab_cleanup_artifacts.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).

gitlab_cleanup_artifacts.sh — survey and (optionally) delete CI/CD job
artifacts on a GitLab project to reclaim storage quota.  Job artifacts are
usually the largest, safest-to-purge consumer of a project's storage.
```

</details>

#### `scripts/install_binsec.sh`

- **Purpose:** Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
- **Usage:** `bash scripts/install_binsec.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `scripts/quality_gates.sh`

- **Purpose:** Canonical quality-gate runner for nvulnlookup.
- **Usage:** `bash scripts/quality_gates.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  Every CI-blocking check lives here so a human never has to remember
  the full list. Documented in the root `CLAUDE.md` "Overall quality
  loop" chapter. Each gate below has its own `gate_<name>` function.

  ## Flags

  | Flag | Effect |
  | --- | --- |
  | (none) | Run every gate once; fuzz at `QG_FUZZ_SECONDS` (default 60s). |
```

</details>

#### `scripts/regenerate_endpoint_lists.sh`

- **Purpose:** Phase 6 + Phase 8 of the dashboard fan-out.
- **Usage:** `bash scripts/regenerate_endpoint_lists.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

regenerate_endpoint_lists.sh — Phase 6 + Phase 8 of the dashboard fan-out.

Reads VENDOR_SPECS slugs from
`vulnerability-lookup-rs/crates/vl-web/src/routes/vendor_dashboard.rs`
and updates three endpoint-list arrays in place:

```

</details>

#### `scripts/release_pipeline.sh`

- **Purpose:** Six-step release cycle orchestrator: build → release → ansible.
- **Usage:** `bash scripts/release_pipeline.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

  ## Options

  shdoc renders `@option` / `@exitcode` only for FUNCTIONS, not for the
  file-level `@description`, so these live in the description body — tags
  placed here would be silently dropped and the README would document
  nothing while the source looked complete.
```

</details>

#### `scripts/render_mermaid.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash scripts/render_mermaid.sh [arguments...]`

#### `scripts/render_plantuml.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash scripts/render_plantuml.sh [arguments...]`

#### `scripts/render_quality_gates.uml_svg_png.sh`

- **Purpose:** Render `scripts/quality_gates.uml` to SVG + PNG via PlantUML, validating.
- **Usage:** `bash scripts/render_quality_gates.uml_svg_png.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.
```

</details>

#### `scripts/repair_csaf_validation_errors.sh`

- **Purpose:** Eight reparation patterns are applied unconditionally to every.
- **Usage:** `bash scripts/repair_csaf_validation_errors.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

repair_csaf_validation_errors.sh — repair pre-existing CSAF 2.1
schema violations across all 2026 advisories surfaced by
`csaf-validator --test basic --csaf-version 2.1` and confirmed
against the OASIS-hosted csaf.json (Draft 2020-12).

Eight reparation patterns are applied unconditionally to every
```

</details>

#### `scripts/revert_publisher_x_extensions.sh`

- **Purpose:** Reverts the x_publisher_brand + x_dashboard_short_name extensions.
- **Usage:** `bash scripts/revert_publisher_x_extensions.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.
```

</details>

#### `scripts/update_ansible_cfg_project_specific.sh`

- **Purpose:** Generate + validate the project-specific `ansible.cfg` written into the.
- **Usage:** `bash scripts/update_ansible_cfg_project_specific.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `scripts/update_audits_toml.sh`

- **Purpose:** Refresh `vulnerability-lookup-rs/supply-chain/imports.lock` with the latest.
- **Usage:** `bash scripts/update_audits_toml.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.
```

</details>

#### `scripts/update_sbom_files.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash scripts/update_sbom_files.sh [arguments...]`

#### `scripts/validate_csaf_documents.sh`

- **Purpose:** Per advisory:.
- **Usage:** `bash scripts/validate_csaf_documents.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

validate_csaf_documents.sh — recursively validate every CSAF advisory
under <root> AND verify its five sidecar checksums (.sha-256,
.sha-512, .sha3-512, .blake3-512, .shake256-512).

Per advisory:
  1. csaf-validator --test basic --csaf-version 2.1 <file>
```

</details>

#### `scripts/verify_role_tests_debian13_selected.sh`

- **Purpose:** Boot a Debian 13 VM via Vagrant, deploy nvulnlookup with hardening off,.
- **Usage:** `bash scripts/verify_role_tests_debian13_selected.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

Test sequence:
  1.  Boot a fresh Debian 13 VM via Vagrant.
  2.  Run the nvulnlookup Ansible role with hardening OFF (binary
      install, no monitoring agents).
  3.  Run `tools/ansible/roles/nvulnlookup/tests/test.yml` with all
      per-test toggles set to false EXCEPT the four enabled by this
```

</details>

#### `scripts/verify_static_assets_debian13.sh`

- **Purpose:** Test sequence: Boot Debian 13 VM → run nvulnlookup Ansible role.
- **Usage:** `bash scripts/verify_static_assets_debian13.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

Test sequence: Boot Debian 13 VM → run nvulnlookup Ansible role
(binary install) → screenshot every navbar-reachable page via
headless Chrome → save under documentation/screenshots/gui/ →
destroy the VM.  Screenshot count grows automatically as new
VENDOR_SPECS rows land — the dashboard slug list is extracted at
runtime from `crates/vl-web/src/routes/vendor_dashboard.rs`.
```

</details>

#### `scripts/verify_static_assets_molecule.sh`

- **Purpose:** Multi-distro Molecule-style verify of vl-web's.
- **Usage:** `bash scripts/verify_static_assets_molecule.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD033 MD044 -->
  <!-- rumdl-disable MD033 MD044 -->

  See the inline comments and the sibling `.bats` for the full
  contract. Generated reference; keep in sync with the script.

Multi-distro Molecule-style verify of vl-web's
`include_dir!`-embedded static assets.  Runs the nvulnlookup
Ansible role against a fresh systemd-enabled container per
distro, waits for HTTPS, captures every navbar-reachable page
via headless Chrome on the host, names each PNG with the OS
suffix:
```

</details>

### `tools/` — git configuration helpers

#### `tools/git_config.sh`

- **Purpose:** Configure global (and repo-local) Git settings for large-repo performance, transfer reliability, and TLS-verified HTTP(S) transport.
- **Usage:** `bash tools/git_config.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  git_config.sh clears any stale ~/.gitconfig.lock, then applies a fixed
  set of `git config --global` values covering core/pack memory limits,
  object durability (core.fsync / core.fsyncMethod — replacing the
  deprecated core.fsyncObjectFiles, which is unset if present), HTTP(S)
  transport (TLS 1.2 floor, certificate verification, HTTP/2), transfer
  fsck, merge/branch/rebase behaviour, commit/diff verbosity, grep
  pattern type, and Git LFS lock verification. When run inside a Git
  work tree it additionally enables `core.sparseCheckout` with
  `--local` scope for that repository only.

  This sibling README (git_config.README.md) is generated from this
  block with shdoc: shdoc < git_config.sh > git_config.README.md
```

</details>

#### `tools/git_credential.sh`

- **Purpose:** Set the global Git identity (user.name / user.email) for this host.
- **Usage:** `bash tools/git_credential.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  git_credential.sh applies `git config --global user.name` and
  `git config --global user.email`, both set to the ndaal service
  identity. Intended as a one-shot identity bootstrap step for new
  development hosts, typically run alongside git_config.sh.

  This sibling README (git_credential.README.md) is generated from this
  block with shdoc: shdoc < git_credential.sh > git_credential.README.md
```

</details>

#### `tools/update_canonical_config_files.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash tools/update_canonical_config_files.sh [arguments...]`

#### `tools/update_csaf_documents.sh`

- **Purpose:** Sync the repository's csaf/ tree into the ndaal CSAF sibling repos.
- **Usage:** `bash tools/update_csaf_documents.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Copies every NEW or NEWER file from <repo>/csaf/ into each destination
  csaf/ directory with `rsync --archive --update`.  Nothing is ever removed
  at a destination -- there is no --delete, so the sync is purely additive.

  PREVIEW BY DEFAULT.  The script performs a dry run and writes nothing
  unless --apply is given.  This mirrors the repo's other mutating helper,
  create_for_bash_sibling_readme.md.sh, whose read-only --check is the
  default and whose --write mutates the tree.

  Default destinations (absolute; override with one or more -d/--dest
  flags):
    /Users/cloud/repos/ndaal_public_csaf_information/csaf
```

</details>

#### `tools/update_skills_claude.md.sh`

- **Purpose:** Enforce-sync CLAUDE.md, CLAUDE.local.md, and skills/ into sibling repos.
- **Usage:** `bash tools/update_skills_claude.md.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Mirrors this repository's CLAUDE.md, CLAUDE.local.md (when present), and
  skills/ tree into every destination repository, OVERRIDING whatever is
  already there.  Unlike the repo's other sync helper
  (update_csaf_documents.sh, which is purely additive), this script
  ENFORCES the source as the single source of truth on every run:

    - CLAUDE.md         — unconditionally overwritten at every destination.
    - CLAUDE.local.md   — overwritten ONLY when the source carries one;
                           a destination's own CLAUDE.local.md is left
                           untouched when the source has none (there is
                           nothing to enforce).
    - skills/            — mirrored with `rsync --archive --delete`: any
```

</details>

#### `tools/update_test_scripts_with_skills.sh`

- **Purpose:** Refresh each skill's vendored test_* gate script from its canonical
- **Usage:** `bash tools/update_test_scripts_with_skills.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  The workspace's gate scripts under
  `vulnerability-lookup-rs/tests/scripts/test_*.{sh,bats,README.md,py}` are the
  CANONICAL copies.  Several skills vendor a subset of them under
  `skills/<skill>/scripts/` so the skill is self-contained and portable (for
  example skills/rust-testing/scripts/, skills/rust-compliance/scripts/).
  Those vendored copies drift the moment a gate script is edited in the app
  tree but not re-copied into the skill.

  This tool walks every `skills/*/scripts/` directory and, for each vendored
  `test_*` file that has a same-named source under tests/scripts/, refreshes
  it so the skill copy byte-matches the canonical source.  It is modelled on
  tools/update_csaf_documents.sh (same options, same preview-by-default
```

</details>

### `nuclei_fire/` — Nuclei scanner wrapper

#### `nuclei_fire/nuclei_scanner.sh`

- **Purpose:** Pedantic-style enforcement (info-level) where the construct is
- **Usage:** `bash nuclei_fire/nuclei_scanner.sh [arguments...]`

#### `nuclei_fire/test_nuclei_scanner.sh`

- **Purpose:** ═══════════════════════════════════════════════════════════════════════════════ UTILITY FUNCTIONS…
- **Usage:** `bash nuclei_fire/test_nuclei_scanner.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  See the inline comments below and the sibling `test_nuclei_scanner.bats` for the
  full contract this gate enforces.
```

</details>

### `test/` — protocol-level integration suites

#### `test/bruno/run.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash test/bruno/run.sh [arguments...]`

#### `test/loadtest/run.sh`

- **Purpose:** Pedantic-style enforcement (info-level) where the construct is
- **Usage:** `bash test/loadtest/run.sh [arguments...]`

#### `test/sqllogictest/run.sh`

- **Purpose:** SC2016: deliberate single-quoted backticks in error/help strings.
- **Usage:** `bash test/sqllogictest/run.sh [arguments...]`

#### `test/sqlmap/run.sh`

- **Purpose:** SC2016: deliberate single-quoted backticks in error/help strings.
- **Usage:** `bash test/sqlmap/run.sh [arguments...]`

#### `test/testssl/quic_check.sh`

- **Purpose:** Pedantic-style enforcement (info-level) where the construct is
- **Usage:** `bash test/testssl/quic_check.sh [arguments...]`

#### `test/testssl/quiche_probe.sh`

- **Purpose:** Pedantic-style enforcement (info-level) where the construct is
- **Usage:** `bash test/testssl/quiche_probe.sh [arguments...]`

#### `test/testssl/run.sh`

- **Purpose:** Pedantic-style enforcement (info-level) where the construct is
- **Usage:** `bash test/testssl/run.sh [arguments...]`

### `vulnerability-lookup-rs/release/` — release pipeline

#### `vulnerability-lookup-rs/release/anodizer_release_pipeline.sh`

- **Purpose:** anodizer-driven multi-format release pipeline (parity with release_pipeline.sh).
- **Usage:** `bash vulnerability-lookup-rs/release/anodizer_release_pipeline.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Drives the anodizer release tool over ../.anodizer.yaml to produce the full
  multi-format release: archives (tar.gz/tar.xz/tar.zst/zip/gz/binary with
  OS overrides), nFPM Linux packages (.deb/.rpm/.apk/.archlinux/.ipk with
  lifecycle scripts), Snapcraft snaps, macOS DMG/PKG, Windows MSI/NSIS,
  Flatpak, AppImage, Makeself, source + source-RPM, CycloneDX/SPDX SBOMs, and
  signing. Mirrors release_pipeline.sh's posture: a quality_gates.sh --fast
  PREFLIGHT must pass, then SNAPSHOT (no publish) is the default; a real
  publish runs only under RELEASE_EXECUTE=1. Stages whose packaging tool is
  absent are skipped by anodizer (use --strict / ANODIZER_STRICT=1 to make
  that fatal). Self-skips cleanly (exit 0) when `anodizer` is not installed.
  Builds run SERIALLY (--parallelism 1) because the host is CPU-constrained;
  override with ANODIZER_PARALLELISM. After a release, step 4 emits the five
```

</details>

#### `vulnerability-lookup-rs/release/bump_version.sh`

- **Purpose:** Bump the nvulnlookup workspace version across every pin in one shot.
- **Usage:** `bash vulnerability-lookup-rs/release/bump_version.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Sets `<X.Y.Z>` in every place the version is pinned so a release never
  ships a mismatched version:

    * `Cargo.toml` `[workspace.package] version`
    * `Cargo.lock` -- the `version` of every workspace crate (discovered
      from `crates/*`, matched by package NAME so a third-party dependency
      at the same version is never touched)
    * `tools/ansible/roles/{nvulnlookup,nvulnlookuptesting}/defaults/main.yml`
      `nvulnlookup_version`
```

</details>

#### `vulnerability-lookup-rs/release/create_cpu_optimized_binaries_with_cargo_sonar.sh`

- **Purpose:** Build per-CPU-microarchitecture-tuned vl-cli/vl-web binaries and emit a SonarQube issues report.
- **Usage:** `bash vulnerability-lookup-rs/release/create_cpu_optimized_binaries_with_cargo_sonar.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Operator-driven, environment-knob-only build (no positional arguments).
  Produces one optimised `vl-cli` + `vl-web` binary per CPU profile via
  `RUSTFLAGS="-C target-cpu=<profile>"` — `native` plus, on x86_64 hosts,
  `x86-64-v3` / `x86-64-v4` / `znver3`, and on aarch64 (or x86_64 macOS)
  hosts the Apple Silicon `apple-m1` … `apple-m5` profiles.  Each profile
  lands in `release/cpu_optimized/v<ver>/<profile>/` with the canonical
  five-hash sidecar set (sha-256/512, sha3-512, blake3-512, shake256-512),
  per-profile aggregate manifests, and a SUMMARY.md verdict table.  Unless
  skipped, a single `cargo sonar --clippy` pass converts `cargo clippy
  --message-format=json` into a SonarQube-importable `sonar-issues.json`.
```

</details>

#### `vulnerability-lookup-rs/release/create_release.sh`

- **Purpose:** Assemble the cross-target nvulnlookup release artefacts with five hash-family sidecars.
- **Usage:** `bash vulnerability-lookup-rs/release/create_release.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Resolves the release version from the first positional argument or, if
  omitted, from `workspace.package.version` in ../Cargo.toml.  For each
  target triple (x86_64/aarch64 Linux-gnu + aarch64/x86_64 Apple-darwin)
  it stages the cross-built `vl-web` / `vl-cli` binaries into
  release/v${VERSION}/<triple>/, packs per-triple `.tar.gz` archives,
  builds optional Linux `.deb` / `.rpm` packages, generates SPDX 2.3 +
  CycloneDX 1.6 SBOMs, and runs an advisory cargo-auditable `.dep-v0`
  check.  Every artefact gets five per-file checksum sidecars
  (`.sha-256`, `.sha-512`, `.sha3-512`, `.blake3-512`, `.shake256-512`)
  plus five aggregate manifests (`SHA-256SUMS.txt`, `SHA-512SUMS.txt`,
  `SHA3-512SUMS.txt`, `BLAKE3-512SUMS.txt`, `SHAKE256-512SUMS.txt`).  By
  default it prunes prior-version artefacts from the release/target dirs;
```

</details>

#### `vulnerability-lookup-rs/release/create_release_on_crates.io.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash vulnerability-lookup-rs/release/create_release_on_crates.io.sh [arguments...]`

#### `vulnerability-lookup-rs/release/create_release_on_gitlab.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash vulnerability-lookup-rs/release/create_release_on_gitlab.sh [arguments...]`

#### `vulnerability-lookup-rs/release/makeself/startup.sh`

- **Purpose:** Makeself startup script — executed after the self-extracting archive unpacks
- **Usage:** `bash vulnerability-lookup-rs/release/makeself/startup.sh [arguments...]`

#### `vulnerability-lookup-rs/release/nfpm/postinstall.sh`

- **Purpose:** (bash script; see the script header)
- **Usage:** `bash vulnerability-lookup-rs/release/nfpm/postinstall.sh [arguments...]`

#### `vulnerability-lookup-rs/release/nfpm/postremove.sh`

- **Purpose:** Data under /var/lib/nvulnlookup is intentionally preserved on remove.
- **Usage:** `bash vulnerability-lookup-rs/release/nfpm/postremove.sh [arguments...]`

#### `vulnerability-lookup-rs/release/nfpm/preinstall.sh`

- **Purpose:** Create the dedicated service account + data dir if absent (idempotent).
- **Usage:** `bash vulnerability-lookup-rs/release/nfpm/preinstall.sh [arguments...]`

#### `vulnerability-lookup-rs/release/nfpm/preremove.sh`

- **Purpose:** (bash script; see the script header)
- **Usage:** `bash vulnerability-lookup-rs/release/nfpm/preremove.sh [arguments...]`

#### `vulnerability-lookup-rs/release/release_on_ndaal_public_nvulnlookup_release.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash vulnerability-lookup-rs/release/release_on_ndaal_public_nvulnlookup_release.sh [arguments...]`

#### `vulnerability-lookup-rs/release/update_rust_nightly.sh`

- **Purpose:** Update the Rust nightly toolchain via `rustup update nightly`.
- **Usage:** `bash vulnerability-lookup-rs/release/update_rust_nightly.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Refreshes the `nightly` Rust toolchain to the latest release with
  `rustup update nightly`, printing the rustc version before and after so
  the release log records exactly which nightly compiler is in play. nightly
  is required by the workspace's `cargo-fuzz` (libFuzzer) targets,
  `cargo-kani` model checking, and `miri`. Runs right AFTER
  update_rust_stable.sh in the release pipeline (before the quality-gate
  preflight) so those nightly-only gates use the current nightly compiler.
  Self-skips cleanly (exit 0) when `rustup` is not installed.
```

</details>

#### `vulnerability-lookup-rs/release/update_rust_stable.sh`

- **Purpose:** Update the Rust stable toolchain via `rustup update stable`.
- **Usage:** `bash vulnerability-lookup-rs/release/update_rust_stable.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Refreshes the `stable` Rust toolchain to the latest release with
  `rustup update stable`, printing the rustc version before and after so
  the release log records exactly which compiler built the artefacts. Run
  FIRST in the release pipeline (before update_rust_nightly.sh and the
  quality-gate preflight) so every downstream build / lint / test uses the
  current stable compiler. Self-skips cleanly (exit 0) when `rustup` is not
  installed.
```

</details>

### `vulnerability-lookup-rs/scripts/` — workspace operations

#### `vulnerability-lookup-rs/scripts/backfill_5sidecar_contract.sh`

- **Purpose:** Backfill the two missing CLAUDE.md checksum sidecar families
- **Usage:** `bash vulnerability-lookup-rs/scripts/backfill_5sidecar_contract.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  For every release artefact that already carries a `.sha-256`
  sidecar (and every `SHA-256SUMS.txt` manifest) under each target
  directory, add the missing `.blake3-512` and `.shake256-512`
  siblings, then verify each new sidecar by recompute-and-compare.
  Idempotent: a tree already on the 5-sidecar contract is a no-op.
  Exits non-zero if any verification check fails.
```

</details>

#### `vulnerability-lookup-rs/scripts/build_all_targets.sh`

- **Purpose:** Cross-compile the vl-web / vl-cli release binaries for every
- **Usage:** `bash vulnerability-lookup-rs/scripts/build_all_targets.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Installs any missing rustup targets, then builds the workspace in
  release mode for each triple — preferring `cargo auditable` for the
  embedded SBOM and `cargo-zigbuild` (falling back to `cross`) for
  Linux targets on a non-Linux host. Copies the built binaries into
  `target/release/<triple>/` and prints a per-target build summary.
```

</details>

#### `vulnerability-lookup-rs/scripts/build_secure.sh`

- **Purpose:** Security-hardened release build with toolchain verification,
- **Usage:** `bash vulnerability-lookup-rs/scripts/build_secure.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Verifies the Rust toolchain integrity, runs `cargo audit` and
  `cargo deny`, builds the vl-web / vl-cli binaries with hardened
  RUSTFLAGS (PIE, full RELRO, immediate binding) either natively or
  for all cross-compile targets, then generates a CycloneDX SBOM,
  SHA-256 checksums, and minisign/signify signatures into `dist/`.
  Optional tools warn-and-skip so a partial toolchain still builds.
```

</details>

#### `vulnerability-lookup-rs/scripts/capture_screenshots.sh`

- **Purpose:** Capture headless-Chrome PNG screenshots of every vl-web page and
- **Usage:** `bash vulnerability-lookup-rs/scripts/capture_screenshots.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Iterates a curated list of base pages and vendor dashboards, driving
  headless Chrome (via `gtimeout`) to write one PNG per page — plus a
  dark-mode sibling where requested — into
  `documentation/screenshots`. A known-broken dashboard skip-list and
  a per-capture timeout keep the batch from wedging. Reads the target
  base URL from `VL_BASE_URL` (default `https://localhost:8080`).
```

</details>

#### `vulnerability-lookup-rs/scripts/cargo_vet_refresh.sh`

- **Purpose:** Refresh the cargo-vet supply-chain store from trusted audits.
- **Usage:** `bash vulnerability-lookup-rs/scripts/cargo_vet_refresh.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Bulk-imports the trusted publisher audit sets, regenerates
  exemptions, and runs the final `cargo vet check` gate, writing a
  timestamped transcript under documentation/rust/audit/. Override
  the publisher list via the VET_AUDIT_SETS environment variable.
```

</details>

#### `vulnerability-lookup-rs/scripts/compress_app_data.sh`

- **Purpose:** 7z-compress the verified dumps_data/ snapshot into dumps_data_archive/.
- **Usage:** `bash vulnerability-lookup-rs/scripts/compress_app_data.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Compresses each data file under `dumps_data/` (the verified snapshot
  produced by save_app_data.sh) with 7z LZMA2 (mx=9) into
  `dumps_data_archive/`, preserving the relative tree.  Every archive is
  then list-verified, integrity-tested, and signed with three
  self-verified hash-family sidecars (`.sha-256` / `.sha-512` /
  `.sha3-512`).  Existing sidecar files inside `dumps_data/` are skipped.
```

</details>

#### `vulnerability-lookup-rs/scripts/compress_data.sh`

- **Purpose:** Compress the data/ directory into a verified 7z archive.
- **Usage:** `bash vulnerability-lookup-rs/scripts/compress_data.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Archives the redb + SQLite data/ tree with 7-Zip at maximum LZMA2
  compression into a timestamped file under data_archive/, then
  verifies it by listing and integrity test. Fails loudly and
  removes the partial archive on any compression or verification
  error.
```

</details>

#### `vulnerability-lookup-rs/scripts/compress_dumps.sh`

- **Purpose:** Compress each NDJSON dump individually into a verified 7z.
- **Usage:** `bash vulnerability-lookup-rs/scripts/compress_dumps.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Compresses every `*.ndjson` under dumps/ into its own `.7z` under
  dumps_archive/ with maximum LZMA2 settings, writing the three
  checksum sidecars per archive. Idempotent: unchanged archives are
  skipped and only missing or stale sidecars are refreshed.
```

</details>

#### `vulnerability-lookup-rs/scripts/compress_dumps_megavul.sh`

- **Purpose:** Recursively compress the nested MegaVul corpus into verified per-file 7z archives.
- **Usage:** `bash vulnerability-lookup-rs/scripts/compress_dumps_megavul.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Recursively compresses every file under `dumps_megavul/<YYYY-MM>/
  <language>/` into its own `.7z` under `dumps_megavul_archive/` with
  maximum LZMA2 settings, mirroring the source sub-directory layout.
  Each archive is validated (`7z l` + `7z t`) and the three checksum
  sidecars (`.sha-256`, `.sha-512`, `.sha3-512`) are written and
  self-verified beside it. Takes no arguments. Idempotent: unchanged
  archives are skipped and only missing or stale sidecars are refreshed.
```

</details>

#### `vulnerability-lookup-rs/scripts/convert_browser_dumps_to_ndjson.sh`

- **Purpose:** Reshape ndaal browser-vulnerability dumps (Chromium + Firefox) into per-source OSV-shaped NDJSON for `vl-cli import-dumps`.
- **Usage:** `bash vulnerability-lookup-rs/scripts/convert_browser_dumps_to_ndjson.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Reads the newest `chrome-vulns-osv-*.json` under the Chromium dump
  directory and ALL `firefox-vulns-*.json` (legacy + modern MFSA) under the
  Firefox dump directory, then emits one OSV-shaped vulnerability object per
  line into `chromium.ndjson` and `firefox.ndjson` in the output directory.
  Each emitted line carries `id`, `summary`/`details`, `published`/`modified`
  (ISO-8601) and `database_specific.severity` so the vendor dashboards render
  the rows. The three source/output directories are overridable via
  `--chromium-dir`, `--firefox-dir` and `--out-dir`; the run needs `jaq`,
  validates every output line, and is idempotent (safe to re-run).
```

</details>

#### `vulnerability-lookup-rs/scripts/create_for_bash_sibling_readme.md.sh`

- **Purpose:** Generate / verify the shdoc sibling reference for every Bash script.
- **Usage:** `bash vulnerability-lookup-rs/scripts/create_for_bash_sibling_readme.md.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Walks the repository recursively from its root and, for every Bash
  script (`*.sh`) that carries shdoc `@`-tags, maintains a sibling
  reference document `<script>.README.md` (naming convention:
  `my-script.sh` -> `my-script.README.md`).

  Two modes:
    * `--check` (default, read-only): assert each documented script has a
      sibling README that EXISTS and is markdownlint- + mdformat-clean.
      Exits non-zero if any documented script lacks a clean README.  This
      is the mode wired into `scripts/quality_gates.sh` (full sweep).
    * `--write`: (re)generate each README via the canonical pipeline
      `shdoc` -> `mdformat --wrap 80` -> `markdownlint --fix` ->
```

</details>

#### `vulnerability-lookup-rs/scripts/cve_api_probe.sh`

- **Purpose:** Probe the vl-web API over HTTP/2 and HTTP/3 for a CVE sample.
- **Usage:** `bash vulnerability-lookup-rs/scripts/cve_api_probe.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Samples a cvelistV5 CSV down to SAMPLE_SIZE CVE ids, then queries
  the running vl-web API for each id twice — once over HTTP/2 (TCP)
  and once over HTTP/3 (QUIC) — and writes a Markdown report on
  which CVEs are present and whether the two transports agree.
```

</details>

#### `vulnerability-lookup-rs/scripts/cvelist_to_csv.sh`

- **Purpose:** Convert the official CVE List (cvelistV5) snapshot into a flat CSV.
- **Usage:** `bash vulnerability-lookup-rs/scripts/cvelist_to_csv.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Downloads the cvelistV5 main-branch tarball (~1 GB), extracts it, then
  walks every `CVE-*.json` record in parallel with `jaq`, emitting one
  CSV row per CVE: id, published date, state, best-available CVSS score
  and severity, and the English description. The output CSV path and an
  optional year filter are positional arguments; the CSV header row is
  always written first. Work happens in a private temp directory that is
  removed on exit.
```

</details>

#### `vulnerability-lookup-rs/scripts/delete_all_data.sh`

- **Purpose:** Cold-reset the nvulnlookup runtime state (stop, wipe, restart).
- **Usage:** `bash vulnerability-lookup-rs/scripts/delete_all_data.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Stops any running vl-web binary, deletes the explicitly-listed runtime
  data files under `data/` (redb + SQLite stores, no wildcards), then —
  unless `--no-start` is given — rebuilds and restarts vl-web, waits for
  its health endpoint, and verifies the database is near-empty (a freshly
  recreated redb file plus per-source count ceilings) to prove the wipe
  took. Thresholds and paths are env-overridable.
```

</details>

#### `vulnerability-lookup-rs/scripts/download_exploitdb.sh`

- **Purpose:** Build a verified, sidecar-signed offline snapshot of the pyExploitDb dataset into dump_pyexploitdb/.
- **Usage:** `bash vulnerability-lookup-rs/scripts/download_exploitdb.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Copies the two bundled CVE-to-EDBID index maps (cveToEdbid.json,
  edbidToCve.json) from the installed pyExploitDb wheel and, unless
  PYEXPLOITDB_DOWNLOAD_CSV=0, downloads only files_exploits.csv from the
  upstream GitLab repository. Every artefact is JSON/CSV sanity-checked and
  gets a three-family hash sidecar (.sha-256, .sha-512, .sha3-512); a
  MANIFEST.txt records provenance; and the snapshot is staged in a sibling
  directory then published with an atomic rename, so the previous
  dump_pyexploitdb/ is replaced only when every file validates. The build is
  idempotent and fail-safe: an error at any step leaves the previous snapshot
```

</details>

#### `vulnerability-lookup-rs/scripts/export_nuclei_data.sh`

- **Purpose:** Dump the `nuclei_templates` SQLite table to a verified NDJSON file.
- **Usage:** `bash vulnerability-lookup-rs/scripts/export_nuclei_data.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Exports the `nuclei_templates` table from vl-web's shared SQLite store
  to NDJSON (one JSON object per line, ordered by `nuclei_uuid` for
  deterministic output) via `sqlite3 -json | jaq`, verifies the result
  (line count, per-line JSON parse, UUID uniqueness), and emits the three
  canonical hash sidecars (`.sha-256`, `.sha-512`, `.sha3-512`). The
  write is atomic (tempfile + `mv`). Flags allow overriding the DB/output
  paths and toggling verify, sidecars, dry-run, verbose, and quiet modes.
```

</details>

#### `vulnerability-lookup-rs/scripts/export_sources_ndaal_dumps.sh`

- **Purpose:** Export every vl-web vulnerability source to a verified NDJSON dump.
- **Usage:** `bash vulnerability-lookup-rs/scripts/export_sources_ndaal_dumps.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Queries the running vl-web API for its list of sources and exports each
  one to its own paginated NDJSON dump. Every dump is verified before it
  is stored — non-empty, per-line JSON with an id-like field, internal
  line-count consistency, and a first-N compare against what the DB
  serves — then wrapped in the full five-family sidecar contract
  (`.sha-256`, `.sha-512`, `.sha3-512`, `.blake3-512`, `.shake256-512`).
  Finally it emits SARIF 2.1.0 and Markdown reports. Behaviour is
  env-overridable and CLI-toggled (single-source, strict, verbose,
  quiet, log-file).
```

</details>

#### `vulnerability-lookup-rs/scripts/feed_25_recent_over_all_sources.sh`

- **Purpose:** Sweep the 25 most-recent entries for every live source and
- **Usage:** `bash vulnerability-lookup-rs/scripts/feed_25_recent_over_all_sources.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Discovers every source from the running listener, fetches the N
  most-recent entries per source, snapshots each response as JSON,
  runs test_unknown_fields.sh after each, and writes a per-run
  matrix TSV plus a summary log under logs/. Read-only against the
  API; the only side effects are the log files it writes. Honours
  --dry-run.
```

</details>

#### `vulnerability-lookup-rs/scripts/fetch_dumps.sh`

- **Purpose:** Fetch the CIRCL vulnerability-lookup NDJSON dumps for DB seeding.
- **Usage:** `bash vulnerability-lookup-rs/scripts/fetch_dumps.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Reconciles the built-in dump list against the live CIRCL index,
  downloads each dump atomically (`.tmp` + `mv`) through the
  BSI-hardened `canonical_curl`, and writes the three-algorithm
  checksum sidecars. Idempotent: unchanged dumps are skipped and
  only missing or stale sidecars are refreshed.
```

</details>

#### `vulnerability-lookup-rs/scripts/generate_db_schema_docs.sh`

- **Purpose:** Generate the Markdown database-schema reference from the
- **Usage:** `bash vulnerability-lookup-rs/scripts/generate_db_schema_docs.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Extracts the redb table definitions from storage.rs, the SQLite
  migrations from crates/vl-models, and a static Meilisearch note,
  and writes them as one Markdown document (default
  documentation/db_schema.md, overridable via $1 or OUT).
  Regenerated on every release; edit the upstream sources, not the
  output.
```

</details>

#### `vulnerability-lookup-rs/scripts/import_and_verify_dumps.sh`

- **Purpose:** Import every NDJSON dump into the database and verify
- **Usage:** `bash vulnerability-lookup-rs/scripts/import_and_verify_dumps.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Checks prerequisites, ensures dumps exist (extracting verified .7z
  archives when needed), verifies each dump's three checksum
  sidecars, counts entries with jaq, imports via vl-cli, then
  compares dump vs database counts against a tolerance. Strict
  checksum mode is the default; set IMPORT_STRICT_CHECKSUMS=0 to
  accept sidecar-less dumps.
```

</details>

#### `vulnerability-lookup-rs/scripts/import_nuclei_data.sh`

- **Purpose:** Verify and import the nuclei dump into SQLite, emitting
- **Usage:** `bash vulnerability-lookup-rs/scripts/import_nuclei_data.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Round-trip companion to export_nuclei_data.sh. Verifies the nuclei
  NDJSON dump's three sidecars (or recovers it from a verified .7z
  archive), bootstraps the nuclei_templates schema, bulk-inserts via
  sqlite3 JSON1, checks post-import consistency, and writes
  .sha-256/.sha-512/.sha3-512 sidecars for the resulting database
  file. Idempotent (INSERT OR REPLACE on template_path). See --help
  for flags. Stages run at top level, gated in order; there is no
  main().
```

</details>

#### `vulnerability-lookup-rs/scripts/import_nuclei_templates.sh`

- **Purpose:** Import the in-tree nuclei template corpus into a SQLite table.
- **Usage:** `bash vulnerability-lookup-rs/scripts/import_nuclei_templates.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Walks the nuclei template corpus (YAML/YML), converts each file to
  JSON via yq or python3+PyYAML, extracts the info.* + classification
  fields, computes a per-row trust score from nuclei_scanner.sh's
  TRUSTED_SOURCES / COMMUNITY_SOURCES arrays, and upserts one row per
  template into the shared vlookup.db `nuclei_templates` table. The
  table is created if absent and cleared on every run by default.
  Idempotent per template_path (INSERT OR REPLACE).
```

</details>

#### `vulnerability-lookup-rs/scripts/import_sources_ndaal_dumps.sh`

- **Purpose:** Import each source's newest usable NDJSON dump into the vl-web redb.
- **Usage:** `bash vulnerability-lookup-rs/scripts/import_sources_ndaal_dumps.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  For every vulnerability source, picks the newest usable dump via a
  fallback chain (newest dumps/ candidate → older → dumps_archive/<S>.7z),
  validates the full 5-sidecar cryptographic contract, verifies the dump
  (schema, amount, in-file duplicate ids) BEFORE import, manages the
  single-writer redb lock held by a running vl-web server, then confirms
  via a 25-entry DB compare. Emits SARIF 2.1.0 + Markdown reports.

File-scope shellcheck disables (CLAUDE.md `.shellcheckrc` policy
requires every suppression to be in-file with rationale):
```

</details>

#### `vulnerability-lookup-rs/scripts/install_meilisearch_on_debian.sh`

- **Purpose:** Idempotently and securely install a pinned Meilisearch binary on Debian.
- **Usage:** `bash vulnerability-lookup-rs/scripts/install_meilisearch_on_debian.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Installs the Meilisearch search engine on Debian 12 (bookworm), 13 (trixie)
  and 14 (forky), amd64 + arm64. Idempotent: if `meilisearch` is already on
  PATH the script prints its version and exits 0 unless --force is given.

  Debian has no Homebrew, and Meilisearch's third-party APT repo
  (apt.fury.io) is published with `[trusted=yes]`, which DISABLES APT's GPG
  signature verification. Per the ndaal / BSI "no unverified sources" policy
  that repo is deliberately NOT used. The only install method is the pinned
  GitHub release Linux binary, downloaded over a BSI-aligned hardened curl
```

</details>

#### `vulnerability-lookup-rs/scripts/install_meilisearch_on_macos.sh`

- **Purpose:** Idempotently and securely install a pinned Meilisearch binary, cross-platform.
- **Usage:** `bash vulnerability-lookup-rs/scripts/install_meilisearch_on_macos.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Installs the Meilisearch search engine on macOS and Linux (amd64 + arm64).
  Idempotent: if `meilisearch` is already on PATH the script prints its
  version and exits 0 unless --force is given. Install strategy, in order:
  (a) on macOS with Homebrew present, `brew install meilisearch`; (b) portable
  fallback for Linux and brew-less macOS — download the pinned release binary
  from the official GitHub releases over a BSI-aligned hardened curl (TLS 1.2
  floor, HTTPS-only proto + redirect allowlist, --fail-with-body, bounded
  redirects/retries, NEVER -k), VERIFY its SHA-256 against GitHub's authoritative
  per-asset digest before installing, chmod +x, and place it under
```

</details>

#### `vulnerability-lookup-rs/scripts/ndaal-chrome-vulns-osv.sh`

- **Purpose:** Enrich ndaal-chrome-vulns.sh JSON with OSV.dev cross-references for Chrome browser CVEs.
- **Usage:** `bash vulnerability-lookup-rs/scripts/ndaal-chrome-vulns-osv.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Reads the vulnerability JSON produced by ndaal-chrome-vulns.sh (from `-i`
  or stdin), then queries OSV.dev for chromium package records using two
  combinable strategies run concurrently up to `-j` parallel requests:
  paginating a package purl's full vuln list (`-e`) and/or direct GET of
  deterministic distro advisory IDs per CVE (`-d`). It builds a
  CVE -> OSV-record index and adds a per-vulnerability `osv` object (matched
  flag, OSV IDs, ecosystem, fixed package versions) plus a top-level
  `osv_summary`, writing the enriched JSON to `-o` or stdout. The input file
  is never mutated (a temp copy is enriched); CVE-less entries stay unmatched
```

</details>

#### `vulnerability-lookup-rs/scripts/ndaal-chrome-vulns.sh`

- **Purpose:** Normalize a Google "Chrome Releases" stable-channel post into one JSON document of security fixes.
- **Usage:** `bash vulnerability-lookup-rs/scripts/ndaal-chrome-vulns.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Fetches a Chrome Releases blog post over a BSI-hardened curl (or reads a
  local HTML file with `-f`) and reshapes every listed security fix into a
  single JSON object `{ source, fetched_at, total, without_cve, by_severity,
  vulnerabilities[] }`. Each fix is keyed by its CVE, or by its Chromium issue
  ID when Google assigned none; CVE-less entries carry `"has_cve": false` so
  they stay first-class in the output. JSON is written to stdout or to the
  file named by `-o`; the script only writes that output and its own temp
  workspace, so re-running it on the same input is idempotent apart from the
  `fetched_at` timestamp. Requires curl, perl, and jaq.
```

</details>

#### `vulnerability-lookup-rs/scripts/ndaal-firefox-vulns-legacy.sh`

- **Purpose:** Normalize a pre-2016 Mozilla Foundation Security Advisory (MFSA) into the CVE-keyed JSON shape used by ndaal-firefox-vulns.sh.
- **Usage:** `bash vulnerability-lookup-rs/scripts/ndaal-firefox-vulns-legacy.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Fetches or reads a legacy mfsaYYYY-NN.md advisory (selected via -m MFSA id,
  -u URL, or -f local file), parses its YAML frontmatter and HTML body with a
  small embedded Python (PyYAML) converter, and normalises it into a single
  JSON document. Because the old format carries no per-CVE metadata, severity,
  title and reporter are inherited from the MFSA-level frontmatter and stamped
  onto every record; CAN-YYYY-NNNN ids are rewritten to the equivalent
  CVE-YYYY-NNNN, and advisories with no CVE/CAN emit one representative record
  so nothing is lost. Output goes to stdout or to the file named by -o, and
  every emitted record is flagged legacy_html_source:true. The conversion is
```

</details>

#### `vulnerability-lookup-rs/scripts/ndaal-firefox-vulns.sh`

- **Purpose:** Normalize a Mozilla Foundation Security Advisory (MFSA) into a single JSON document.
- **Usage:** `bash vulnerability-lookup-rs/scripts/ndaal-firefox-vulns.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Fetches or reads one MFSA (from Mozilla's foundation-security-advisories
  repo via `-m YYYY-NN`, an explicit `-u URL`, or a local `-f FILE`), converts
  the advisory YAML to JSON with PyYAML, and emits a CVE-keyed summary document
  covering the whole Mozilla family the MFSA set spans (Firefox, Firefox ESR,
  Thunderbird, Firefox for Android/iOS, SeaMonkey) and the downstream
  derivatives that track them (Tor Browser / Mullvad Browser on ESR, LibreWolf,
  Waterfox).

  Each vulnerability record carries its CVE, severity, title, reporter, the
```

</details>

#### `vulnerability-lookup-rs/scripts/refresh_provider_metadata.sh`

- **Purpose:** Refresh each CSAF feeder's cached provider-metadata.json.
- **Usage:** `bash vulnerability-lookup-rs/scripts/refresh_provider_metadata.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Greps every `csaf_*.rs` feeder for its provider-metadata.json URL,
  downloads each with TLS-hardened curl (atomic `.tmp` + mv), validates
  the JSON carries a publisher.name before promoting it, and stores it
  under crates/vl-web/data/csaf/<slug>/. Idempotent: rewrites each
  provider-metadata.json in place; reports an ok/failed tally.
```

</details>

#### `vulnerability-lookup-rs/scripts/restore_app_data.sh`

- **Purpose:** Restore the app data/ directory from the verified dumps_data/ snapshot.
- **Usage:** `bash vulnerability-lookup-rs/scripts/restore_app_data.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  The inverse of save_app_data.sh.  Gracefully stops vl-web, then restores
  `data/` from the snapshot: PRIMARY path verifies each file's
  `.sha-256` / `.sha-512` / `.sha3-512` sidecars and copies it into a
  STAGING tree byte-for-byte; the FALLBACK path rehydrates from the
  `dumps_data_archive/` 7z archives when a plain snapshot file is absent.
  STAGING is promoted into `data/` only after every file verifies, then
  the app is optionally restarted and health-checked.
```

</details>

#### `vulnerability-lookup-rs/scripts/run_all_tests.sh`

- **Purpose:** Comprehensive workspace test runner producing a Markdown report.
- **Usage:** `bash vulnerability-lookup-rs/scripts/run_all_tests.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Orchestrates an eight-phase test pipeline for vulnerability-lookup-rs:
  static analysis (fmt / clippy / unit tests / shellcheck), build, data
  lifecycle, QA gates, API/endpoint verification, security scans
  (testssl / sqlmap / ZAP / nuclei), and UI/load/fuzz. Heavier phases are
  gated by RUN_* env flags. Writes a timestamped Markdown report under
  test_reports/ and exits non-zero if any check failed.
```

</details>

#### `vulnerability-lookup-rs/scripts/run_qa.sh`

- **Purpose:** Run every quality-assurance gate for vulnerability-lookup-rs.
- **Usage:** `bash vulnerability-lookup-rs/scripts/run_qa.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Runs the QA suite across Rust (fmt, clippy, tests, doc, audit, geiger,
  rust-doctor, machete), shell (shellcheck), Python (ruff, bandit), and
  frontend (htmlhint, oxlint, fta). Each check is gated on its tool being
  installed (missing tools are skipped, not failed). Prints a run/skip
  tally and exits non-zero if any check failed.
```

</details>

#### `vulnerability-lookup-rs/scripts/save_app_data.sh`

- **Purpose:** Snapshot the running app's redb + SQLite databases into dumps_data/.
- **Usage:** `bash vulnerability-lookup-rs/scripts/save_app_data.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Gracefully stops vl-web, then copies each live data file into a STAGING
  directory with a BOUNDED read (so a still-growing redb can never hang
  the copy), verifies each copy byte-for-byte, writes + self-verifies
  three hash-family sidecars (`.sha-256` / `.sha-512` / `.sha3-512`) per
  file, and only then atomically promotes STAGING into `dumps_data/`.
  The snapshot is replaced ONLY when every file verifies.
```

</details>

#### `vulnerability-lookup-rs/scripts/scan_dumps_dumps_archive_with_clamav_yara.sh`

- **Purpose:** Scan the dumps/ + dumps_archive/ trees with ClamAV and YARA-Forge.
- **Usage:** `bash vulnerability-lookup-rs/scripts/scan_dumps_dumps_archive_with_clamav_yara.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Refreshes the ClamAV signature DB via freshclam, downloads the latest
  YARA-Forge rule bundle from GitHub, then scans every configured dump
  directory with both engines.  Per-run logs and a summary land under
  logs/scan_dumps_<stamp>/.  Exits non-zero when ClamAV finds an
  infection or YARA matches, unless FAIL_ON_MATCH=0.
```

</details>

#### `vulnerability-lookup-rs/scripts/testssl_endpoints.sh`

- **Purpose:** Run testssl.sh against every public vl-web endpoint over TLS 1.3.
- **Usage:** `bash vulnerability-lookup-rs/scripts/testssl_endpoints.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Runs a full testssl.sh baseline once per host (TLS 1.3 only, EC key
  exchange, no RSA, clean vulnerability checks), then does a lightweight
  per-endpoint TLS 1.3 handshake + HTTP status probe across the page,
  API and static route catalogues.  JSON/HTML reports are written to a
  timestamped directory under documentation/tls/testssl/; exits 1 when
  any endpoint responds with an unexpected status.
```

</details>

#### `vulnerability-lookup-rs/scripts/uncompress_dumps.sh`

- **Purpose:** Restore every 7z dump archive into dumps_restore/ after verifying it.
- **Usage:** `bash vulnerability-lookup-rs/scripts/uncompress_dumps.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  The mirror image of `compress_dumps.sh`.  For every `*.7z` under
  dumps_archive/ it verifies the three checksum sidecars
  (`.sha-256` / `.sha-512` / `.sha3-512`), runs the 7z integrity
  test, extracts the single NDJSON payload into dumps_restore/, and
  writes+self-verifies three fresh sidecars for the restored file.
  Idempotent: an already-restored, sidecar-verified dump is skipped.
  A per-run Markdown + plain-text report is written under the
  `--target` documentation directory.
```

</details>

#### `vulnerability-lookup-rs/scripts/update_ansible_role.sh`

- **Purpose:** Sync built binaries, packages and static assets into the Ansible roles.
- **Usage:** `bash vulnerability-lookup-rs/scripts/update_ansible_role.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  For each role in ROLES, clears stale artefacts then copies the
  version-scoped vl-web/vl-cli binaries and .deb/.rpm packages (each
  with five checksum sidecars: sha-256/sha-512/sha3-512/blake3-512/
  shake256-512) plus the static web assets and a certs/ placeholder.
  Finally propagates the workspace Cargo.toml version into every
  embedded reference across the Ansible tree.  Idempotent.
```

</details>

#### `vulnerability-lookup-rs/scripts/zap_scan.sh`

- **Purpose:** Run OWASP ZAP against the vl-web TCP and QUIC listeners.
- **Usage:** `bash vulnerability-lookup-rs/scripts/zap_scan.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  <!-- markdownlint-disable MD024 MD033 MD044 -->
  <!-- rumdl-disable MD024 MD033 MD044 -->

  Detects a ZAP backend (Docker stable/legacy image or a native
  zap.sh), probes the HTTP/2 and HTTP/3 endpoints, then runs the
  requested scan mode (baseline / full / api) against the reachable
  listener.  HTML/JSON/XML/Markdown reports land under the shared
  documentation zap tree; the JSON/XML report is parsed and the run
  exits 1 on any High-risk alert (Medium too when ZAP_FAIL_ON_MEDIUM=1).
```

</details>

### `vulnerability-lookup-rs/tests/scripts/` — gate runners

#### `vulnerability-lookup-rs/tests/scripts/test_alint.sh`

- **Purpose:** Run alint over the repo and emit every documented output format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_alint.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs alint (a language-agnostic structure / filename / content
  linter) against the scan root and writes one report per documented
  format (human, json, sarif, github, markdown, junit, gitlab, agent)
  plus a SUMMARY.txt under
  documentation/linter/alint/alint_<TIMESTAMP>/. On findings it runs a
  size-bounded `alint fix` and re-checks. Self-skips when alint or
  .alint.yml is absent; --strict turns findings into a non-zero exit.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_ansible_role_assets.sh`

- **Purpose:** Validate the Ansible role's bundled files/ assets.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_ansible_role_assets.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Checks the nvulnlookup Ansible role's files/ tree: presence and ELF
  type of the vl-* binaries, completeness of the static/ subtree
  (css/js/img/fonts) against the source, optional certs/ validation
  (cert/key modulus match, expiry, permissions), and that the molecule
  vl-web fixture is a real binary. Prints a pass/fail/skip summary and
  exits non-zero on any failure.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_api_bash.sh`

- **Purpose:** End-to-end smoke + data-audit of the vl-web HTTP API.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_api_bash.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Exercises the vulnerability-lookup REST API on a running server:
  auth/status checks across health, system, vulnerability, search and
  404/405 paths, then fetches a slice of the API over both the 8080
  (HTTP/2) and 8081 (HTTP/3) listeners, compares bodies, dedups,
  checks CVSS presence, cross-checks IDs against dumps/*.ndjson, and
  writes a Markdown report under documentation/api/fetch_data_api/.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_apihunter.sh`

- **Purpose:** Run apihunter against a URL seed list and emit every format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_apihunter.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Opt-in gate that runs apihunter (an async API security scanner)
  against an operator-supplied APIHUNTER_URLS seed file, wrapped in a
  wall-clock timeout, and writes pretty/ndjson/sarif reports plus a
  Markdown summary under
  documentation/apihunter/apihunter_<TIMESTAMP>/. Guarantees a valid
  SARIF 2.1.0 (native or jaq-synthesised). Self-skips when apihunter
  or the seed file is absent; --strict fails on findings.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_arch_graphs.sh`

- **Purpose:** test_arch_graphs — capture the Rust workspace architecture graphs
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_arch_graphs.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  `cargo modules structure|dependencies|orphans` per workspace crate and
  `cargo depgraph` for the workspace, archives every artefact under a
  timestamped directory, synthesises a jaq SARIF 2.1.0 from the
  orphan-module findings, and validates it.  Both tools are read-only and
  operate on `cargo metadata` (workspace members only) — no filesystem walk,
  no source mutation.  See the inline comments and the sibling
  `test_arch_graphs.bats` for the full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bash_bats_sibling.sh`

- **Purpose:** Audit in-scope *.sh for a missing sibling .bats; emit MD + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bash_bats_sibling.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  AUDITS every *.sh in the repo EXCEPT skills/ and documentation/ for the
  presence of a co-located `<name>.bats` sibling test, reporting the ones
  that are MISSING.  Pure presence audit — no external tool.  Emits the
  list / Markdown / JSON / SARIF 2.1.0 formats under
  documentation/shell/bats/missing/, validates the SARIF via skills/sarif,
  and records that a missing test must be authored by hand per skills/bats
  (no autofix).  The audit is read-only + idempotent (byte-identical on a
  re-run).  Report-only by default; BATS_SIBLING_STRICT=1 fails when one or
  more *.sh lack a sibling .bats.  See the sibling
  `test_bash_bats_sibling.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bash_with_bats.sh`

- **Purpose:** Run bats on in-scope *.bats suites; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bash_with_bats.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  RUNS `bats --formatter tap` over every in-scope *.bats suite in the repo
  EXCEPT skills/ and documentation/ (and EXCEPT this gate's own sibling
  test_bash_with_bats.bats, to prevent infinite recursion), wrapping each
  suite in a `timeout` (BATS_TIMEOUT, default 120s).  Emits the TAP / JUnit
  / JSON / SARIF 2.1.0 formats under documentation/shell/bats/, validates
  the SARIF via skills/sarif, and normalises all timing + absolute paths so
  the reports are byte-identical across runs (idempotent).  Report-only by
  default; BATS_STRICT=1 fails when any suite has a failing test or times
  out.  See the sibling `test_bash_with_bats.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bash_with_checkbashisms.sh`

- **Purpose:** Run checkbashisms over in-scope *.sh; emit text + JSON + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bash_with_checkbashisms.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `checkbashisms -f -p` over every *.sh in the repo EXCEPT skills/
  and documentation/, emits a human report (checkbashisms.txt), a derived
  findings JSON (checkbashisms.json), and a jaq-derived SARIF 2.1.0
  (checkbashisms.sarif) under documentation/shell/checkbashisms/, validates
  the SARIF via skills/sarif, and records a NOT_APPLICABLE autofix note
  (checkbashisms only reports — bashisms are removed by hand).  The repo is
  never mutated, so the gate is idempotent.  Report-only by default;
  CHECKBASHISMS_STRICT=1 fails on any offender.  See the sibling
  `test_bash_with_checkbashisms.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bash_with_kcov.sh`

- **Purpose:** Run kcov line-coverage over in-scope *.sh; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bash_with_kcov.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `kcov` over every *.sh in the repo EXCEPT skills/ and documentation/
  on each script's side-effect-free `--help` code path, emits the human
  table / merged Cobertura XML / findings JSON / SARIF 2.1.0 formats under
  documentation/shell/kcov/, validates the SARIF via skills/sarif, and flags
  every file whose measured line coverage falls below KCOV_MIN_PERCENT
  (default 0, so informational by default).  kcov is a coverage recorder
  with no autofix, so the autofix slot is a NOT_APPLICABLE note (gaps are
  closed by writing tests).  kcov output embeds dates / absolute paths /
  timestamps which are normalised out, so the gate is idempotent.
  Report-only by default; KCOV_STRICT=1 fails when any file is below the
  threshold.  See the sibling `test_bash_with_kcov.bats` for the full
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bash_with_opengrep.sh`

- **Purpose:** Run opengrep SAST over in-scope *.sh; emit all formats + SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bash_with_opengrep.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `opengrep scan` (semgrep fork) over every *.sh in the repo EXCEPT
  skills/ and documentation/, with bash + injection + secrets rulesets.
  Emits the text / native JSON / SARIF 2.1.0 formats under
  documentation/shell/opengrep/.  opengrep emits SARIF 2.1.0 NATIVELY; the
  gate prefers that document and only falls back to a jaq-derived SARIF when
  the native one is absent or not 2.1.0.  Either way the SARIF is
  schema-validated via skills/sarif.  An autofix before/after demonstration
  runs on COPIES (the repo is never mutated; the gate is idempotent — it
  scans the relative target `.` so JSON/SARIF carry relative paths).
  Report-only by default; OPENGREP_STRICT=1 fails on any finding.  Self-skips
  cleanly when opengrep is missing, no ruleset resolves, or the registry is
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bash_with_shellcheck.sh`

- **Purpose:** Run shellcheck over in-scope *.sh; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bash_with_shellcheck.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `shellcheck` (static analysis linter) over every *.sh in the repo
  EXCEPT skills/ and documentation/, emits the list / tty / checkstyle /
  merged json1 / SARIF 2.1.0 formats under documentation/shell/shellcheck/,
  validates the SARIF via skills/sarif, and documents what `--format=diff`
  autofix would do on COPIES (the repo is never mutated, so the gate is
  idempotent).  Each shellcheck comment becomes one SARIF result with its
  own ruleId (SCnnnn), level, message, and line/column region.  Report-only
  by default; SHELLCHECK_STRICT=1 fails on any offender.  See the sibling
  `test_bash_with_shellcheck.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bash_with_shellharden.sh`

- **Purpose:** Run shellharden over in-scope *.sh; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bash_with_shellharden.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `shellharden --check` over every *.sh in the repo EXCEPT skills/
  and documentation/, emits the list / unified-diff / JSON / SARIF 2.1.0
  formats under documentation/shell/shellharden/, validates the SARIF via
  skills/sarif, and documents what `--replace` autofix would do on COPIES
  (the repo is never mutated, so the gate is idempotent).  Report-only by
  default; SHELLHARDEN_STRICT=1 fails on any offender.  See the sibling
  `test_bash_with_shellharden.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bash_with_shellmetrics.sh`

- **Purpose:** Run shellmetrics over in-scope *.sh; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bash_with_shellmetrics.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `shellmetrics` (cyclomatic-complexity reporter) over every *.sh in
  the repo EXCEPT skills/ and documentation/, emits the native human table
  / CSV plus a derived JSON / SARIF 2.1.0 under
  documentation/shell/shellmetrics/, validates the SARIF via skills/sarif,
  and flags every function whose CCN exceeds SHELLMETRICS_MAX_CCN
  (default 10).  shellmetrics is a reporter with no autofix, so the
  autofix slot is a NOT_APPLICABLE note.  The gate only measures — it never
  mutates a source — so it is idempotent.  Report-only by default;
  SHELLMETRICS_STRICT=1 fails when any function exceeds the threshold.  See
  the sibling `test_bash_with_shellmetrics.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bash_with_shfmt.sh`

- **Purpose:** Run shfmt over in-scope *.sh; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bash_with_shfmt.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `shfmt -l` (canonical ndaal style -i 0 -bn -ci -sr) over every
  *.sh in the repo EXCEPT skills/ and documentation/, emits the list /
  unified-diff / JSON / SARIF 2.1.0 formats under
  documentation/shell/shfmt/, validates the SARIF via skills/sarif, and
  documents what `shfmt -w` autofix would do on COPIES
  (the repo is never mutated, so the gate is idempotent).  Report-only by
  default; SHFMT_STRICT=1 fails on any offender.  See the sibling
  `test_bash_with_shfmt.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bats.sh`

- **Purpose:** Sweep-run every sister .bats file and archive TAP/JUnit/summary.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bats.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Discovers every committed .bats file across three directories
  (tests/scripts, workspace scripts, repo scripts), runs each one
  individually under a per-file timeout, and archives TAP, JUnit, and
  per-suite stderr plus a SUMMARY.tsv and human summary under
  documentation/shell/bats/<TIMESTAMP>/. Self-skips when bats-core is
  absent; exits non-zero if any suite reported a failure.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_benchmark.sh`

- **Purpose:** Benchmark the local vl-web API vs. the CIRCL reference service.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_benchmark.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Measures single-request latency for a fixed CVE sample against both
  the local vl-web API and the public CIRCL service, then runs a
  parallel throughput test against the local API. Computes
  min/max/avg/p50/p95/p99 percentiles and writes a Markdown report
  under documentation/rust/benchmark/benchmark-<TIMESTAMP>.md.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_benchmark_loadtest.sh`

- **Purpose:** Wrap the loadtest runner and render its oha JSON as Markdown.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_benchmark_loadtest.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Delegates to `test/loadtest/run.sh` (oha --http2 --insecure) against
  the configured base URL, captures the runner log, locates the newest
  `documentation/loadtest/` report directory, and emits a timestamped
  Markdown report under `test_reports/` with a per-endpoint throughput
  table, a rollup, and the raw runner output. Self-skips (exit 0) when
  `oha` is not on PATH.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_betterleaks.sh`

- **Purpose:** Scan the working tree for hard-coded secrets with betterleaks.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_betterleaks.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs two betterleaks (gitleaks-compatible) passes over the repo
  working tree — never the .git history: pass 1 uses the repo's own
  `.gitleaks.toml` + `.gitleaksignore`, pass 2 fetches the canonical
  ndaal base ruleset per run. Each pass emits json/csv/junit/sarif
  reports plus a SUMMARY.md under
  `documentation/secrets/betterleaks/betterleaks_<ISO>/`. Self-skips
  (exit 0) when the betterleaks binary is missing.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bincheck.sh`

- **Purpose:** Run bincheck binary-hardening checks over the release binaries.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bincheck.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Discovers every Mach-O / ELF / PE binary under `${SCAN_ROOT}`
  (default: QG_WORKSPACE/release) and runs `bincheck` once per
  documented output format (table/json/sarif), checking per-binary
  security properties (PIE, stack canary, NX, RELRO, code signature,
  banned functions, …). Reports and a SUMMARY.txt land under
  `documentation/rust/bincheck/bincheck_<TIMESTAMP>/`. Self-skips
  (exit 0) when bincheck is missing; `--strict` gates on findings.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_binsec.sh`

- **Purpose:** Run binsec binary-hardening checks over the release binaries.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_binsec.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Discovers every Mach-O / ELF / PE binary under `${SCAN_ROOT}`
  (default: QG_WORKSPACE/release, walked recursively) and runs
  `binsec` per binary, capturing text + JSON reports, aggregating the
  JSON, and deriving a SARIF 2.1.0 document via jaq (binsec has no
  native SARIF emitter). Reports and a SUMMARY.txt land under
  `documentation/security/binary/binsec/binsec_<TIMESTAMP>/`.
  Self-skips (exit 0) when binsec or jaq is missing; `--strict` gates
  on scan failures.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_blint.sh`

- **Purpose:** Probe the OWASP `blint` binary linter; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_blint.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  the OWASP `blint` binary linter over the BUILT first-party binaries
  (vl-web / vl-cli / vl-updater under target/, release preferred), captures
  its security-audit findings, derives a schema-validated SARIF 2.1.0 (blint
  has no native SARIF reporter), and writes reports under
  documentation/security/blint/.  Analysis-only + idempotent; report-only
  unless BLINT_STRICT=1 (which fails on any high/critical finding).
  Self-skips (rc 0) when blint is absent OR when no binary has been built.
  See the sibling test_blint.bats.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bruno_dashboard_coverage.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bruno_dashboard_coverage.sh [arguments...]`

#### `vulnerability-lookup-rs/tests/scripts/test_build_bumblebee.sh`

- **Purpose:** Clone, build, test, selftest, and install perplexityai/bumblebee.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_build_bumblebee.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Five-phase pipeline: git-clone the bumblebee source, `go build` the
  binary (recording checksum sidecars), `go test ./...`, run the
  binary's `selftest`, then `install` it to a system sbin directory.
  Any test failure aborts the install step. Per-phase logs and a
  SUMMARY.txt land under
  `documentation/security/binary/bumblebee/bumblebee_<TIMESTAMP>/`.
  Self-skips (exit 0) when git / Go (>= 1.25) are missing.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_bumblebee.sh`

- **Purpose:** Exercise every native bumblebee subcommand and capture its output.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_bumblebee.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Detects an installed bumblebee binary and runs each native
  subcommand — version, roots, selftest, and a bounded `scan`
  (baseline profile, --max-duration cap) — capturing NDJSON scan
  output. Derives a slurped JSON array view and, when an exposure
  catalog yields findings, a SARIF 2.1.0 view, both via jaq. Reports
  and a SUMMARY.txt land under
  `documentation/security/bumblebee/bumblebee_<TIMESTAMP>/`. Self-skips
  (exit 0) when the bumblebee binary is missing; `--strict` gates on
  subcommand failures.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_acl.sh`

- **Purpose:** Enforce cackle's per-crate capability policy via `cargo acl` and derive a SARIF report.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_acl.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE supply-chain gate that runs cackle (https://github.com/cackle-rs/cackle)
  through `cargo acl` over the workspace, enforcing the per-dependency +
  per-build-script capability policy (net / fs / process / unsafe) declared in
  the workspace-root cackle.toml. Complements cargo-vet / cargo-deny /
  cargo-audit: vet/deny/audit answer "may we ship this crate version?", cackle
  answers "which ambient capabilities may each crate actually reach?".
  Because `cargo acl` wraps a full cargo build it is SLOW and therefore LIVE
  (--full only), like cargo-careful / cargo-hack. Self-skips cleanly (rc 0)
  when cargo-acl is not installed OR the workspace has no cackle.toml yet.
  Report-only by default; CARGO_ACL_STRICT=1 promotes any policy violation
  (or a non-zero `cargo acl` exit) to a blocking failure (rc 1). Reports land
  under documentation/security/cackle/<ISO>/ with a jaq-derived, validated
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_afl.sh`

- **Purpose:** `cargo-afl` (AFL++) fuzz runner + jaq-derived SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_afl.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  See the inline comments below and the sibling `test_cargo_afl.bats`
  for the full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_audit.sh`

- **Purpose:** `cargo audit` RustSec advisory scan of the workspace Cargo.lock.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_audit.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Scans the workspace `Cargo.lock` against the RustSec advisory
  database, denying warnings / unsound / unmaintained / yanked.
  Reads the optional RUSTSEC ignore list from `audit.toml` and
  forwards each id as `--ignore <ID>`. Writes a text log plus a
  JSON findings file under documentation/rust/cargo_audit/.
  Self-skips with rc=0 when cargo-audit is not on PATH.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_auditable.sh`

- **Purpose:** `cargo auditable build` SBOM-in-binary build + extraction gate.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_auditable.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Builds vl-cli + vl-web with `cargo auditable build --release`
  into an isolated target dir, then exercises four output formats
  against the embedded `.dep-v0` section: raw section bytes,
  `rust-audit-info` pretty + raw JSON, and `cargo audit bin`.
  Rolls up per-binary per-method verdicts (pass / fail /
  unsupported); RC=1 iff any method reports `fail`. Full build is
  5-10 min. Self-skips with rc=0 when cargo-auditable is missing.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_bench.sh`

- **Purpose:** `cargo bench` (Criterion) workspace benchmark runner + archive.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_bench.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs the workspace's Criterion benchmarks registered via
  `[[bench]]` blocks, then archives the standard Criterion HTML
  report and a flat-text stdout log under
  documentation/rust/perf/cargo-bench_<TIMESTAMP>/.
  Self-skips with rc=0 when no `[[bench]]` target is registered.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_bloat.sh`

- **Purpose:** `cargo bloat` binary-size analyser for the release binaries.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_bloat.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Surfaces what eats the release binary's bytes for vl-web and
  vl-cli — by-crate and by-function breakdowns plus a JSON form
  for cross-run diffing — archived under
  documentation/rust/cargo_bloat/cargo-bloat_<ISO>/.
  Self-skips with rc=0 when cargo-bloat is not on PATH.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_call_stack.sh`

- **Purpose:** `cargo call-stack` worst-case stack-usage survey + call graph.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_call_stack.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs cargo-call-stack (nightly) over each workspace binary
  (vl-web, vl-cli) to emit a per-binary `.dot` call graph with a
  worst-case stack estimate per node, renders SVG/PNG when
  graphviz `dot` is present, and rolls up node/edge/byte counts
  into SUMMARY.tsv under documentation/call-stack/<TIMESTAMP>/.
  Advisory archive only — never enforces a policy. Self-skips with
  rc=0 when cargo-call-stack or the nightly toolchain is missing.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_capsec.sh`

- **Purpose:** `cargo capsec audit` static capability audit, every output format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_capsec.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs cargo-capsec — a static capability audit that reports what
  the code can do to the outside world (filesystem, network,
  process spawning, FFI, ambient authority) — and emits every
  documented format (text / json / sarif) under
  documentation/rust/cargo_capsec/. Informational by default;
  `--strict` exits non-zero on any finding. Self-skips with rc=0
  when cargo-capsec is missing.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_careful.sh`

- **Purpose:** Run the test suite under cargo-careful's hardened std/core.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_careful.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Quality gate that runs `cargo +nightly careful test --workspace
  --all-features`, which rebuilds std/core with debug-assertions and
  extra runtime sanitisers to catch a class of undefined behaviour.
  Archives the setup + test logs under
  documentation/rust/soundness/cargo-careful_<TIMESTAMP>/. Self-skips
  (exit 0) when the nightly toolchain or cargo-careful is missing.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_clippy.sh`

- **Purpose:** Lint the whole workspace with clippy, warnings-as-errors.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_clippy.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Quality gate that runs `cargo clippy --workspace --all-targets
  --all-features -- -D warnings`, honouring the workspace clippy.toml
  thresholds. Writes a human-readable log plus a JSON findings stream
  under documentation/rust/lint/cargo-clippy_<TIMESTAMP>/. Self-skips
  (exit 0) when cargo is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_crev.sh`

- **Purpose:** Archive cargo-crev distributed-review status per crate.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_crev.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Forensic (non-enforcing) survey that runs `cargo crev verify` for
  every workspace member, recording each dependency's community
  review status plus a SUMMARY.tsv rollup under
  documentation/rust/cargo_crev/<TIMESTAMP>/. Per-crate non-zero exits
  are advisory (unreviewed deps are the normal state). Self-skips
  (exit 0) when cargo-crev or an initialised crev trust DB is absent.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_crev_to_cargo_vet_converter.sh`

- **Purpose:** test_cargo_crev_to_cargo_vet_converter — informational crevette
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_crev_to_cargo_vet_converter.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  crevette (https://lib.rs/crevette, binary `crevette`) converts the
  operator's cargo-crev reviews into a cargo-vet-compatible audits.toml so
  crev's distributed reviews can satisfy cargo-vet's audit-coverage gate.
  This gate runs `crevette`, records its output (text) + the generated
  audits.toml (toml, when an Id is configured), derives a sorted JSON record
  and a validated SARIF 2.1.0 summary note (crevette emits no native
  JSON/SARIF — both are jaq-derived), and documents that crevette exposes no
  autofix (before == after).  Without a current crev Id (the CI norm)
  crevette writes nothing and the gate records that honestly.  The gate never
  fails CI: it self-skips (rc 0) when cargo / crevette / jaq is missing and
  otherwise exits 0.  Runs after the cargo-crev gate and before cargo-vet
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_criterion.sh`

- **Purpose:** `cargo-criterion` benchmark runner + jaq-derived SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_criterion.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  See the inline comments below and the sibling
  `test_cargo_criterion.bats` for the full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_cyclonedx.sh`

- **Purpose:** Emit CycloneDX JSON + XML SBOMs from Cargo.lock.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_cyclonedx.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Quality gate that runs `cargo cyclonedx --all` in both json and xml
  formats to capture the pre-build dependency graph for every
  workspace member, then moves each crate's bom.* into
  documentation/sbom/cargo-cyclonedx_<TIMESTAMP>/. Complements the
  compiled-binary SBOM scan. Self-skips (exit 0) when cargo-cyclonedx
  is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_deadlinks.sh`

- **Purpose:** Probe `cargo deadlinks`; emit all formats + jaq-derived SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_deadlinks.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Builds
  the workspace rustdoc HTML out-of-tree with `cargo doc`, runs
  `cargo deadlinks` over it to find broken documentation links, normalises the
  log to JSON, derives a schema-validated SARIF 2.1.0 (no native SARIF
  reporter exists), and writes reports under documentation/rust/cargo_deadlinks/.
  Analysis-only + idempotent; report-only unless CARGO_DEADLINKS_STRICT=1.
  Self-skips (rc 0) when cargo-deadlinks is absent.  See the sibling
  test_cargo_deadlinks.bats.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_deny.sh`

- **Purpose:** Enforce cargo-deny policy: advisories, bans, licenses, sources.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_deny.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Quality gate that runs `cargo deny check` against the workspace
  deny.toml — RustSec advisories, duplicate/denied-crate bans, the
  SPDX license allow-list, and registry/git source pinning — and
  archives the log under
  documentation/rust/cargo_deny/cargo-deny_<TIMESTAMP>/. Self-skips
  (exit 0) when cargo-deny is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_describe.sh`

- **Purpose:** Archive cargo-describe workspace metadata in every format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_describe.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Read-only forensic runner that invokes `cargo describe --fields all`
  once per --output-format value (human-text, csv, md-table, plain),
  archiving each per-format stdout/stderr plus a roll-up report.md
  under documentation/rust/cargo_describe/cargo-describe_<TIMESTAMP>/.
  Only real failures bump the exit code; unsupported formats stay
  advisory. Self-skips (exit 0) when cargo or cargo-describe is absent.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_dokita.sh`

- **Purpose:** Run cargo-dokita and archive every documented output format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_dokita.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Wraps cargo-dokita (Rust project best-practice / pitfall analyser),
  emitting each documented format (human, json) under
  documentation/rust/cargo_dokita/cargo_dokita_<TIMESTAMP>/ plus a
  SUMMARY.txt rollup. Self-skips with rc=0 when cargo-dokita is not on
  PATH; informational by default, exits non-zero only under --strict.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_duplicates.sh`

- **Purpose:** Archive `cargo duplicates` full and --short output.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_duplicates.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs cargo-duplicates twice (full dependency chains + `--short`
  per-crate version list), archiving each mode plus a report.md rollup
  with the duplicate count under
  documentation/rust/cargo_duplicates/cargo-duplicates_<TIMESTAMP>/.
  Forensic only: never fails on a positive duplicate count (the policy
  gate is `cargo tree --duplicates`). Self-skips with rc=0 when cargo
  or cargo-duplicates are not on PATH.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_dylint.sh`

- **Purpose:** Run `cargo dylint` custom + community lint plugins.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_dylint.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs registered dylint lint libraries (`[workspace.metadata.dylint]`)
  across all workspace targets and features, archiving stdout under
  documentation/rust/lint/cargo-dylint_<TIMESTAMP>/. Self-skips with
  rc=0 when cargo-dylint is absent or no dylint section is registered.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_expand.sh`

- **Purpose:** Archive per-crate `cargo expand` macro / derive expansion output.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_expand.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Iterates every workspace member crate and captures the post-expansion
  Rust source (`--color never --theme none --tests --ugly`) plus a
  SUMMARY.tsv line-and-byte rollup under
  documentation/rust/macro-expansion/<TIMESTAMP>/. Forensic archive
  only — per-crate expansion errors are advisory, never fatal.
  Self-skips with rc=0 when cargo-expand is not on PATH.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_fa.sh`

- **Purpose:** Run `cargo fa` (framealloc analyser) once per output format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_fa.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs the cargo-fa framealloc static analyser with `--all`, auto-
  discovering every `--format` the tool supports (falling back to a
  canonical list) and archiving each format's stdout/stderr plus a
  report.md verdict table under
  documentation/rust/cargo_fa/cargo-fa_<TIMESTAMP>/. Self-skips with
  rc=0 when cargo or cargo-fa are not on PATH. CCB_FA_FORMATS overrides
  the auto-discovered format list.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_features_manager.sh`

- **Purpose:** Run `cargo features-manager analyze` for stray Cargo features.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_features_manager.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs cargo-features-manager in non-interactive `analyze` mode across
  the workspace to surface unused / over-enabled / conflicting feature
  flags, archiving the output under
  documentation/rust/deps/cargo-features-manager_<TIMESTAMP>/. Advisory
  only — findings never fail the gate. Self-skips with rc=0 when
  cargo-features-manager is not on PATH.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_ferris_wheel.sh`

- **Purpose:** Quality gate: detect circular workspace dependency cycles.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_ferris_wheel.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs cargo-ferris-wheel in three passes — `inspect` (cycle verdict
  in human/json/junit), `spectacle` (Mermaid + Graphviz DOT dep-graph
  renders), and `lineup` (transitive dep inventory). Artefacts land
  under documentation/rust/cargo_ferris_wheel/. The gate exit code is
  taken from the inspect pass only. Self-skips (rc 0) when
  cargo-ferris-wheel is not on PATH.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_fl.sh`

- **Purpose:** Quality gate: run cargo-fl (fast lint) and emit every report format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_fl.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs cargo-fl over the crate sources and writes default, json, and
  github reports plus a jaq-derived SARIF 2.1.0 document and a SUMMARY
  under documentation/rust/cargo_fl/. Report-only by default (rc 0);
  set CARGO_FL_STRICT=1 to fail when issues are found. Never passes
  --fix, so no source file is mutated. Self-skips (rc 0) when cargo,
  cargo-fl, or jaq is missing.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).

test_cargo_fl.sh — run `cargo fl check` (cargo-fl, "fast lint") over the
workspace and emit EVERY available data format under
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_flamegraph.sh`

- **Purpose:** Quality gate: capture a cargo-flamegraph CPU profile.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_flamegraph.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Profiles a chosen workspace binary (default vl-cli) and writes a
  flamegraph SVG under documentation/rust/perf/. Requires perf (Linux)
  or dtrace (macOS); self-skips (rc 0) when cargo-flamegraph or the
  kernel profiler is unavailable. Knobs: FLAMEGRAPH_BIN,
  FLAMEGRAPH_BIN_ARGS, FLAMEGRAPH_DURATION.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_fmt.sh`

- **Purpose:** Quality gate: run `cargo fmt --all --check` over the workspace.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_fmt.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Verifies every workspace source file matches rustfmt's canonical
  form. Self-skips (rc 0) when cargo is not on PATH. Writes the
  `cargo fmt --all --check` output to a timestamped log under
  documentation/rust/fmt/ and warns (does not hard-fail) when the
  formatter would modify one or more files. Read-only: never rewrites
  sources.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_fmt_toml.sh`

- **Purpose:** Quality gate: format every workspace Cargo.toml with cargo-fmt-toml.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_fmt_toml.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Backs up the root Cargo.toml, snapshots every member manifest, then
  runs cargo-fmt-toml in three passes — check (diagnose), apply
  (write), and check (idempotency verify) — capturing a before/after
  diff and a report under documentation/rust/cargo_fmt_toml/. Mutates
  the working tree's Cargo.toml files on the apply pass. Self-skips
  (rc 0) when cargo-fmt-toml is not on PATH.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_geiger.sh`

- **Purpose:** Quality gate: survey transitive unsafe code with cargo-geiger.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_geiger.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Iterates every workspace member crate and runs cargo-geiger with the
  most-restrictive flag set (all deps/targets/features, include-tests,
  locked/frozen/offline), archiving per-crate JSON under
  documentation/rust/cargo_geiger/. Advisory only — first-party unsafe
  is already blocked by #![forbid(unsafe_code)]. Self-skips (rc 0)
  when cargo-geiger is not on PATH.

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_goggles.sh`

- **Purpose:** Probe `cargo-goggles` crate provenance; emit all formats + jaq-derived SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_goggles.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  cargo-goggles over the workspace's resolved Cargo.lock dependency set to
  verify that every published crates.io artifact reconciles with the git
  repository it claims — the provenance gap cargo-vet, cargo-audit and
  cargo-deny all leave open.  Folds, normalises and sorts the checker log,
  derives a schema-validated SARIF 2.1.0 (no native SARIF reporter exists),
  and writes reports under `documentation/rust/cargo_goggles/`.  Content
  mismatches are error-level; unverifiable cases are note-level.
  Analysis-only + idempotent; report-only unless CARGO_GOGGLES_STRICT=1.
  Self-skips (rc 0) when cargo-goggles, cargo, or Cargo.lock is absent.
  See the sibling test_cargo_goggles.bats.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_hack.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_hack.sh [arguments...]`

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_hakari.sh`

- **Purpose:** Archive the cargo-hakari workspace-hack feature-unification state.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_hakari.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs cargo-hakari against the workspace and archives its consistency
  verdicts — `verify`, `manage-deps --dry-run`, a workspace-hack
  Cargo.toml snapshot, and `generate --diff` — into a timestamped
  forensic directory under documentation/rust/cargo-hakari/. Self-skips
  when cargo-hakari is absent or the workspace has no
  [workspace.metadata.hakari] block; verify drift is advisory here.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_impact.sh`

- **Purpose:** Blast-radius diff analysis via cargo-impact, archived 3 ways.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_impact.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs cargo-impact against a git diff (--since ref) to identify the
  tests, APIs, and docs affected, persisting json / markdown / sarif
  reports in parallel under documentation/rust/cargo_impact/. Self-skips
  when cargo-impact or git is missing, outside a work tree, or with no
  usable --since ref; exit status follows the worst --fail-on verdict.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_inspect.sh`

- **Purpose:** Archive per-crate Rust syntactic-sugar desugaring via cargo-inspect.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_inspect.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Iterates every workspace member crate and runs cargo-inspect to rewrite
  Rust sugar (`?`, `for`, `if let`, ...) into the lower-level form the
  compiler operates on, writing one <crate>.rs archive per crate under
  documentation/rust/dinspect/. A forensic archive only — per-crate
  errors are advisory. Self-skips when cargo-inspect is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_insta.sh`

- **Purpose:** Fail on uncommitted insta snapshot drift (.snap.new) in the tree.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_insta.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `cargo insta test --check` to fail whenever any `.snap.new`
  exists in the workspace — the drift class where a developer forgets to
  accept or revert a regenerated snapshot. Lists pending snapshots and
  captures output under documentation/rust/cargo_insta/. Self-skips when
  cargo-insta is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_install_update.sh`

- **Purpose:** Keep installed cargo binaries current via cargo-update.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_install_update.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Two-pass driver for `cargo install-update`: pass 1 lists pending
  updates (read-only), pass 2 applies them all (`--all --git`, a write
  pass that mutates ~/.cargo/bin). Logs and a report.md land under
  documentation/rust/cargo_install_update/. Full-sweep only (network +
  side effects); self-skips when cargo-install-update is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_kani.sh`

- **Purpose:** Model-check every #[kani::proof] harness with cargo-kani.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_kani.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs the Kani Rust verifier (CBMC backend) across the workspace to
  prove absence of panics, memory-safety violations, and assertion
  failures within each harness's bounded input space. Output under
  documentation/rust/cargo_kani/. Gated hard on QG_RUN_KANI=1
  (nightly-only + slow) and self-skips when cargo-kani is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_license.sh`

- **Purpose:** Archive each workspace crate's dependency-licence survey (`cargo license`).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_license.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Iterates every workspace member crate and runs cargo-license,
  capturing three formats side by side per crate (JSON, TSV, and a
  human-readable table), a per-crate size SUMMARY.tsv, and a
  workspace-wide unique-licence rollup (LICENSES.txt, when jq is
  present). Forensic archive only — the licence policy verdict is
  gate 5 `cargo deny`, not this script. Self-skips with rc=0 when
  cargo-license is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_llvm_lines.sh`

- **Purpose:** Archive the per-crate `cargo llvm-lines` monomorphisation profile.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_llvm_lines.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs cargo-llvm-lines against each first-party crate (vl-core,
  vl-models, vl-feeders, vl-web, vl-cli) to surface the functions
  and generic instantiations that emit the most LLVM IR — the
  compile-time hotspots. Writes one report per crate under
  documentation/rust/perf/. Sister tool to cargo-bloat, which
  surfaces runtime binary size rather than compile cost.
  Self-skips with rc=0 when cargo-llvm-lines is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_machete.sh`

- **Purpose:** Detect declared-but-unused workspace dependencies with `cargo machete`.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_machete.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Scans every workspace member's Cargo.toml against its source for
  dependencies that are declared but never imported, catching
  dep-bloat before merge. `--with-metadata` makes machete honour
  per-crate `[package.metadata.cargo-machete]` ignore lists. The
  full run log is archived and findings are surfaced as a
  non-fatal warning. Self-skips with rc=0 when cargo-machete is
  not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_mend.sh`

- **Purpose:** Run the `cargo mend` visibility auditor once per advertised output mode.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_mend.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Auto-discovers cargo-mend's output modes from `--help` (default,
  --json, --check, --markdown, --text, --format), runs each, and
  archives per-mode stdout and stderr plus a rolled-up per-mode
  verdict table (pass / unsupported / fail). Modes rejected by the
  argv parser are `unsupported` (informational); only real failures
  bump the reported rc. Wired into `quality_gates.sh --full` only.
  Self-skips with rc=0 when cargo or cargo-mend is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_minimal_versions.sh`

- **Purpose:** Probe `cargo minimal-versions check`; emit all formats + jaq-derived SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_minimal_versions.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Resolves
  every workspace dependency to its DECLARED MINIMUM version with taiki-e's
  `cargo minimal-versions` (which drives the nightly-only
  `-Z minimal-versions` through `cargo hack`) and builds, so an
  under-specified version requirement such as `serde = "1"` fails HERE rather
  than in a downstream consumer carrying an older lockfile.  Normalises the
  build log to JSON, derives a schema-validated SARIF 2.1.0 (no native SARIF
  reporter exists), and writes reports under
  documentation/rust/cargo_minimal_versions/.  Analysis-only + idempotent:
  artefacts go to an out-of-tree CARGO_TARGET_DIR and the rewritten Cargo.lock
  is restored byte-for-byte.  Report-only unless
  CARGO_MINIMAL_VERSIONS_STRICT=1.  Self-skips (rc 0) naming whichever of the
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_msrv.sh`

- **Purpose:** Verify the workspace's claimed minimum supported Rust version (`cargo msrv`).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_msrv.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `cargo msrv verify` against a member-crate manifest (default
  crates/vl-web/Cargo.toml, override via MSRV_MANIFEST) to confirm
  the pinned rust-version still compiles cleanly — catching a
  contributor who accidentally uses a newer-than-claimed language
  feature. Writes both JSON and plain-text reports. Self-skips with
  rc=0 when cargo-msrv is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_mutants.sh`

- **Purpose:** Run the `cargo mutants` mutation tester over the workspace.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_mutants.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Mutates source (swaps operators, drops branches, returns default
  values) and re-runs the test suite to find weak or missing tests —
  every surviving "MISSED" mutant is behaviour the tests fail to
  detect. Slow, so it lives in the live-gate lane that `--fast`
  skips. Tunable via MUTANTS_TIMEOUT_SECS, MUTANTS_TIMEOUT_MUTANTS,
  and MUTANTS_PACKAGE. Self-skips with rc=0 when cargo-mutants is
  not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_nextest.sh`

- **Purpose:** cargo-nextest quality gate — parallel test runner that surfaces flaky tests.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_nextest.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Self-skipping quality gate that runs `cargo nextest run
  --workspace --all-features --no-fail-fast` in addition to the
  plain `cargo test` gate, to surface flaky / racy / order-dependent
  tests the serial default runner misses. Skips cleanly (rc 0) when
  cargo-nextest is not on PATH; writes the run log under
  documentation/rust/cargo_nextest/cargo-nextest_<TIMESTAMP>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_oneway.sh`

- **Purpose:** cargo-oneway quality gate — opinionated rustfmt + clippy + dylint runner.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_oneway.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs the Oneway one-command lint suite
  (github.com/Almaju/oneway-lints) in two passes: `cargo oneway fmt`
  applies rustfmt fixes, then `cargo oneway` re-audits (rustfmt-check
  + clippy + the oneway dylint library). Self-skips (rc 0) when
  cargo-oneway, cargo-dylint, or dylint-link are missing; the second
  pass's verdict is the gate exit code. Logs land under
  documentation/rust/cargo_oneway/cargo-oneway_<TIMESTAMP>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_outdated.sh`

- **Purpose:** cargo-outdated quality gate — reports workspace deps with newer releases.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_outdated.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Self-skipping quality gate that lists workspace dependencies with
  a newer version available on crates.io, complementing cargo audit,
  cargo deny, and cargo vet (none of which flag a merely-old dep).
  Advisory by default (rc 0); set OUTDATED_FAIL_ON_MAJOR=1 to fail
  on any available major-version bump, and OUTDATED_DEPTH to widen
  from direct deps (1) to the whole tree (0). Writes stdout.log and
  findings.json under
  documentation/rust/cargo_outdated/cargo-outdated_<TIMESTAMP>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_perf.sh`

- **Purpose:** cargo-perf quality gate — preventive performance-anti-pattern analysis for Rust.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_perf.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs cargo-perf (crates.io/crates/cargo-perf) over the Cargo
  workspace to catch async / lock / allocation / iteration
  anti-patterns before production, emitting every documented output
  format (console, json, sarif). Informational by default (rc 0);
  pass --strict to fail on any finding and --strict-rules to run only
  the high-confidence rules. Self-skips (rc 0) when cargo-perf is
  missing or the scan root has no Cargo.toml. Reports land under
  documentation/rust/cargo_perf/cargo_perf_<TIMESTAMP>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_propagate_features.sh`

- **Purpose:** cargo-propagate-features runner — propagates workspace feature flags to deps.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_propagate_features.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Backs up the root Cargo.toml, snapshots every workspace member's
  Cargo.toml, archives the tool's --help, optionally runs a
  --dry-run / --check diagnose pass when advertised, then applies
  `cargo propagate-features` (which pushes a crate's feature flags
  down to its dependencies). A before/after diff is captured for
  forensic audit. Only the apply pass's rc bumps the verdict.
  Self-skips (rc 0) when cargo or cargo-propagate-features is
  missing. Artefacts under
  documentation/rust/cargo_propagate_features/cargo-propagate-features_<TIMESTAMP>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_public_api.sh`

- **Purpose:** cargo-public-api quality gate — snapshots each library crate's API surface.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_public_api.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Self-skipping quality gate that captures the public API surface
  (every exported item, signature, and trait) of each first-party
  library crate (vl-core, vl-models, vl-feeders), giving reviewers a
  snapshot to diff PR-over-PR. Complements cargo semver-checks, which
  detects breaking changes. Requires a nightly toolchain (unstable
  rustdoc JSON); skips cleanly (rc 0) when cargo-public-api is
  missing. One <crate>.txt per crate under
  documentation/api/cargo-public-api_<TIMESTAMP>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_quality.sh`

- **Purpose:** Run the cargo-qual read-only structural-quality audit over the crates.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_quality.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs a single read-only `cargo qual` audit (crate `rustqual`; the
  `cargo qual` subcommand alias) over the first-party `crates` tree,
  emitting the text / json / sarif reports and gating on cargo-qual's
  exit code (1 = findings, 0 = clean). cargo-qual has NO auto-fix pass.
  Self-skips (rc=0) when `cargo-qual` is not on PATH. All reports plus a
  roll-up are archived under `documentation/rust/cargo_quality/`.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_reedme.sh`

- **Purpose:** Exercise cargo-reedme across every advertised output mode.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_reedme.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Auto-discovers the supported modes (markdown / `--json` / `--check`)
  from `--help`, runs each against an isolated copy of the workspace
  README, and classifies every run as pass / unsupported / fail.
  Self-skips (rc=0) when cargo or cargo-reedme is missing. Per-mode
  output is archived under `documentation/rust/cargo_reedme/`.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_semver_checks.sh`

- **Purpose:** Diff the workspace public API against the latest crates.io release.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_semver_checks.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `cargo semver-checks check-release --workspace`, failing on
  any change that would require a major version bump so accidental
  API breakage is caught before a release tag. Self-skips (rc=0)
  when cargo-semver-checks is not on PATH. The run log is archived
  under `documentation/rust/cargo_semver_checks/`.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_spellcheck.sh`

- **Purpose:** Spell-check the workspace doc comments with cargo-spellcheck.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_spellcheck.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs the non-interactive `cargo spellcheck check`, which uses
  hunspell dictionaries and understands Rustdoc syntax so it does
  not false-flag type names like `Vec<T>`. Findings are surfaced as
  warnings, not gate failures. Self-skips (rc=0) when cargo-spellcheck
  is missing; output lands under `documentation/rust/lint/`.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_supply_chain.sh`

- **Purpose:** Enumerate the publishers behind every workspace dependency.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_supply_chain.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Emits the `publishers`, `crates`, and `json` reports from
  cargo-supply-chain so a reviewer can spot single-author or
  single-publisher crates that warrant a `cargo vet trust` or audit.
  Complements the cargo-vet gate. Self-skips (rc=0) when
  cargo-supply-chain is missing; reports land under
  `documentation/rust/deps/`.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_tarpaulin.sh`

- **Purpose:** Measure workspace test coverage with cargo-tarpaulin.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_tarpaulin.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs an instrumented coverage sweep, emitting HTML, LCOV, Cobertura
  XML, and JSON reports plus the raw stdout log. Scope and per-test
  timeout are tunable via `TARPAULIN_PACKAGES` and `TARPAULIN_TIMEOUT`.
  Self-skips (rc=0) when cargo-tarpaulin is not on PATH; output lands
  under `documentation/rust/cargo_tarpaulin/`.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_test.sh`

- **Purpose:** Two-pass cargo-test workspace runner: lib/integration + doctests.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_test.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `cargo test --workspace --all-features` in two passes — pass 1
  covers the lib, bin, and integration tests; pass 2 covers the
  doctests that the default invocation skips — and tees both into a
  single log under `documentation/test/`. Honours QG_TEST_THREADS
  (forwarded as RUST_TEST_THREADS) for constrained environments.
  Self-skips with rc=0 when cargo is not on PATH; exits 1 when any
  test-result group fails.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_thanku.sh`

- **Purpose:** Run cargo-thanku once per output format and archive each result.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_thanku.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Drives `cargo-thanku` (dependency-acknowledgment generator) once per
  output format — auto-discovering the format list from `--help` with a
  canonical fallback — and archives every per-format `.out` + `.log`
  plus a roll-up `report.md` under `documentation/rust/cargo_thanku/`.
  Works around two upstream v0.5.1 bugs (ignored `--output`, stripped
  `--format`). Self-skips with rc=0 when cargo/cargo-thanku is absent.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_tree_duplicates.sh`

- **Purpose:** Survey cargo-tree duplicates: crates resolved to >1 version.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_tree_duplicates.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `cargo tree --workspace --all-features --duplicates` and counts
  crates that resolve to more than one version — a code-bloat and
  security signal (advisories often patch only one resolved version).
  Archives the raw list under `documentation/rust/deps/`. Advisory by
  default; set QG_TREE_DUPLICATES_STRICT=1 to fail on any duplicate.
  Self-skips with rc=0 when cargo is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_udeps.sh`

- **Purpose:** Run cargo-udeps (nightly) to find unused dependencies.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_udeps.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `cargo +nightly udeps --workspace --all-targets --all-features`
  — the resolver-accurate complement to `cargo machete` — and emits a
  human-readable log plus machine-readable JSON under
  `documentation/rust/cargo_udeps/`. Self-skips with rc=0 when
  cargo-udeps or the nightly toolchain is missing; warns (does not
  hard-fail) when unused dependencies are detected.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_unmaintained.sh`

- **Purpose:** Probe `cargo unmaintained`; emit all formats + jaq-derived SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_unmaintained.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  Trail of Bits' `cargo unmaintained` over the Cargo workspace to find
  EMPIRICALLY unmaintained dependencies — archived repositories, repositories
  that no longer exist or no longer contain the package, and dormant upstreams
  whose last commit exceeds the max-age threshold — i.e. the long tail that no
  RUSTSEC advisory covers yet, which `cargo audit` cannot see.  Normalises the
  report to JSON, derives a schema-validated SARIF 2.1.0 (no native SARIF
  reporter exists), and writes reports under
  `documentation/rust/cargo_unmaintained/`.  Analysis-only + idempotent;
  report-only unless `CARGO_UNMAINTAINED_STRICT=1`.  Self-skips (rc 0) when
  cargo-unmaintained is absent.  Needs network; a GitHub token is read from
  `GITHUB_TOKEN_PATH`/`GITHUB_TOKEN` and is NEVER echoed.  See the sibling
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_unused_workspace_deps.sh`

- **Purpose:** cargo-unused-workspace-deps (report-only): text + json + SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_unused_workspace_deps.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `cargo unused-workspace-deps` in REPORT mode (never `--fix`)
  over the workspace Cargo.toml and emits every data format under
  `documentation/rust/cargo_unused_workspace_deps/`: native text,
  findings JSON parsed via jaq, and a jaq-derived SARIF 2.1.0 document,
  plus a SUMMARY.txt. Report-only by default (exit 0); CUWD_STRICT=1
  fails on findings. Self-skips when cargo/subcommand/jaq is missing.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_valgrind.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_valgrind.sh [arguments...]`

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_vet.sh`

- **Purpose:** Run cargo-vet check: supply-chain audit-coverage gate.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_vet.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `cargo vet check` to confirm every dependency in `Cargo.lock`
  is covered by an in-tree audit, a trust entry, an imported peer audit
  (mozilla / google / bytecodealliance), or a tracked exemption in
  `supply-chain/config.toml`. Archives the run under
  `documentation/rust/cargo_vet/`. Self-skips with rc=0 when cargo-vet
  is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_workspace_lints.sh`

- **Purpose:** Run `cargo workspace-lints` and emit text + JSON + SARIF reports.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_workspace_lints.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Quality gate that runs `cargo workspace-lints` (verifies every
  workspace package sets `lints.workspace = true`), then emits every
  data format under documentation/rust/cargo_workspace_lints/<ISO>/:
  the native text report, a jaq-parsed findings JSON, and a jaq-derived
  SARIF 2.1.0. Report-only by default; set CWL_STRICT=1 to fail when a
  package misses workspace lints. Self-skips (exit 0) when cargo / the
  subcommand / jaq is missing.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cargo_xss.sh`

- **Purpose:** Drive `cargo xss-testing` against the vl-web crate.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cargo_xss.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Installs cargo-xss-testing on demand (best-effort), runs it against
  the workspace crate `vl-web`, and asserts zero findings. Writes a log
  plus a Markdown report under documentation/xss/<ISO>/. Skips cleanly
  (exit 0 with a WARN) when the optional tool is absent; set
  XSS_REQUIRE=1 to hard-fail when the tool is missing instead.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cats.sh`

- **Purpose:** Fuzz the live OpenAPI contract with cats (Endava) and derive a SARIF report.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cats.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Opt-in DAST gate that runs cats (the Endava OpenAPI fuzzer) against the
  live vl-web contract, complementing schemathesis with negative / boundary
  mutation matrices. Probes the server health endpoint, fetches
  ${BASE}/openapi.json, runs cats bounded by CATS_MAX wall-clock seconds,
  then derives a validated SARIF 2.1.0 from the cats report with jaq.
  Reports land under documentation/api/cats/<ISO>/. Self-skips cleanly
  (rc 0) when cats is absent, the server health endpoint is unreachable, or
  the OpenAPI contract is unavailable. FAILs (rc 1) on any error-severity
  result; warn-severity is non-fatal unless CATS_FAIL_ON_WARN=1.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cert_dump.sh`

- **Purpose:** test_cert_dump — scan the repo for X.509 certificates with cert-dump
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cert_dump.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  `cert-dump` over the git-tracked repository files (excluding `skills/`
  and `documentation/`), emits text / json / tree / sqlite, synthesises
  SARIF 2.1.0 from the json via jaq, and validates it for SARIF
  compliance.  See the inline comments and the sibling
  `test_cert_dump.bats` for the full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_charybdefs.sh`

- **Purpose:** Inject FUSE filesystem faults under a redb store; assert crash-consistent reopen.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_charybdefs.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE chaos/fault-injection gate. Mounts charybdefs (ScyllaDB's fault-
  injecting FUSE filesystem, https://github.com/scylladb/charybdefs) over a
  scratch backing dir, stages a redb-style store file on the mount, injects an
  errno (EIO) or a bounded op-delay MID-WRITE via the charybdefs thrift/cli
  cookbook, then CLEARS the fault, drops the handle, and REOPENS the store —
  asserting it recovers (open_or_create succeeds, payload integrity intact, no
  corruption). This mirrors the reopen transition the proptest-state-machine
  redb model checks, but forces it through a real faulting filesystem instead
  of an in-process fault. charybdefs is Linux + FUSE only and typically needs
  root; the gate self-skips cleanly (rc 0) when the platform is not Linux OR
  charybdefs / fusermount is absent (the expected state on macOS / any host
  without it). The mount is unmounted and every charybdefs process is killed by
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_code_dupes.sh`

- **Purpose:** Run code-dupes and emit text + JSON + synthesised SARIF 2.1.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_code_dupes.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Drives the code-dupes `report` subcommand across its native text and
  JSON formats, then synthesises SARIF 2.1 from the JSON stream with
  jaq. Scans the Cargo workspace at QG_WORKSPACE by default; per-format
  reports land under documentation/linter/code_dupes/<ISO>/. Report-only
  by default; --strict fails on any duplicate group. Self-skips (exit 0)
  when code-dupes is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_codesearch.sh`

- **Purpose:** Run the codesearch analysis pass and emit every native format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_codesearch.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Drives `codesearch <subcommand>` (default `analyze`) over the Cargo
  workspace at QG_WORKSPACE and emits every documented output format
  (text, csv, markdown, json) under
  documentation/linter/codesearch/<ISO>/. Report-only by default;
  --strict fails when any format reports findings. Self-skips (exit 0)
  when codesearch is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_committed.sh`

- **Purpose:** Lint recent commits with the committed Conventional Commits checker.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_committed.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `committed` over a git range (default origin/main..HEAD, falling
  back to HEAD~5..HEAD) so the downstream cargo-release / changelog
  pipelines can rely on Conventional Commits subject lines. Writes the
  report under documentation/git/committed_<ISO>/. Self-skips (exit 0)
  when `committed` is absent or no usable git range exists.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_creusot.sh`

- **Purpose:** Probe the `creusot` deductive verifier; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_creusot.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  the `creusot` unbounded deductive verifier over the Cargo workspace,
  captures its verdict, derives a schema-validated SARIF 2.1.0 (no native
  SARIF reporter exists), and writes reports under documentation/rust/creusot/.
  Analysis-only + idempotent; report-only unless CREUSOT_STRICT=1.  Self-skips
  (rc 0) when the verifier is absent.  See the sibling test_creusot.bats.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_csaf_ndaal.sh`

- **Purpose:** Validate, import, and check availability of the ndaal CSAF 2.1 feed.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_csaf_ndaal.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  End-to-end check of the ndaal CSAF 2.1 advisories under csaf/: file
  existence, JSON syntax, CSAF 2.1 required fields, provider metadata,
  optional gocsaf schema validation, GitLab raw-feed availability, and
  import into a running vl-web server. Prints a pass/fail summary and
  exits non-zero when any assertion fails.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_css_with_stylelint.sh`

- **Purpose:** Run stylelint over in-scope *.css/*.scss/*.less; emit all formats +
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_css_with_stylelint.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `stylelint` over every *.css / *.scss / *.less file in the repo
  EXCEPT .git/, skills/, documentation/, and nuclei-templates/, emits a
  human `string` report plus a normalised JSON findings list and a
  jaq-derived, schema-validated SARIF 2.1.0 (stylelint has no native SARIF
  reporter) under documentation/css/stylelint/, and documents what
  `stylelint --fix` would do by running it on COPIES (the repo is never
  mutated, so the gate is idempotent AND non-destructive).  Report-only by
  default; STYLELINT_STRICT=1 fails on any error-severity finding.
  Self-skips (exit 0) when `stylelint` is not on PATH.  See the sibling
  `test_css_with_stylelint.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_cve_api_probe.sh`

- **Purpose:** Probe the vl-web CVE API over HTTP/2 and HTTP/3 and compare.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_cve_api_probe.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Shrinks a cvelistV5 CSV to a deterministic stride sample, then
  probes the running vl-web API twice per CVE, once over HTTP/2 on
  the TCP listener and once over HTTP/3 on the QUIC listener. Records
  which CVEs are present and whether the two transports agree on the
  returned vuln_id, emitting sample.csv, http2.ndjson, http3.ndjson
  and a Markdown comparison report under REPORT_DIR.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_dashboard_entry_titles.sh`

- **Purpose:** Exhaustive dashboard entry-title integrity check: for EVERY vendor
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_dashboard_entry_titles.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Enumerates every slug in VENDOR_SPECS (crates/vl-web/.../vendor_dashboard.rs)
  and, against the running vl-web, GETs /api/v1/vendor/<slug>/recent (which
  returns `{ "rows": [ { "title": "...", ... } ] }` — the title the dashboard
  actually renders, derived with fallbacks). For each dashboard that shows
  >= 1 row, every row's `title` must be a present, non-whitespace string.
  Dashboards with 0 rows are reported but not failed (no data yet != a bug).
  A TSV matrix lands under documentation/dashboard_titles/<ISO>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_dashboard_field_distinctness.sh`

- **Purpose:** Exhaustive dashboard field-distinctness check: for EVERY vendor
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_dashboard_field_distinctness.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Enumerates every slug in VENDOR_SPECS and, against the running vl-web,
  verifies for each dashboard:
    1. API:    GET /api/v1/vendor/<slug>/recent — for every row the rendered
               `title` must NOT equal the `short_id` (the CVE / advisory id).
               A title that equals the id means the description fallback was
               empty and the recent table is showing the bare id.
    2. GUI:    GET /dashboards/<slug> returns 200 and mounts the recent list
               (the same rows the API serves).
    3. Detail: GET /dashboards/<slug>/<short_id> for the first row — the page
               title, the description text and the cve_id must be three
               distinct values (no two identical).
  Dashboards with 0 rows are reported but not failed (no data yet != a bug).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_debtmap.sh`

- **Purpose:** debtmap code-complexity/technical-debt gate (json/markdown/terminal/dot + jaq-synthesised SARIF).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_debtmap.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  debtmap (https://github.com/spechtx/debtmap) analyses a whole directory
  tree in one process (unlike pylyzer) but has NO native SARIF output and
  NO autofix capability — both confirmed empirically against the
  installed binary (see attempt_autofix() below).  debtmap's `[ignore]`
  config section is honoured ONLY via a `.debtmap.toml` auto-discovered
  relative to the process's current working directory — `--config <path>`
  does NOT forward the ignore patterns (confirmed empirically) — so this
  gate temporarily writes a hermetic `.debtmap.toml` into the scan
  target, `cd`s there to run debtmap, and ALWAYS restores the target to
  its original state via the ndaal_cleanup EXIT trap, even on a signal or
  errexit-triggered exit.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_deductive_verification.sh`

- **Purpose:** Probe deductive-verification / refinement-type provers over the workspace.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_deductive_verification.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  One LIVE gate that PROBES four unbounded deductive verifiers — creusot,
  prusti, verus and flux. Unlike kani (bounded model checking) these prove
  properties UNBOUNDED via SMT / Why3 / Viper. For each tool present on PATH
  the gate runs its check over the vulnerability-lookup-rs workspace, bounded
  by DEDUCTIVE_VERIFICATION_TIMEOUT wall-clock seconds, and archives the
  per-tool log under documentation/rust/deductive_verification/<ISO>/<tool>/.
  A tool that is absent is noted as skipped. When ALL four tools are absent
  the whole gate self-skips cleanly (rc 0) — the expected state until a
  verification toolchain is installed. A combined SUMMARY plus a
  jaq-synthesised, schema-validated SARIF 2.1.0 aggregate any findings.
  Analysis-only: this gate NEVER adds #[requires]/#[ensures]/verus!
  annotations to the real crates. Report-only unless
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_dei.sh`

- **Purpose:** Run the dei god-class / architecture linter and synthesise SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_dei.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Drives dei check and dei arch over the Cargo workspace, emitting
  every native dei format (text, json) plus a SARIF 2.1 document
  synthesised from the JSON with jaq. Writes per-format reports and a
  SUMMARY rollup under documentation/linter/dei/dei_<TIMESTAMP>/.
  Skips cleanly when dei is absent and gates on findings with --strict.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_devguard.sh`

- **Purpose:** Run the devguard code / git-health linter across all output formats.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_devguard.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Drives `devguard check` and `devguard git health` over the repo,
  running all four output formats (human, json, markdown, sarif) in
  parallel per subcommand and writing one report each under
  documentation/git/. Skips cleanly when devguard is absent and exits
  with the worst format rc when --fail-on trips.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_dm_crash_consistency.sh`

- **Purpose:** Device-mapper crash-consistency chaos gate (dm-log-writes / dm-flakey) for redb.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_dm_crash_consistency.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE fault-injection gate. On Linux + root, layers a device-mapper
  crash-consistency target (dm-log-writes, which journals every block
  write so the volume can be replayed to any checkpoint, or dm-flakey,
  which intermittently drops/corrupts writes) over a loop-backed
  sparse volume, runs a redb write workload against the mounted
  filesystem, marks checkpoints, then either replays to a checkpoint
  (log-writes) or forces torn writes (flakey) and asserts redb opens
  consistently. Report-only by default; DM_CRASH_CONSISTENCY_STRICT=1
  makes an observed inconsistency, corruption, or OOM fatal. Self-skips
  cleanly (rc=0) on any non-Linux host, when not root, or when
  dmsetup / losetup are absent — the expected result off a Linux box.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_doc_drift.sh`

- **Purpose:** test_doc_drift — doc-drift markdown/source drift gate (SARIF 2.1.0).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_doc_drift.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  doc-drift (https://crates.io/crates/doc-drift) catches when the markdown
  docs drift from the Rust source — undocumented public items, missing
  derive attributes, missing fields, thin docs.  This gate runs doc-drift in
  every form it offers (human + json), derives a validated SARIF 2.1.0
  report (one result per diagnostic, excluding any under skills/ or
  documentation/), and documents that doc-drift exposes no autofix (the
  before/after snapshots are identical by construction).  It is
  report-only: it never fails CI, self-skips (rc 0) when doc-drift or the
  project's `doc-drift.toml` config is missing, and otherwise exits 0.  See
  the sibling `test_doc_drift.bats` for the full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_dokono_rs.sh`

- **Purpose:** test_dokono_rs — informational dokono-rs change-impact reporting gate.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_dokono_rs.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  dokono-rs (https://crates.io/crates/dokono-rs, binary `dokono`) answers
  "given this change, which binary entrypoints are affected?" by driving
  rust-analyzer over LSP — it never invokes `cargo build`.  It is a
  change-impact reporter, NOT a linter: it has no findings-severity and no
  autofix.  This gate runs it across the diff between two git refs (default
  `main`..`HEAD`), records the result in every form dokono offers (text +
  json), derives a validated SARIF 2.1.0 note report (one note per affected
  entrypoint), and documents that dokono exposes no autofix (before == after).
  The gate never fails CI: it self-skips (rc 0) when dokono or rust-analyzer
  is missing and otherwise exits 0.  See the sibling `test_dokono_rs.bats`
  for the full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_dump_import_feed_cycle.sh`

- **Purpose:** End-to-end dump -> import -> live-feed cycle test for vl-cli / vl-web.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_dump_import_feed_cycle.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Clears the database, imports the fetched CIRCL NDJSON dumps, verifies
  the imported count against the dump line counts, then starts vl-web
  with feeders enabled and waits to confirm the feeders grow the store.
  Prints a pass/fail summary and exits non-zero on any failed check.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_enrichment_api.sh`

- **Purpose:** Smoke-test the vl-web enrichment API endpoints and UI pages.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_enrichment_api.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Exercises the CVSS, EPSS/KEV, CWE, CAPEC, GCVE and HATEOAS-link
  enrichment endpoints (plus core UI pages) against a running server
  at BASE, checking extracted field values and HTTP status codes for a
  fixed set of CVEs. Prints a pass/fail tally and exits non-zero on any
  failure.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_epss_history_dashboard.sh`

- **Purpose:** Live contract for the EPSS History + Old-vs-New dashboards.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_epss_history_dashboard.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Curls the two dashboard pages and their JSON endpoints on a running
  server (https://localhost:8080): pages + positive APIs must return 200
  with exact HATEOAS links; the negative guards must return the exact
  400/404 (never a 5xx); the download endpoint must set an attachment.
  See the sibling `test_epss_history_dashboard.bats` for the structural
  contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_feroxbuster.sh`

- **Purpose:** Run a feroxbuster content-discovery sweep and emit multi-format reports.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_feroxbuster.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Resolves the default ports from vl-core's config, a SecLists wordlist
  (env override, local cache, shallow clone, or inline fallback), and an
  optional mitmdump TLS-terminating proxy, then runs feroxbuster against
  each target. Converts the NDJSON output to pretty JSON, CSV, Markdown,
  HTML and a validated SARIF 2.1.0 document under
  documentation/vulnerabilities/feroxbuster/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_ffuf.sh`

- **Purpose:** Run an ffuf content-discovery sweep and emit SARIF 2.1.0 reports.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_ffuf.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Vendors the SecLists wordlist, fuzzes each configured target with
  ffuf, writes every native ffuf format (`-of all`), then derives and
  validates a SARIF 2.1.0 report per target via jaq. Targets, wordlist,
  thread count, and maxtime are all overridable through FFUF_*
  environment variables; results land in a timestamped output dir with
  a SUMMARY.md rollup.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_flux.sh`

- **Purpose:** Probe the `flux` deductive verifier; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_flux.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  the `flux` unbounded deductive verifier over the Cargo workspace,
  captures its verdict, derives a schema-validated SARIF 2.1.0 (no native
  SARIF reporter exists), and writes reports under documentation/rust/flux/.
  Analysis-only + idempotent; report-only unless FLUX_STRICT=1.  Self-skips
  (rc 0) when the verifier is absent.  See the sibling test_flux.bats.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_foxguard.sh`

- **Purpose:** Run the foxguard security scanner and emit every output format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_foxguard.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Wraps foxguard (a local security scanner with 170+ rules across 11
  languages plus a Cryptography Bill of Materials emitter) and writes
  each documented format — terminal, json, sarif, cbom — plus a
  SUMMARY.txt rollup under documentation/linter/foxguard/. Defaults to
  scanning first-party Rust crates; --strict turns findings into a
  non-zero exit for CI gating.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_fuzzing_targets.sh`

- **Purpose:** Run every cargo-fuzz target across the workspace and report findings.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_fuzzing_targets.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Enumerates the cargo-fuzz targets under crates/*/fuzz and the
  workspace-root fuzz/, runs each for a configurable duration,
  classifies every outcome (OK / CRASH / BUILD_FAIL / TIMEOUT), and
  writes a human summary, a results TSV, and a SARIF 2.1.0 report per
  run under documentation/rust/fuzzing/. The exit status mirrors the
  crash count so CI can gate on it.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_ghsa_cve_linking.sh`

- **Purpose:** Smoke-test GHSA-to-CVE linking across the API and UI routes.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_ghsa_cve_linking.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Exercises the running vl-web server for known GHSA/CVE pairs: an
  advisory without a CVE must 404, advisories with a CVE must resolve
  via both the API and the UI plus their enrichment and CVSS endpoints,
  and the core UI pages must load. Tallies pass/fail counts and exits
  non-zero on any failure.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_gitleaks.sh`

- **Purpose:** Scan the working tree for hard-coded secrets with gitleaks.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_gitleaks.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs two gitleaks passes over the working tree (never the .git
  history): one with the repo's own .gitleaks.toml + .gitleaksignore,
  and one with the canonical ndaal base ruleset fetched per run. Each
  pass emits json, csv, junit, and sarif reports plus a SUMMARY.md
  under documentation/secrets/gitleaks/. Self-skips cleanly when the
  gitleaks binary is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_goose.sh`

- **Purpose:** Goose load-test runner for the standalone loadtest crate.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_goose.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the vulnerability-lookup-rs quality-gate suite under `tests/scripts/`.
  See the inline comments below and the sibling `test_goose.bats` for the
  full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_h3spec.sh`

- **Purpose:** HTTP/3 + QUIC protocol-conformance gate — h3spec against the LOCAL QUIC listener, plus an optional h2load availability sample; all-format reports + jaq-derived SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_h3spec.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE, LOOPBACK-ONLY conformance gate for the QUIC / HTTP-3 listener on
  `VL_PORT_H3`.  That listener currently has NO protocol-conformance coverage
  at all: `h2spec` and `slowhttptest` in `test_protocol_abuse.sh` only drive
  the TCP listener on `VL_PORT_H2`, so every QUIC transport rule and every
  HTTP/3 frame rule is untested.

  Two upstream tools drive that surface:

    * h3spec (<https://github.com/summerwind/h3spec>) — an HTTP/3 and QUIC
      protocol conformance suite.  It is the primary driver: one case per
      MUST / MUST-NOT rule, each reported as OK, FAIL, or SKIP.
    * h2load — an OPTIONAL, small, bounded HTTP/3 availability sample.  It is
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_hateoas_compliance_vulnlookup.sh`

- **Purpose:** Verify HAL / HATEOAS compliance of the vulnerability API and UI.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_hateoas_compliance_vulnlookup.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Exercises the running vl-web server against the HAL specification
  (draft-kelly-json-hal-08) and RFC 8288 web linking: checks for
  _links objects, href formats, self links, relation types, link
  navigation, pagination metadata, content types, POST and error
  response shapes, and cross-resource discoverability. Tallies
  pass / fail / skip and exits non-zero on any failure.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_hotspots_cli.sh`

- **Purpose:** hotspots-cli Local Risk Score static-analysis gate (all 5 formats).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_hotspots_cli.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `hotspots analyze` over the Rust tree and emits all five native
  formats (text/json/html/jsonl/sarif), defensively re-validates the
  SARIF as genuine 2.1.0 (with a jaq fallback if it ever regresses),
  and runs a `hotspots diff` before/after risk-delta comparison. The
  tool is read-only — it has no autofix. Every call is bounded by a
  timeout; a hit is a per-artefact SKIP, not a gate failure.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_html.sh`

- **Purpose:** Lint HTML assets with htmlhint, oxlint, and fta in every format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_html.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Discovers first-party `.html` files, extracts their inline <script>
  blocks into a JS fixture, then runs htmlhint (8 formats), oxlint
  (10 formats), and fta (3 formats), writing per-tool timestamped
  reports under documentation/html/<tool>/<ISO>/. Findings are reported
  but the gate exits 0 unless --strict is given.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_html_with_htmlhint.sh`

- **Purpose:** Run htmlhint over in-scope *.html; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_html_with_htmlhint.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `htmlhint` over every *.html file in the repo EXCEPT skills/ and
  documentation/, emits the offender list / native JSON / compact / unix /
  jaq-derived SARIF 2.1.0 formats under documentation/html/htmlhint/, and
  validates the SARIF via skills/sarif.  htmlhint is a LINTER ONLY (it
  cannot fix), so the autofix slot is a NOT_APPLICABLE note; the repo is
  never mutated, so the gate is idempotent.  Report-only by default;
  HTMLHINT_STRICT=1 fails on any message.  Emits empty-but-valid reports and
  exits 0 when zero in-scope *.html files exist.  See the sibling
  `test_html_with_htmlhint.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_html_with_vnu.sh`

- **Purpose:** Run vnu (W3C Nu Html Checker) over in-scope *.html/*.htm; emit all
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_html_with_vnu.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `vnu` over every *.html / *.htm file in the repo EXCEPT .git/,
  skills/, documentation/, and nuclei-templates/, emits a human report plus
  a normalised JSON findings list and a jaq-derived, schema-validated
  SARIF 2.1.0 (vnu has no native SARIF reporter) under
  documentation/html/vnu/, and records that autofix is NOT_APPLICABLE (vnu
  validates, it does not rewrite).  The repo is never mutated, so the gate
  is idempotent.  Report-only by default; VNU_STRICT=1 fails on any
  error-type finding.  Self-skips (exit 0) when neither a `vnu` binary nor
  a `vnu.jar` + `java` runtime is available.  See the sibling
  `test_html_with_vnu.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_http_garden.sh`

- **Purpose:** Differential HTTP-parsing gate — http-garden / t-reqs against the
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_http_garden.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE, LOOPBACK-ONLY gate for the request-smuggling / HTTP-desync class that
  neither schemathesis nor OWASP ZAP models.  nvulnlookup can sit behind a
  reverse proxy (HAProxy) in front of hyper; a PARSING DIFFERENTIAL between
  the two front ends is exactly the primitive an attacker turns into request
  smuggling.  Two upstream differential fuzzers drive that surface:

    * http-garden (<https://github.com/narfindustries/http-garden>) — feeds one
      crafted request to MULTIPLE HTTP implementations and reports every point
      where their parses DISAGREE.
    * t-reqs (<https://github.com/bahruzjabiyev/t-reqs>) — a grammar-based HTTP
      request-smuggling fuzzer.

```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_interactsh.sh`

- **Purpose:** Out-of-band (blind SSRF) egress gate — interactsh-client against the LOCAL vl-web listener; all-format reports + jaq-derived SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_interactsh.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE, LOOPBACK-ONLY gate for the BLIND / out-of-band vulnerability class.
  interactsh (<https://github.com/projectdiscovery/interactsh>) allocates a
  unique callback domain and reports every DNS / HTTP / SMTP interaction that
  reaches it.  That callback is the only way to observe a request that returns
  NO response body: a blind SSRF in the feeder or enrichment path is invisible
  to schemathesis, ZAP, nuclei and every unit test, because the vulnerable code
  never echoes anything back.

  This gate is the LIVE counterpart of the in-tree host_guard egress suite:
  host_guard proves the guard REJECTS metadata / RFC1918 / link-local targets
  at the API boundary; interactsh proves that nothing in the running feeder or
  enrichment path silently reaches the INTERNET out-of-band anyway.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_javascript_typescript_with_biome.sh`

- **Purpose:** Run biome over in-scope JS/TS; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_javascript_typescript_with_biome.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `biome lint` over every JavaScript / TypeScript file in the repo
  (*.js/*.ts/*.jsx/*.tsx/*.mjs/*.cjs) EXCEPT skills/ and documentation/,
  emits the list / native JSON / github / junit / SARIF 2.1.0 formats
  under documentation/javascript_typescript/biome/, validates the SARIF
  via skills/sarif, and documents what `biome check --write` autofix would
  do on COPIES (the repo is never mutated, so the gate is idempotent).
  Report-only by default; BIOME_STRICT=1 fails on any diagnostic.  Emits
  empty-but-valid reports and exits 0 when zero in-scope JS/TS files exist.
  See the sibling `test_javascript_typescript_with_biome.bats` for the
  full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_javascript_typescript_with_markuplint.sh`

- **Purpose:** Run markuplint over in-scope *.html; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_javascript_typescript_with_markuplint.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `markuplint` over every *.html file in the repo EXCEPT skills/,
  documentation/, and nuclei-templates/, emits Standard / Simple / GitHub /
  JSON formats plus a jaq-derived, schema-validated SARIF 2.1.0 (markuplint
  has no native SARIF reporter) under documentation/html/markuplint/, and
  documents what `--fix` autofix would do on COPIES (the repo is never
  mutated, so the gate is idempotent).  Report-only by default;
  MARKUPLINT_STRICT=1 fails on any finding.  See the sibling
  `test_javascript_typescript_with_markuplint.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_javascript_typescript_with_oxlint.sh`

- **Purpose:** Run oxlint over in-scope JS/TS; emit txt/json + native SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_javascript_typescript_with_oxlint.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `oxlint` over every *.js / *.ts / *.jsx / *.tsx / *.mjs / *.cjs
  file in the repo EXCEPT skills/ and documentation/, emits the human
  (default), JSON, and SARIF 2.1.0 formats under
  documentation/javascript_typescript/oxlint/, prefers oxlint's NATIVE
  `--format=sarif` SARIF (falling back to a jaq-derived 2.1.0 doc), then
  validates it via skills/sarif and documents what `--fix` autofix would
  do on COPIES (the repo is never mutated, so the gate is idempotent).
  Report-only by default; OXLINT_STRICT=1 fails on any diagnostic.  See
  the sibling `test_javascript_typescript_with_oxlint.bats` for the full
  contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_jonesy.sh`

- **Purpose:** jonesy panic-point analysis gate for compiled Rust binaries.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_jonesy.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Discovers debug (unstripped) Rust binaries under JONESY_SCAN_ROOT and
  runs jonesy over each, emitting every documented format (text/json/
  html) plus a jaq-synthesised, structurally validated SARIF 2.1.0 (one
  result per panic point). Read-only: jonesy has no autofix. Self-skips
  (rc=0) when jonesy, jaq, or a debug binary is absent.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_kardo.sh`

- **Purpose:** kardo AI-readiness score gate for the git project.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_kardo.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs kardo at the repository root, emitting every native format
  (summary/detailed/json/badge/hook-summary) plus a jaq-synthesised
  SARIF 2.1 mapped from the JSON `.issues[]`. Informational by default;
  --strict fails on any reported issue. Self-skips (rc=0) when kardo is
  not installed.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_katana.sh`

- **Purpose:** Route-discovery gate — katana crawls the LOCAL vl-web listener and reports OpenAPI drift; all-format reports + jaq-derived SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_katana.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE, LOOPBACK-ONLY crawl gate built on katana
  (<https://github.com/projectdiscovery/katana>).

  Every other DAST gate in this repository — nuclei, ffuf, ZAP, schemathesis —
  is only ever as good as the URL list it is handed.  That list is normally
  derived from `specs/openapi.yaml` or from a template pack, so a route that
  EXISTS but is documented nowhere is invisible to all of them.  katana
  derives the list from the RUNNING application instead, which makes its most
  valuable output here the DRIFT signal: routes katana reaches that the
  OpenAPI specification does not describe.

  Classification:
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_kryptonclaw.sh`

- **Purpose:** test_kryptonclaw — scan the repo for CI/CD security issues with
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_kryptonclaw.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  `kryptonclaw scan` over a staging tree of the git-tracked files
  (excluding `.git/`, `skills/`, `documentation/`), emits text/json plus a
  native SARIF 2.1.0 (URIs made repo-relative + results sorted for
  idempotency), and validates the SARIF.  See the inline comments and the
  sibling `test_kryptonclaw.bats` for the full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_leaktor.sh`

- **Purpose:** leaktor secret-scanning gate — local + ndaal-base two-pass sweep.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_leaktor.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs the leaktor secret scanner twice over the working tree: once
  with the repo's committed `.leaktor.toml`, once with the fetched
  ndaal gitleaks base ruleset, emitting json/sarif/html per pass and a
  SUMMARY.md with the SARIF finding counts. Self-skips (rc=0) when
  leaktor is missing or the repo uses the reftable git layout.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_libfiu.sh`

- **Purpose:** Chaos/fault-injection gate — libc/syscall faults via libfiu fiu-run.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_libfiu.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE chaos gate: wraps a built repo binary (vl-cli by default, else
  vl-web) under libfiu's `fiu-run -x -c "enable_random name=<class>,..."`
  (LD_PRELOAD) so that open / read / write / close / malloc calls fail
  at random, then asserts the binary reports a clean error instead of
  crashing.  A segfault (SIGSEGV / rc 139), an abort (SIGABRT / rc 134),
  an AddressSanitizer report, or an unbounded hang under injection is the
  finding.  A merely non-zero-but-clean exit is the expected, good result.
  Enumerates a few failure-point classes (posix/io/oc/*, posix/io/rw/*,
  libc/mm/*).  Self-skips (exit 0) when the platform is not Linux, when
  fiu-run / jaq is absent, or when no built binary exists under target/.
  Report-only unless LIBFIU_STRICT=1.  Archives per-class stderr + a
  human summary + a jaq-synthesised, schema-validated SARIF 2.1.0 report
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_lineguard.sh`

- **Purpose:** lineguard line-ending / trailing-space / final-newline gate.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_lineguard.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs lineguard over a target tree in every format (human/json/github
  plus a jaq-derived SARIF 2.1.0) under a timestamped output dir. Phase
  1 is a report-only `--dry-run` (the source of every report + count);
  phase 2 runs `--fix`. Report-only by default (exit 0); set
  LINEGUARD_STRICT=1 to fail on issues. Self-skips when lineguard or the
  target is absent.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_linthis.sh`

- **Purpose:** Run the `linthis` linter over the workspace, emitting every format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_linthis.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `linthis lint` in human, JSON, and github-actions formats, then
  derives a SARIF 2.1.0 report from the JSON via jaq, and writes a
  per-format SUMMARY.txt under documentation/linter/linthis/<ISO-8601>/.
  Report-only by default (exit 0); LINTHIS_STRICT=1 fails on any issue.
  Self-skips cleanly when `linthis` is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_lintscout.sh`

- **Purpose:** Sweep the repository with `lintscout` and emit every output format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_lintscout.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs the lintscout linter-ignore-directive detector across the repo in
  text, JSON, count, and SARIF 2.1.0 formats, writing per-format reports
  plus a SUMMARY.txt under documentation/linter/lintscout/<TIMESTAMP>/.
  Report-only by default (exit 0); --strict fails on any finding, and the
  gate self-skips cleanly when `lintscout` is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_live_feed_cycle.sh`

- **Purpose:** End-to-end live feed-cycle smoke test against a running vl-web server.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_live_feed_cycle.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Drives the running server over HTTP to verify a feed cycle preserves
  data: checks health, records baseline counts, waits for async work,
  re-counts to confirm no loss, then exercises the /recent, detail,
  search, and JSON API routes for a set of known CVEs. Prints a PASS/FAIL
  summary and exits non-zero when any check fails.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_lonkero_scan.sh`

- **Purpose:** Run the `lonkero` AI-driven DAST scanner against the vl-web listeners.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_lonkero_scan.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Pre-flights lonkero, curl, and a reachable Ollama model, optionally
  launches vl-web, then for every target runs an AI auto-mode pentest pass
  followed by a maximum-coverage scan in each documented output format
  (pdf, html, json, xlsx, csv, sarif, markdown) under
  documentation/vulnerabilities/lonkero/. Writes a SUMMARY.md and exits
  non-zero when any sub-task fails.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_loom.sh`

- **Purpose:** Run the loom permutation tests for the workspace concurrency models.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_loom.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Builds the standalone loom-harness crate with RUSTFLAGS="--cfg loom" so
  loom's instrumented Arc/Mutex/Atomics replace the real ones, then runs its
  models under --release to exhaustively explore the workspace's shared-memory
  interleavings (the DbPool Arc<Mutex<Connection>> checkout, the csaf
  Semaphore, and the FEEDER_STOP AtomicBool shutdown latch).  `--cfg loom` is
  a GLOBAL rustc flag that breaks vl-web's tokio/hyper tree, so the models
  live in loom-harness (its own [workspace]) — never in the vl-* crates.
  A LIVE / --full-only gate: self-skips (exit 0) when cargo or rustc is
  missing, and reports a loom failure via a WARN line plus test.log rather
  than a non-zero exit.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_mimetype_cli.sh`

- **Purpose:** Detect MIME / file types of shipped binaries with `mimetype-cli`.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_mimetype_cli.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs mimetype-cli recursively over the release tree, emitting every
  documented format — txt, markdown, json, and native SARIF 2.1.0 — under
  documentation/security/binary/mimetype_cli/<TIMESTAMP>/, validating the
  JSON and SARIF outputs via jaq, and writing a per-format SUMMARY.txt.
  Report-only by default (exit 0); --strict fails on any format failure,
  and the gate self-skips cleanly when `mimetype-cli` is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_mirai.sh`

- **Purpose:** Run MIRAI (endorlabs) abstract-interpretation taint analysis over the workspace.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_mirai.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE analysis-only gate that runs `cargo mirai` (Meta/endorlabs MIRAI, a
  nightly-toolchain abstract interpreter) over the whole workspace to trace
  tag propagation from untrusted sources (feeder network downloads, archive
  entries) to dangerous sinks. Captures the native --message-format json
  diagnostic stream, renders a human summary, then derives a validated
  SARIF 2.1.0 from the diagnostics with jaq (one result per MIRAI warning;
  an empty-but-valid run when there are none). Reports land under
  documentation/rust/mirai/<ISO>/. Self-skips cleanly (rc 0) when the
  nightly toolchain or the cargo-mirai binary is absent. Report-only by
  default; MIRAI_STRICT=1 promotes any warning/error result to fatal (rc 1).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_miri.sh`

- **Purpose:** Run `cargo +nightly miri test` to detect undefined behaviour.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_miri.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Miri is the rustc UB-detector interpreter.  This gate provisions the
  miri sysroot, runs the test suite for one crate (MIRI_PACKAGE, default
  vl-core), and writes the setup + test logs under
  documentation/rust/soundness/miri_<TIMESTAMP>/.  Self-skips cleanly
  (exit 0) when the nightly toolchain or the miri component is absent.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_mkdlint.sh`

- **Purpose:** Run the mkdlint Markdown style checker across the repo tree.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_mkdlint.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Sweeps every `.md` file with mkdlint, emitting each documented output
  format (text, json, sarif, github) plus a non-destructive
  `--fix-dry-run` pass; `--apply-fixes` additionally writes the fix-mode
  diff back into the tree.  Per-format reports land under
  documentation/markdown/mkdlint/mkdlint_<TIMESTAMP>/.  Self-skips
  (exit 0) when the mkdlint binary is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_ndaal_binsec.sh`

- **Purpose:** Run ndaal-binsec static hardening checks over shipped binaries.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_ndaal_binsec.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Walks every shipped ELF / PE / Mach-O binary under the scan root
  (default QG_WORKSPACE/release, recursively) and runs the ndaal fork of
  binsec, emitting text, JSON, native SARIF 2.1.0 and native Markdown per
  binary plus a jaq-rolled-up SARIF envelope under
  documentation/security/binary/ndaal_binsec/ndaal_binsec_<TIMESTAMP>/.
  Self-skips (exit 0) when binsec, the ndaal fork, or jaq is absent.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_nexcore_downloads_scanner.sh`

- **Purpose:** test_nexcore_downloads_scanner — classify the repo's top-level
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_nexcore_downloads_scanner.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  `nexcore-downloads-scanner` over REPO_ROOT (it classifies the immediate
  children, dropping .git/skills/documentation), emits markdown, parses it
  into JSON, synthesises SARIF 2.1.0 via jaq, sorts the results for
  idempotency, and validates the SARIF.  See the inline comments and the
  sibling `test_nexcore_downloads_scanner.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_nyx_scanner.sh`

- **Purpose:** test_nyx_scanner — scan the repo source with nyx (nyx-scanner) and
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_nyx_scanner.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  `nyx scan` over the repository (honouring .gitignore), emits
  console/json/sarif, drops findings under `.git/`, `skills/`, and
  `documentation/` from the SARIF, sorts the results for idempotency, and
  validates the SARIF for compliance.  See the inline comments and the
  sibling `test_nyx_scanner.bats` for the full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_oasdiff.sh`

- **Purpose:** Diff the live OpenAPI contract against a baseline and flag BREAKING changes.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_oasdiff.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Wire-level counterpart to the cargo-semver-checks gate: cargo-semver-checks
  guards the Rust public API, this guards the HTTP /api surface. Directly
  relevant because vl-updater ships SELF-UPDATES, so a breaking /api change
  between releases must be caught before it reaches a self-updating client.
  Compares a BASELINE OpenAPI spec (OASDIFF_BASE, or the committed snapshot at
  tests/openapi/baseline.json) against the CURRENT ${BASE}/openapi.json fetched
  from the running vl-web via `oasdiff breaking` + `oasdiff changelog`. A
  breaking change is the finding. Reports land under
  documentation/api/oasdiff/<ISO>/ (native oasdiff formats PLUS a jaq-derived,
  validated SARIF 2.1.0). Analysis-only: this gate NEVER mutates the baseline
  or the served contract. Self-skips cleanly (rc 0) when oasdiff is absent, no
  baseline is configured/committed, the server is unreachable, or the current
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_opengrep.sh`

- **Purpose:** Run opengrep SAST across the repo's languages with layered rules.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_opengrep.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Drives opengrep (the OSS semgrep fork) per language, layering pinned,
  cached external semgrep-rule repositories on top of the registry `p/…`
  packs, then scans the discovered targets and writes text, JSON, SARIF,
  and a SUMMARY.md per language under
  documentation/<lang>/opengrep/opengrep_<TIMESTAMP>/.  External rule
  fetches are best-effort and non-fatal.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_pedant.sh`

- **Purpose:** Run the pedant opinionated Rust linter and synthesise SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_pedant.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Drives pedant's `check` subcommand over every *.rs file under the scan
  root (default QG_WORKSPACE), emits each native output format, and
  synthesises SARIF 2.1 from the JSON report with jaq (pedant has no
  native SARIF emitter).  Per-format reports land under
  documentation/rust/pedant/pedant_<TIMESTAMP>/.  Self-skips (exit 0)
  when pedant is not on PATH.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_phylax.sh`

- **Purpose:** test_phylax — scan the repo for threats with phylax and emit every
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_phylax.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  `phylax scan` over the git-tracked repository files (excluding `skills/`
  and `documentation/`), emits text / json / markdown, synthesises SARIF
  2.1.0 from the findings via jaq, and validates it for SARIF compliance.
  See the inline comments and the sibling `test_phylax.bats` for the full
  contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_pip_audit.sh`

- **Purpose:** Run pip-audit over a requirements file and emit every data format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_pip_audit.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Audits a Python requirements file with pip-audit (PyPA's OSV/PyPI-backed
  auditor), emitting columns, JSON, CycloneDX (JSON + XML), Markdown, and a
  jaq-derived SARIF 2.1.0 under documentation/python/pip_audit/<ISO-8601>/.
  Report-only by default (exit 0); PIP_AUDIT_STRICT=1 fails on any vuln.
  Self-skips (exit 0) when pip-audit is missing, no requirements file is
  found, or the OSV/PyPI lookup times out.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_pmat.sh`

- **Purpose:** Run the pmat Technical Debt Grading (TDG) gate over the workspace.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_pmat.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `pmat analyze tdg` against the Cargo workspace (QG_WORKSPACE by
  default), emitting every TDG output format pmat supports and gating
  on the overall letter grade — the run FAILS unless the grade is A or
  A+. Self-skips (rc 0) when pmat is not on PATH. Per-format reports
  plus GRADE.txt / SUMMARY.txt land under documentation/linter/pmat/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_port_scan.sh`

- **Purpose:** Non-invasive listener-surface guard for the nvulnlookup ports.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_port_scan.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Reads the expected TCP/UDP port set from config/generic.json plus
  the Meilisearch default, then runs rustscan (TCP banners), an nmap
  QUIC UDP probe, and an nmap top-ports sweep to detect unexpected or
  missing listeners on 127.0.0.1. Emits per-run SARIF 2.1.0 + markdown
  artefacts under documentation/ports/ and fails on any surprise port.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_port_scan_with_nmap.sh`

- **Purpose:** INVASIVE all-TCP-port + service/version nmap scan of localhost.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_port_scan_with_nmap.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs a single deliberately invasive nmap sweep (-Pn -A -p- -sV
  --version-all -T4) against 127.0.0.1, wrapped in `timeout`, and
  emits raw XML/gnmap plus parsed JSON and SARIF 2.1.0 artefacts under
  documentation/ports/nmap/. An empty open-port set is a valid clean
  result; self-skips (rc 0) when nmap or jaq is missing.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_port_scan_with_rustscan.sh`

- **Purpose:** INVASIVE all-port + service scan of localhost via rustscan.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_port_scan_with_rustscan.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs a single deliberately invasive rustscan sweep of 127.0.0.1 that
  shells out to nmap (-Pn -A -sV --version-all) for the service stage,
  wrapped in `timeout`, and emits raw + parsed JSON and SARIF 2.1.0
  artefacts under documentation/ports/rustscan/. An empty open-port
  set is valid; self-skips (rc 0) when rustscan, nmap, or jaq is missing.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_pqaudit.sh`

- **Purpose:** Run the pqaudit TLS post-quantum readiness audit gate.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_pqaudit.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs pqaudit against a live TLS endpoint (default VL_HOST:VL_PORT)
  and emits every output format the tool documents (json, sarif,
  cbom, human). Self-skips (rc 0) when pqaudit is missing or the
  target is unreachable — the normal state during a `--fast` dev
  loop. Per-format reports land under documentation/tls/pqaudit/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_pqc_tls.sh`

- **Purpose:** Configuration.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_pqc_tls.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  See the inline comments below and the sibling `test_pqc_tls.bats` for the
  full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_promtool.sh`

- **Purpose:** Lint the live vl-web Prometheus metrics exposition with promtool and derive a SARIF report.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_promtool.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  CONDITIONAL observability gate that validates the Prometheus metrics
  exposition served by vl-web with `promtool check metrics` (naming,
  HELP / TYPE consistency, no duplicate series).  The gate first probes the
  server health endpoint, then probes GET ${METRICS_PATH} (default /metrics):
  only when that endpoint returns a well-formed Prometheus exposition does it
  pipe the body through `promtool check metrics` and derive a validated
  SARIF 2.1.0 with jaq.  Reports land under
  documentation/observability/promtool/<ISO>/.  Self-skips cleanly (rc 0) when
  promtool is absent, the server health endpoint is unreachable, or NO
  Prometheus /metrics endpoint is exposed (the likely state today — the gate
  activates automatically once a Prometheus exporter is added).  Report-only
  by default; PROMTOOL_STRICT=1 (or --strict) makes any lint finding fatal
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_proptest.sh`

- **Purpose:** Run the workspace's proptest property-based regression suite.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_proptest.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs every `proptest!` invariant across the Cargo workspace and
  emits four artefacts per run: text (cargo test), json + junit
  (cargo-nextest), and a copy of every proptest-regressions/*.txt
  seed-pin file. Self-skips (rc 0) when cargo is missing or the scan
  root has no Cargo.toml. Reports land under documentation/rust/proptest/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_protocol_abuse.sh`

- **Purpose:** HTTP protocol-abuse DoS gate — h2spec + slowhttptest against vl-web.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_protocol_abuse.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE gate: exercises the running vl-web listener with two protocol-abuse
  DoS classes — HTTP/2 frame handling via h2spec (the rapid-reset
  CVE-2023-44487 / CONTINUATION-flood family lives in the h2 conformance
  surface) and connection-exhaustion via slowhttptest (slowloris slow-header
  + slow-body), asserting the server stays AVAILABLE throughout. Self-skips
  (exit 0) when neither tool is installed or vl-web is unreachable.
  Report-only unless PA_STRICT=1. Archives reports under
  documentation/dos/protocol_abuse_<TIMESTAMP>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_prusti.sh`

- **Purpose:** Probe the `prusti` deductive verifier; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_prusti.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  the `prusti` unbounded deductive verifier over the Cargo workspace,
  captures its verdict, derives a schema-validated SARIF 2.1.0 (no native
  SARIF reporter exists), and writes reports under documentation/rust/prusti/.
  Analysis-only + idempotent; report-only unless PRUSTI_STRICT=1.  Self-skips
  (rc 0) when the verifier is absent.  See the sibling test_prusti.bats.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_pumba.sh`

- **Purpose:** LIVE chaos gate — pumba container fault-injection over the Molecule
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_pumba.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE gate: with the Molecule test containers running on podman, use pumba
  to inject bounded network chaos (netem delay + loss) and a bounded pause
  against ONE target container, while probing the app/health endpoint, then
  assert the role/playbook/app-under-test tolerates the fault (recovers to a
  healthy state after the fault window closes). This is the fault-injection /
  resilience class that a static test can never exercise — it needs a live
  container runtime and a running target.

  SELF-SKIP is the dominant path: exits 0 cleanly when the platform is not
  Linux (pumba netem manipulates the container's `tc` qdisc — Linux only),
  when `pumba` is absent, when no container runtime (podman/docker) is
  present, or when no target container is running. It ALWAYS self-skips on
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_pyscan.sh`

- **Purpose:** Run pyscan over the repo and emit every OSV vulnerability report format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_pyscan.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs the OSV-backed pyscan dependency scanner over the target tree and
  writes the human report, machine JSON, and a jaq-derived SARIF 2.1.0
  under documentation/python/pyscan/<ISO-8601>/. Report-only by default
  (exit 0); set PYSCAN_STRICT=1 to fail when vulns > 0. Self-skips cleanly
  when pyscan is missing, no Python manifest is found, or the OSV lookup
  times out or is offline.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_bandit.sh`

- **Purpose:** Run the Bandit Python security linter and emit every report format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_bandit.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs bandit -r over the repo in every native output format (csv, html,
  json, screen, txt, xml, yaml), synthesises a SARIF 2.1.0 from the json
  report with jaq, and writes a Markdown summary under
  documentation/python/bandit/<ISO-8601>/. Report-only by default; pass
  --strict / BANDIT_STRICT=1 to fail on findings or on a SARIF report that
  fails 2.1.0 validation. Self-skips cleanly when
  bandit is absent.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_codeql.sh`

- **Purpose:** Run CodeQL over the repo's Python and emit a validated SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_codeql.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Builds a CodeQL Python database from ${SCAN_ROOT} (default: the repo
  root) restricted to *.py, excluding .git/, skills/, documentation/ and
  nuclei-templates/ via a code-scanning config, then analyzes it with the
  codeql/python-queries suite. Emits every documented format (native SARIF
  2.1.0 and CSV); if a native 2.1.0 SARIF is unavailable it is synthesised
  from the CSV with jaq. The final SARIF is validated for SARIF compliance
  (skills/sarif) under documentation/python/codeql/. Read-only; a missing
  tool or query pack self-skips (rc 0).

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).

```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_mypy.sh`

- **Purpose:** Run the mypy static type-checker and emit every report format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_mypy.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Type-checks the repo with mypy, emitting text diagnostics, every mypy
  report generator, a parsed JSON view, a jaq-derived SARIF 2.1.0, and a
  Markdown summary under documentation/python/mypy/<ISO-8601>/. Report-only
  by default; pass --strict / MYPY_STRICT=1 to fail on type errors or on a
  SARIF report that fails 2.1.0 validation.
  Self-skips cleanly when mypy is absent.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_opengrep.sh`

- **Purpose:** Run opengrep Python SAST and emit every report format plus SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_opengrep.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Scans *.py files with python-relevant opengrep registry rulesets, emits
  one report per supported output format, guarantees a SARIF 2.1.0 (native
  or jaq-synthesised from the json report), and writes a Markdown summary
  under documentation/python/opengrep/<ISO-8601>/. Report-only by default;
  pass --strict / OPENGREP_PY_STRICT=1 to fail on findings. Self-skips when
  opengrep is absent.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_pip-audit.sh`

- **Purpose:** Run pip-audit over Python dependencies and emit every report format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_pip-audit.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Audits a discovered requirements*.txt (or the current environment) with
  pip-audit in every --format, synthesises a SARIF 2.1.0 from the json
  report with jaq, and writes a Markdown summary under
  documentation/python/pip-audit/<ISO-8601>/. Report-only by default; pass
  --strict / PIP_AUDIT_STRICT=1 to fail on vulnerabilities. Self-skips when
  pip-audit is absent or PyPI is unreachable.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_pylyzer.sh`

- **Purpose:** pylyzer Python static type-check gate (text + json + jaq-synthesised SARIF).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_pylyzer.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  pylyzer (https://github.com/mtshiba/pylyzer) is a Rust-based Python static
  type checker with NO directory/batch mode (one file per invocation, no
  --output-format flag) and NO autofix capability — both confirmed
  empirically against the installed binary (see attempt_autofix() below and
  the sibling `test_python_with_pylyzer.bats`).  This gate therefore
  discovers every `*.py` file itself, drives pylyzer once per file, and
  synthesises every downstream data format (json, SARIF 2.1.0) from the
  parsed diagnostic text with jaq — mirroring the "use all available data
  formats" + "if SARIF 2.1 is not available create it from json with jaq"
  requirements for a tool that natively offers only colored diagnostic text.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_pyre.sh`

- **Purpose:** Run the Pyre static type-checker and emit every report format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_pyre.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Type-checks the repo with a hermetic Pyre configuration, emitting the
  json + text reports, a SARIF 2.1.0 (native or jaq-synthesised from the
  json report), and a Markdown summary under
  documentation/python/pyre/<ISO-8601>/. Report-only by default; pass
  --strict / PYRE_STRICT=1 to fail on type errors. Self-skips cleanly when
  pyre is absent or fails to initialise.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_pyright.sh`

- **Purpose:** Report-only pyright type-check gate (text/JSON/SARIF/Markdown).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_pyright.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs pyright over the repo through a generated in-target config that
  excludes vendored and skills/ trees, then synthesises a SARIF 2.1.0
  report and a Markdown summary alongside the native text and JSON.
  Report-only by default; --strict (or PYRIGHT_STRICT=1) turns any type
  error into a non-zero exit. Self-skips when pyright is not installed.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_pyscan.sh`

- **Purpose:** test_python_with_pyscan — nvulnlookup quality-gate test.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_pyscan.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  See the inline comments below and the sibling `test_python_with_pyscan.bats` for the
  full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_radon.sh`

- **Purpose:** Report-only radon complexity gate (cc/mi/raw/hal + SARIF/Markdown).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_radon.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs radon cyclomatic-complexity, maintainability-index, raw and
  Halstead analyses over the repo in every format radon offers, then
  synthesises a SARIF 2.1.0 report from the cc JSON and a Markdown
  summary. Report-only by default; --strict (or RADON_STRICT=1) fails on
  any block worse than RADON_MAX_RANK. Self-skips when radon is absent.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_ruff.sh`

- **Purpose:** Report-only ruff format + lint gate (every ruff output format).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_ruff.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Auto-formats the repo with `ruff format`, then runs `ruff check` once
  per output format (concise, json, junit, sarif, and the rest),
  guaranteeing a valid SARIF 2.1.0 (native or jaq-synthesised) plus a
  Markdown summary. Report-only by default; --strict (or RUFF_STRICT=1)
  fails on remaining violations. Self-skips when ruff is not installed.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_python_with_vulture.sh`

- **Purpose:** Report-only vulture dead-code gate (text/JSON/SARIF/Markdown).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_python_with_vulture.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs vulture over the repo, captures its native text plus a whitelist,
  parses the text into JSON, and synthesises a SARIF 2.1.0 report and a
  Markdown summary. Excludes vendored and skills/ trees and its own
  report tree. The synthesised SARIF is validated before it is published.
  Report-only by default; --strict (or VULTURE_STRICT=1) fails on any
  finding or an invalid SARIF. Self-skips when vulture is not installed.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_quic_interop.sh`

- **Purpose:** QUIC cross-implementation interop gate — quic-interop-runner against the LOCAL h3 listener; all-format reports + jaq-derived SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_quic_interop.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE, LOOPBACK-ONLY gate for QUIC INTEROPERABILITY.
  Every other protocol gate in this repository drives our own stack against
  itself: our client, our server, one implementation.  That can never reveal
  an interop defect, because both peers share the same bug.  The QUIC Interop
  Runner (<https://github.com/quic-interop/quic-interop-runner>) is the only
  harness that points OTHER implementations — quic-go, quiche, ngtcp2, picoquic,
  msquic, neqo, … — at our listener and asserts on the wire behaviour:
  handshake, version negotiation, retry, 0-RTT, key update, connection
  migration.  Those are exactly the failures a single-stack test cannot see.

  The harness is Docker-based and heavy: every implementation ships as a `qns`
  container image and a single test case can pull multiple GB.  An unguarded
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_radamsa.sh`

- **Purpose:** Mutate the parser corpus fixtures with radamsa and smoke-parse every mutant.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_radamsa.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs radamsa (Aalto's black-box mutation fuzzer) over the repo's parser
  fixtures — the sample CSAF advisory, ~30 CSAF provider-metadata.json docs,
  and the CVE-id line list — generating RADAMSA_COUNT mutants per fixture and
  cheaply smoke-parsing each WITHOUT a Rust build: JSON mutants are parsed
  with jaq under a per-mutant timeout (a hang is a FINDING, a malformed-JSON
  reject is EXPECTED), and the line list is checked for UTF-8 well-formedness
  plus a line-length bound. A per-run summary and a schema-validated SARIF
  2.1.0 report land under documentation/fuzzing/radamsa/<ISO>. radamsa self-
  skips cleanly (rc=0) when absent; jaq + timeout are the report deps. Fails
  (exit 1) only on a parse-timeout/hang finding (or when RADAMSA_STRICT trips).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_ramparts.sh`

- **Purpose:** test_ramparts — scan an MCP server for security issues with ramparts
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_ramparts.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  `ramparts scan <RAMPARTS_TARGET>` against an MCP server, emits
  json/text/table/raw/markdown, synthesises SARIF 2.1.0 from the JSON via
  jaq, and validates it for SARIF compliance.  Self-skips when no target is
  configured.  See the inline comments and the sibling `test_ramparts.bats`
  for the full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_ratchets.sh`

- **Purpose:** Progressive-lint gate driving `ratchets check` in every format.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_ratchets.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `ratchets check` (human + jsonl) from the Cargo workspace, keeping
  each rule's violation count within the budget tracked in ratchets.toml,
  and writes per-format reports plus a SUMMARY.txt. Self-skips with rc=0
  when ratchets is not installed or the project has no committed
  ratchets.toml (it never runs `init`). --strict gates on over-budget rules.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_react_perf_analyzer.sh`

- **Purpose:** test_react_perf_analyzer — nvulnlookup quality-gate test.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_react_perf_analyzer.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  See the inline comments below and the sibling
  `test_react_perf_analyzer.bats` for the full contract this gate
  enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_reproducible_build.sh`

- **Purpose:** Reproducible-build gate — build one binary twice, assert byte-identity.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_reproducible_build.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Supply-chain gate (SLSA build-integrity): builds a designated release
  binary TWICE under a deterministic environment (SOURCE_DATE_EPOCH,
  CARGO_INCREMENTAL=0, --remap-path-prefix, --locked) and compares the two
  artefacts byte-for-byte. Byte-identity is the property that lets an
  independent verifier confirm a published binary corresponds to the
  published source — the layer above cargo-auditable (embedded provenance)
  and cargo-cyclonedx (SBOM). Self-skips (exit 0) when cargo / the crate /
  the hashers are absent. Report-only unless RB_STRICT=1. Archives both
  hashes + a diff summary under documentation/reproducible/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_restler.sh`

- **Purpose:** Stateful REST fuzzing of the running server with Microsoft RESTler.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_restler.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Fetches the live OpenAPI spec from the running vl-web server, compiles a
  RESTler grammar from it, runs a `restler test` smoke pass followed by a
  bounded `restler fuzz-lean`, then parses RESTler's bug buckets and network
  logs. Fails (exit 1) on any reported bug or any 5xx response; derives a
  validated SARIF 2.1.0 with jaq. Complements the stateless schemathesis
  contract gate. LIVE + server-dependent: self-skips cleanly (exit 0) when
  restler is absent, the server is unreachable, or /openapi.json is missing.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_ripr.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_ripr.sh [arguments...]`

#### `vulnerability-lookup-rs/tests/scripts/test_rust_cli_with_assert_cmd.sh`

- **Purpose:** Detect + run the workspace `assert_cmd` CLI harness; emit all formats
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_rust_cli_with_assert_cmd.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  `assert_cmd` is a Rust dev-dependency (a test LIBRARY, not an installable
  CLI), so this gate first DETECTS whether the workspace declares it under
  `[dev-dependencies]` AND whether any in-scope Rust source actually uses it.
  With no harness it self-skips (rc 0), records what is missing plus the
  one-line remediation, and still writes empty-but-valid reports.  With a
  harness it runs `cargo test -p <pkg> --test <harness>` out-of-tree, turns
  every failing test into a normalised finding, derives a schema-validated
  SARIF 2.1.0 from that JSON, and writes everything under
  documentation/rust/assert_cmd/.  assert_cmd has no accept/bless mode, so
  the autofix slot records NOT_APPLICABLE.  Analysis-only + idempotent;
  report-only unless ASSERT_CMD_STRICT=1.  See the sibling
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_rust_cli_with_snapbox.sh`

- **Purpose:** Detect + run the snapbox snapshot harness; emit all formats,
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_rust_cli_with_snapbox.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  snapbox (https://docs.rs/snapbox) is the assertion / snapshot engine that
  sits under trycmd; it is a Rust DEV-DEPENDENCY CRATE, not an installable
  CLI (`cargo install snapbox` fails — no binary target), so this gate never
  probes PATH for it.  Instead it DETECTS the harness (dev-dependency
  declared in a workspace manifest AND a `snapbox::` using test target), then:
  self-skips with rc 0 when no harness exists — printing exactly what is
  missing and the one-line remediation — or runs
  `cargo test -p <pkg> --test <harness>` and normalises the outcome into a
  findings array, a jaq-derived + schema-validated SARIF 2.1.0 document, and
  a NON-DESTRUCTIVE `SNAPSHOTS=overwrite` bless record produced on COPIES so
  the repository's committed snapshots are never rewritten.  Reports land
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_rust_cli_with_trycmd.sh`

- **Purpose:** Drive the trycmd CLI snapshot harness; emit all formats + jaq-derived
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_rust_cli_with_trycmd.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  trycmd
  is a Rust TEST LIBRARY (dev-dependency), not an installable CLI, so this
  gate DETECTS the harness — dev-dependency declared + `trycmd::` referenced
  by a test target + the `--test` target present — and SELF-SKIPS (rc 0) with
  the exact remediation when any piece is missing.  When the harness exists it
  runs `cargo test -p <pkg> --test <harness>`, normalises the failures to
  JSON, derives a schema-validated SARIF 2.1.0 (trycmd emits none), and
  documents what the `TRYCMD=overwrite` bless mode WOULD rewrite by running it
  on a COPY of the tracked workspace — the repository is digest-guarded and
  never mutated.  Reports land under documentation/rust/trycmd/.  Report-only
  by default; TRYCMD_STRICT=1 fails on any failed case.  See the sibling
  `test_rust_cli_with_trycmd.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_rust_doctor.sh`

- **Purpose:** rust-doctor workspace health-score gate (0-100, five pillars).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_rust_doctor.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `rust-doctor .` against the Cargo workspace, first generating LCOV
  coverage so the coverage pillar is populated, then captures the output
  and the extracted 0-100 score under documentation/rust/health/. Runs
  linearly (no main); self-skips when rust-doctor is not installed. The
  /about score MUST match a fresh scan from this gate.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_rust_guardian.sh`

- **Purpose:** Run rust-guardian across every documented output format and roll up findings.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_rust_guardian.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Wraps the rust-guardian code-quality enforcer, scanning the Cargo
  workspace (QG_WORKSPACE) or a `--root` override in each of its six
  documented output formats (human, json, junit, sarif, github, agent).
  The per-format reports plus a SUMMARY.txt land under
  documentation/rust/rust_guardian/rust_guardian_<TIMESTAMP>/. A missing
  tool self-skips (rc 0); findings are informational unless `--strict`.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_rust_meth.sh`

- **Purpose:** test_rust_meth — informational rust-meth method-discovery smoke gate.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_rust_meth.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  rust-meth (https://crates.io/crates/rust-meth) is an interactive
  method-discovery tool: given a Rust TYPE it lists the methods available on
  it (via rust-analyzer).  It is NOT a linter — it has no codebase scan, no
  findings, no native JSON/SARIF, and no autofix.  This gate therefore runs
  an INFORMATIONAL smoke check: it probes a fixed, deterministic list of
  Rust types, records the discovered methods in every form rust-meth offers
  (plain + `--doc`), derives a JSON roll-up and a SARIF 2.1.0 note-level
  report (synthesised with jaq, then validated), and documents that rust-meth
  exposes no autofix (the before/after snapshots are identical by design).
  The gate never fails CI: it self-skips (rc 0) when rust-meth or
  rust-analyzer is missing and otherwise exits 0.  See the sibling
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_rust_with_codeql.sh`

- **Purpose:** Run CodeQL over the repo's Rust and emit a validated SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_rust_with_codeql.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Builds a CodeQL Rust database from ${SCAN_ROOT} (default: the repo
  root) restricted to *.rs, excluding .git/, skills/, documentation/ and
  nuclei-templates/ via a code-scanning config, then analyzes it with the
  codeql/rust-queries suite. Emits every documented format (native SARIF
  2.1.0 and CSV); if a native 2.1.0 SARIF is unavailable it is synthesised
  from the CSV with jaq. The final SARIF is validated for SARIF compliance
  (skills/sarif) under documentation/rust/codeql/. Read-only; a missing
  tool or query pack self-skips (rc 0).

ndaal Bash Boilerplate — strict mode, signal handling, deterministic env.
Designed for Bash >= 4.4 on Linux (Debian 12/13) and macOS (Homebrew Bash).

```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_rust_with_hela.sh`

- **Purpose:** Run the Hela multi-scanner orchestrator and synthesise a validated SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_rust_with_hela.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Wraps Hela (SAST / SCA / secret / license) over `${HELA_TARGET}`
  (default: vulnerability-lookup-rs). secret / license / sca always run
  (they degrade gracefully when unconfigured); sast runs only when semgrep
  is on PATH (Hela panics on `-s` without it). Emits Hela's text + JSON and
  a jaq-synthesised, structurally validated SARIF 2.1.0 under
  documentation/rust/hela/hela_<TIMESTAMP>/. Read-only; a missing tool
  self-skips (rc 0).
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_rustqual.sh`

- **Purpose:** Run rustqual across every documented output format and roll up findings.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_rustqual.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Wraps the rustqual code-quality analyzer (seven dimensions: IOSP,
  Complexity, DRY, SRP, Test Quality, Coupling, Architecture), scanning
  the Cargo workspace (QG_WORKSPACE) or a `--root` override in each of its
  eight documented formats (text, json, github, sarif, html, ai, ai-json,
  dot). Per-format reports plus a SUMMARY.txt land under
  documentation/rust/rustqual/rustqual_<TIMESTAMP>/. A missing tool
  self-skips (rc 0); findings are informational unless `--strict` or
  `--min-quality-score`.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_rustwright.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_rustwright.sh [arguments...]`

#### `vulnerability-lookup-rs/tests/scripts/test_rwalk.sh`

- **Purpose:** test_rwalk — enumerate a web server's surface with rwalk and emit
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_rwalk.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  `rwalk <RWALK_TARGET> <RWALK_WORDLIST>` against a web server, emits
  text/json, synthesises SARIF 2.1.0 from the JSON via jaq, and validates
  it for SARIF compliance.  Self-skips when no target/wordlist is
  configured.  See the inline comments and the sibling `test_rwalk.bats`
  for the full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sanitizers.sh`

- **Purpose:** Run the test suite under ThreadSanitizer + AddressSanitizer.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sanitizers.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Quality gate that runs `cargo +nightly test -Zbuild-std` twice, under
  `-Zsanitizer=thread` and `-Zsanitizer=address`, with
  CFLAGS/CXXFLAGS=-fsanitize=<san> so the aws-lc-sys / aws-lc-rs C+asm
  crypto is instrumented too. This is the only gate that dynamically
  covers the FFI+threading region that is dark to Miri (foreign
  functions) and only modelled — not executed — by Loom. Nightly +
  Linux only; report-only (exit 0) unless SAN_STRICT=1. Archives per-pass
  logs under documentation/rust/soundness/sanitizers_<TIMESTAMP>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sbom_with_bitvex.sh`

- **Purpose:** Run bitvex over an SPDX SBOM + kernel config + device tree; emit every
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sbom_with_bitvex.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  bitvex is an embedded-Linux / Yocto CRA compliance tool: it filters an
  SBOM's CVE list against the target board's actual hardware configuration
  (kernel .config, device tree) and emits OpenVEX JSON-LD and SARIF.  The
  gate discovers bitvex's real output formats from `bitvex --help` at runtime
  (the flags in the fallback come from skills/sbom-bitvex/SKILL.md and are
  UNVERIFIED against a live binary), emits one file per format plus a
  schema-validated SARIF 2.1.0, normalises every volatile field and sorts
  every unordered array so two runs are byte-identical, and writes a
  SUMMARY.txt rollup.  Report-only by default; BITVEX_STRICT=1 fails on a
  missing/empty format or invalid SARIF.  Self-skips (exit 0) when `bitvex`
  is not on PATH OR when the SBOM / kernel config / device tree inputs are
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sbom_with_bomber.sh`

- **Purpose:** Scan an SBOM of this repo with bomber; emit all native formats +
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sbom_with_bomber.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  bomber consumes an SBOM rather than a filesystem, so the gate first
  obtains one (BOMBER_SBOM, else a syft-generated + normalised CycloneDX
  1.5 document over the repo with .git/, skills/, documentation/, and
  nuclei-templates/ excluded), then emits every native bomber output
  (stdout / json / md / html — `ai` is deliberately skipped because it
  calls a third-party LLM) plus a jaq-derived, schema-validated SARIF
  2.1.0 under documentation/sbom/bomber/<ISO-8601>/.  Report content is
  byte-identical between runs; only the run-directory NAME carries the
  timestamp.  Report-only by default; BOMBER_STRICT=1 fails on any
  vulnerability.  Self-skips (exit 0) when `bomber` — or any SBOM input —
  is unavailable.  See the sibling `test_sbom_with_bomber.bats` for the
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sbom_with_bomdrift.sh`

- **Purpose:** Diff two SBOMs with bomdrift and emit the supply-chain drift report in
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sbom_with_bomdrift.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite.  bomdrift is a DIFF tool: it
  compares a BASELINE SBOM against a CURRENT SBOM and reports supply-chain
  risk on the changed components (CVE + EPSS + CISA-KEV, typosquat,
  multi-major version jump, maintainer age / takeover, licence policy).  It
  never walks a source tree, so this gate first OBTAINS two SBOMs — from
  BOMDRIFT_BASELINE / BOMDRIFT_CURRENT when both are set, else from a syft
  scan of BOMDRIFT_ROOT (self-diff => a clean zero-drift baseline), else it
  self-skips.  Every network enricher is disabled so the run is deterministic
  and offline.  Emits one report per `--output` value discovered from
  `bomdrift diff --help`, copies the NATIVE SARIF to drift.sarif, validates it
  through skills/sarif, normalises + sorts every array so two runs are
  byte-identical, proves that with a BEFORE/AFTER diff in the autofix slot
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sbom_with_grype.sh`

- **Purpose:** Run Anchore grype over the in-scope repo tree; emit every advertised
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sbom_with_grype.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Scans a filesystem tree with `grype dir:.` — by default the STAGED
  git-tracked file set (scope `tracked`, EXCLUDING skills/, documentation/
  and nuclei-templates/), or the scan root itself with only .git/ excluded
  (scope `all`).  Emits table / json / cyclonedx / cyclonedx-json / sarif /
  template — the set discovered from `grype --help`, not a hardcoded list —
  into documentation/sbom/grype/<ISO-8601>/, and validates grype's NATIVE
  SARIF against the canonical dual-schema validator.
  Report CONTENT is byte-idempotent (every volatile field pinned); the run
  directory name carries the ISO-8601 stamp and a `latest` symlink tracks the
  newest run.  Report-only by default; GRYPE_STRICT=1 fails on critical/high
  findings, invalid SARIF, a failed or TIMED-OUT scan, or zero usable
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sbom_with_inspektr.sh`

- **Purpose:** Run inspektr over the in-scope repo; emit every native format
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sbom_with_inspektr.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  inspektr is dual-purpose (SBOM generation AND CVE scanning in one binary,
  comparable in scope to syft + grype).  It has no exclude flag, so this
  gate stages a scratch mirror of every in-scope package manifest / lock
  file (excluding .git/, skills/, documentation/, nuclei-templates/,
  .claude/, .vagrant/, target/, node_modules/) and scans that.  Every report
  is normalised AND array-sorted so two runs are byte-identical.
  Report-only by default; INSPEKTR_STRICT=1 fails on findings.  Self-skips
  (exit 0) when the inspektr binary is not on PATH.  See the sibling
  `test_sbom_with_inspektr.bats` for the full contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sbom_with_ort.sh`

- **Purpose:** Run the ORT (OSS Review Toolkit) analyze/advise/report pipeline; emit
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sbom_with_ort.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs ORT (oss-review-toolkit/ort — a Kotlin/JVM compliance pipeline, NOT a
  Rust crate) through Analyzer -> Advisor -> Reporter over the workspace and
  emits every reporter format the installed ORT advertises in
  `ort report --help` plus a jaq-derived, schema-validated SARIF 2.1.0 (ORT
  has no native SARIF reporter — oss-review-toolkit/ort#1029 has been open
  since 2018) under <target>/sbom/ort/<ISO-8601>/.  Reporter outputs are
  classified by CONTENT, never by a hardcoded filename, because ORT's output
  names vary across versions.  Every report is scrubbed of timestamps, UUIDs
  and absolute paths so two runs are BYTE-IDENTICAL.  A `latest` symlink and a
  retention prune keep the report tree bounded.  Report-only by default;
  ORT_STRICT=1 fails on a missing stage/format or invalid SARIF.  Self-skips
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sbom_with_osv_scanner.sh`

- **Purpose:** Run osv-scanner over the repo; emit every natively supported format
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sbom_with_osv_scanner.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `osv-scanner scan source -r` over the repository at the selected
  scan scope (-s/--scope: `tracked`, the default, stages the git-tracked
  files minus skills/, documentation/ and nuclei-templates/ into a private
  scratch tree so the multi-GB target/ and data/ trees are never walked;
  `all` walks everything under the root except .git/ with --no-ignore),
  emits every format the installed osv-scanner advertises in `--help`
  (table / html / vertical / json / markdown / sarif / gh-annotations /
  cyclonedx-1-4..1-7 / spdx-2-3) under
  documentation/sbom/osv_scanner/<ISO-8601>/, validates the NATIVE SARIF
  2.1.0 against skills/sarif/scripts/validate_sarif_schema.sh, and
  normalises every volatile field so two runs produce byte-identical
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sbom_with_provenant.sh`

- **Purpose:** Run provenant (Rust ScanCode port) over the first-party source and emit
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sbom_with_provenant.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite.  Performs ONE `provenant scan`
  with every native output writer attached (the format list is enumerated at
  runtime from `provenant scan --help`, never hardcoded), emits SARIF 2.1.0
  natively when the installed provenant supports `--sarif` and otherwise
  derives it from the JSON with jaq, then schema-validates it via
  skills/sarif/scripts/validate_sarif_schema.sh.  Reports land in an ISO-8601
  named run directory whose CONTENT is byte-identical between runs (volatile
  fields nulled AND every array deterministically sorted).  Report-only by
  default; PROVENANT_STRICT=1 fails on a missing format, an invalid SARIF, or
  a licence-policy violation.  Self-skips (exit 0) when provenant is not on
  PATH.  See the sibling `test_sbom_with_provenant.bats` for the full
  contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sbom_with_shieldbom.sh`

- **Purpose:** Scan an SPDX / CycloneDX SBOM with shieldbom, emitting every supported
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sbom_with_shieldbom.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite.  Resolves an input SBOM
  (SHIELDBOM_SBOM, else a syft-generated CycloneDX JSON of SHIELDBOM_ROOT at
  the selected -s/--scope), normalises it, then runs `shieldbom scan`
  once per output format the installed shieldbom lists in `shieldbom scan
  --help`.  The SARIF is NATIVE (`--format sarif`) and is schema-validated
  against SARIF 2.1.0 (+ 2.2 draft) via
  skills/sarif/scripts/validate_sarif_schema.sh.  Every report is normalised
  (volatile timestamps nulled, arrays sorted, paths made repository-relative)
  so two runs are byte-identical, and that determinism is proved in-run by a
  BEFORE/AFTER re-scan diff in the autofix slot (shieldbom has no --fix).
  Licence-conflict counts are surfaced separately from vulnerability counts.
  Report-only by default; SHIELDBOM_STRICT=1 fails on a missing/empty format,
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sbom_with_tern.sh`

- **Purpose:** Run tern over one container image / Dockerfile; emit every advertised
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sbom_with_tern.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Runs `tern report` (tern-tools/tern, the PYTHON container SCA tool — NOT
  the crates.io `tern` DB-migration crate) against ONE container image or
  Dockerfile and emits EVERY format the installed tern advertises in
  `tern report --help` (2.12.x: spdxtagvalue / spdxjson / cyclonedxjson /
  json / yaml / html) plus tern's default human report and a jaq-derived,
  schema-validated SARIF 2.1.0 (tern has no native SARIF reporter) under
  <target>/sbom/tern/<ISO-8601>/.  Every report is scrubbed of timestamps,
  UUIDs and absolute paths so two runs are BYTE-IDENTICAL.  A `latest`
  symlink and a retention prune keep the report tree bounded.  Report-only
  by default; TERN_STRICT=1 fails on a missing format or invalid SARIF.
  Self-skips (exit 0) when `tern` is not on PATH, when the binary on PATH is
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sbom_with_trivy.sh`

- **Purpose:** Run `trivy filesystem` over the repo; emit all nine native formats +
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sbom_with_trivy.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Scans the repository ONCE with `trivy filesystem --scanners
  vuln,misconfig,secret` (excluding .git/, skills/, documentation/,
  nuclei-templates/, .claude/, .vagrant/, target/, node_modules/) and
  converts that single JSON report into every other format trivy supports —
  table, template, sarif, cyclonedx, spdx, spdx-json, github, cosign-vuln —
  under `<target>/sbom/trivy/<ISO-8601>/`.  The native SARIF is validated
  against the SARIF 2.1.0 schema via `skills/sarif`.  Every volatile field
  (scan timestamps, report UUIDs, SBOM serial numbers, absolute paths) is
  stripped or pinned so two runs are BYTE-IDENTICAL; a `latest` symlink and
  a retention prune keep the report tree usable and bounded.  Report-only by
  default; TRIVY_STRICT=1 fails on any finding.  Self-skips (exit 0) when
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_schemathesis.sh`

- **Purpose:** Fuzz the OpenAPI/HATEOAS contract with schemathesis and derive multi-format reports.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_schemathesis.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs `schemathesis run` against each configured target (default: the
  local TLS + QUIC listeners), streaming events to NDJSON, then derives
  JSON / pretty-JSON / CSV / Markdown / HTML and a validated SARIF 2.1.0
  per target with jaq. Configuration comes from the SCHEMA_* env vars;
  reports land under documentation/api/schemathesis/. Requires
  schemathesis + jaq; targets without a schema are skipped cleanly.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_secrets_with_betterleaks.sh`

- **Purpose:** Shellcheck disable=SC2312 Pedantic-style enforcement (info-level) where the construct is intentional or noisy: see CLAUDE.md "bash…
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_secrets_with_betterleaks.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  See the inline comments below and the sibling `test_secrets_with_betterleaks.bats` for the
  full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_secrets_with_gitleaks.sh`

- **Purpose:** Shellcheck disable=SC2312 Pedantic-style enforcement (info-level) where the construct is intentional or noisy: see CLAUDE.md "bash…
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_secrets_with_gitleaks.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  See the inline comments below and the sibling `test_secrets_with_gitleaks.bats` for the
  full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_secrets_with_leaktor.sh`

- **Purpose:** SCRIPT_PATH + REPO_ROOT are defined as `readonly` anchors above by the canonical ndaal boilerplate (Bash 4.4+).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_secrets_with_leaktor.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  See the inline comments below and the sibling `test_secrets_with_leaktor.bats` for the
  full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_shamefile.sh`

- **Purpose:** Run the read-only `shame me -n` suppression audit and derive JSON + SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_shamefile.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Wraps the shamefile crate's `shame` binary in mandatory dry-run (`-n`)
  mode over `${SHAMEFILE_TARGET}` (default: REPO_ROOT), capturing the
  native text, parsing it into JSON, and synthesising a SARIF 2.1.0 with
  jaq. A TIMESTAMP-stamped Markdown summary is always produced under
  documentation/shamefile/shamefile_<TIMESTAMP>/. Report-only by default;
  a missing tool self-skips (rc 0); findings gate only under `--strict`.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_simdutf8_cli.sh`

- **Purpose:** test_simdutf8_cli — nvulnlookup quality-gate test.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_simdutf8_cli.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  See the inline comments below and the sibling `test_simdutf8_cli.bats` for the
  full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_soak.sh`

- **Purpose:** Endurance/soak gate — detect RSS + fd monotonic growth under load.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_soak.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE gate: samples the running vl-web process's resident memory (RSS) and
  open file-descriptor count at a fixed interval while sustained read-only
  load runs against it, then flags a monotonic upward trend — the
  resource-leak class (the permit/handle leak the 504 incident exposed) that
  only manifests under sustained load with request churn, never in a smoke
  test. Self-skips (exit 0) when vl-web is not running / the tools are
  absent. Report-only unless SOAK_STRICT=1. Archives the sample series +
  verdict under documentation/soak/soak_<TIMESTAMP>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_source_drift.sh`

- **Purpose:** Source "drift" detector — flags per-source data drift against the
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_source_drift.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Reads GET /api/v1/system/info (.storage.db_sizes / .storage.last_updates)
  and compares each source against tests/fixtures/source_drift_baseline.json:
    1. floor       db_sizes[src]    >= baseline.min          (collapse/regress)
    2. freshness   age(last_update) <= baseline.max_age_days (stuck feeder)
    3. collapse    a source with a last_update but <= 1 row is suspicious
  Sources marked "dead": true (e.g. drupal, upstream removed) WARN instead of
  FAIL. A TSV matrix is written under documentation/drift/<ISO>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_source_recent_integrity.sh`

- **Purpose:** Sample recent dashboard entries per source and verify their integrity.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_source_recent_integrity.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  For each dashboard source, samples the most-recent 2026/2025/2024 rows
  and checks that Severity/Published/Title are non-empty, that the
  drill-down round-trips to the stored record with a description, and
  (opt-in) that the CVE alias resolves upstream. Report-only unless
  STRICT=1; skips cleanly when the server at BASE_URL is unreachable.
  Reports land under documentation/source_integrity/. An embedded Python
  harness does the fetch / parse / verify work.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_spectral.sh`

- **Purpose:** Lint the live OpenAPI contract with spectral (Stoplight) + derive SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_spectral.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Opt-in spec-quality gate that runs spectral (the Stoplight OpenAPI /
  AsyncAPI linter) against the live vl-web contract, complementing the cats /
  restler / schemathesis DAST fuzzers with static contract-quality rules
  (missing operation descriptions / tags, undocumented responses, style
  drift).  Probes the server health endpoint, fetches ${BASE}/openapi.json,
  runs `spectral lint <spec> --ruleset <ruleset>` emitting spectral's NATIVE
  SARIF 2.1.0 plus JSON, validates the SARIF (jaq invariants) and keeps a
  jaq-synthesised SARIF as a fallback when the native emitter is unavailable.
  Reports land under documentation/api/spectral/<ISO>/.  Self-skips cleanly
  (rc 0) when spectral is absent, the server health endpoint is unreachable,
  or the OpenAPI contract is unavailable.  Report-only by default; FAILs
  (rc 1) on any error-severity finding only under SPECTRAL_STRICT=1.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sql_query_analyzer.sh`

- **Purpose:** Run sql-query-analyzer over the vl-models schema + sample queries.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sql_query_analyzer.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Concatenates the vl-models migrations into a throwaway schema, then
  fans out `sql-query-analyzer analyze` across four output formats
  (text, json, yaml, sarif) in parallel, writing one timestamped
  report per format under documentation/sql/. Skips cleanly when the
  analyzer binary, schema, or queries file is absent; the worst
  per-format exit code becomes the gate exit status.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sql_with_sqlfluff.sh`

- **Purpose:** test_sql_with_sqlfluff — nvulnlookup SQL-linter quality-gate.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sql_with_sqlfluff.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Lints every first-party `*.sql` file with sqlfluff
  (https://sqlfluff.com), emits every output format the tool documents
  into a FIXED (idempotent) report tree under
  documentation/sql/sqlfluff/before-fix/, guarantees a schema-valid
  SARIF 2.1.0 (native, else synthesised from the json report with jaq),
  then runs `sqlfluff fix` on COPIES of the files (never the real repo)
  into after-fix/ so the gate is fully idempotent.  Report-only by
  default; see the sibling `test_sql_with_sqlfluff.bats` for the
  structural contract and `test_sql_with_sqlfluff.README.md` for the
  operator guide.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sql_with_sqlness_cli.sh`

- **Purpose:** Run the sqlness-cli SQL integration-test runner and emit text, JSON, and SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sql_with_sqlness_cli.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Drives sqlness-cli against a configured MySQL/PostgreSQL target,
  capturing the native run log, a derived JSON summary, and a
  jaq-synthesised, structurally validated SARIF 2.1.0 under
  documentation/sql/sqlness/. This project is SQLite-only, so the
  gate self-skips (rc=0) whenever no target and case-dir are
  configured. Test failures are recorded in artefacts, never as an abort.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sqlite_integrity.sh`

- **Purpose:** Run the SQLite integrity PRAGMAs read-only over every in-scope
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sqlite_integrity.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.
  Opens every in-scope *.db / *.sqlite / *.sqlite3 / *.db3 file through the
  read-only SQLite URI form (`file:<db>?mode=ro&immutable=0`) and records
  `PRAGMA integrity_check`, `PRAGMA foreign_key_check`, `PRAGMA quick_check`
  plus the informational `journal_mode` / `foreign_keys` / `page_size` /
  `schema_version` PRAGMAs the ndaal SQL contract cares about.  Scope is the
  whole repo EXCEPT .git/, skills/, documentation/, nuclei-templates/,
  target/ and node_modules/, plus any extra paths named in
  SQLITE_INTEGRITY_DB.  Emits a human report plus a normalised JSON findings
  list and a jaq-derived, schema-validated SARIF 2.1.0 (sqlite3 has no
  native SARIF reporter) under documentation/sql/sqlite_integrity/, and
  records that autofix is NOT_APPLICABLE (an integrity check diagnoses, it
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sqllogictest_bin.sh`

- **Purpose:** test_sqllogictest_bin — run the repo's .slt regression files through
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sqllogictest_bin.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Finds
  the tracked `*.slt` files (excluding .git/skills/documentation), probes
  engine reachability, runs each file through `sqllogictest`, emits a JUnit
  XML + a text log, synthesises per-file JSON + SARIF 2.1.0 via jaq, sorts
  the results for idempotency, and validates the SARIF.  See the inline
  comments and the sibling `test_sqllogictest_bin.bats` for the contract.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_sqlmap.sh`

- **Purpose:** Drive sqlmap + manual payloads against the vl-web HTTP API.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_sqlmap.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs sqlmap in batch mode against every injectable endpoint and
  replays a curated list of manual SQL-injection payloads via curl,
  writing a timestamped Markdown report plus the raw sqlmap output.
  Self-skips with rc=0 when sqlmap is absent or the server is
  unreachable; fails with rc=1 when any endpoint or payload looks
  injectable.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_stateright.sh`

- **Purpose:** Run the Stateright model checker for the workspace state-machine models.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_stateright.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Builds + runs the standalone stateright-harness crate (`cargo test
  --release`), which model-checks two protocols of the workspace with a
  breadth-first checker: the {Idle,Running,Stopping,Stopped} feeder lifecycle
  driven by the FEEDER_STOP latch (safety: no store after stop; liveness:
  RequestStop eventually reaches Stopped) and a linearizable Insert/Get
  register over the storage (every reachable history is valid for
  Stateright's own Register reference object).  Stateright is a normal library
  dependency — this gate MODELS the protocols, so unlike loom's `--cfg loom`
  the harness is an ordinary crate; it still lives in its own `[workspace]`
  so its stateright dep never reaches cargo-deny / geiger / machete.
  A --fast gate (NOT in LIVE_GATES, like test_loom.sh): self-skips (exit 0)
  when cargo/rustc or the stateright-harness crate is missing (or when
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_stress_ng.sh`

- **Purpose:** Apply stress-ng memory/IO/CPU pressure while vl-web serves; assert survival.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_stress_ng.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE chaos/fault-injection gate. Runs bounded stress-ng stressors — --vm,
  --io, --hdd, --memrate, --cpu — for STRESS_NG_SECONDS each WHILE the running
  vl-web keeps serving, then asserts the server SURVIVES the pressure: it stays
  up (health still 200), its resident memory (RSS) stays bounded, and the
  error rate of a concurrent health-probe stream stays under a threshold. This
  is the host-resource-exhaustion complement to the endurance soak gate — it
  forces the leak/back-pressure class to manifest under real memory/IO/CPU
  scarcity rather than waiting for organic churn. stress-ng CAN run standalone
  (the stressors themselves need no server); the PAIRED survival assertion
  self-skips when vl-web is down, while still recording that the standalone
  stressor ran. The whole gate self-skips cleanly (rc 0) when stress-ng is
  absent (the expected state on macOS / any host without it). Every spawned
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_taudit.sh`

- **Purpose:** License: All content is licensed under the terms of the <Apache 2.0>
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_taudit.sh [arguments...]`

#### `vulnerability-lookup-rs/tests/scripts/test_testssl_endpoints.sh`

- **Purpose:** testssl.sh TLS-posture sweep of every vl-web route over TLS 1.3.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_testssl_endpoints.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs a testssl.sh baseline against the main TLS listener (and the
  optional Meilisearch listener when present), then probes every page,
  API, and static route with a TLS-1.3-only curl handshake, flagging
  any endpoint that returns an unexpected HTTP status. Writes JSON +
  HTML reports and a failed-endpoints log; exits non-zero when any
  route misbehaves.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_tls_endpoints.sh`

- **Purpose:** testssl.sh + openssl TLS 1.3 enforcement sweep of vl-web endpoints.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_tls_endpoints.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs testssl.sh protocol + server-default checks against every
  configured endpoint (including the optional Meilisearch listener),
  then uses openssl s_client to assert TLS 1.3 negotiates and TLS 1.2
  is refused. Tallies pass/fail counts and exits non-zero on any
  failure.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_tlsfuzzer.sh`

- **Purpose:** Negative TLS-handshake gate — tlsfuzzer / TLS-Attacker against the LOCAL vl-web listener; all-format reports + jaq-derived SARIF 2.1.0.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_tlsfuzzer.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE, LOOPBACK-ONLY gate for the NEGATIVE half of the TLS surface.
  `testssl.sh` enumerates what the server ACCEPTS; this gate drives what it
  must REJECT: malformed ClientHellos, TLS 1.2 downgrade attempts, fragmented
  handshake records, and — specifically — the hybrid post-quantum ML-KEM
  key-share NEGOTIATION-FAILURE path.  rustls must reject every one of them
  cleanly: never panic, never emit a 5xx, never hang.

  Two upstream frameworks drive that surface:

    * tlsfuzzer (<https://github.com/tlsfuzzer/tlsfuzzer>) — Python scripts
      that send malformed / edge-case ClientHellos and assert on the server's
      reaction.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_toxiproxy.sh`

- **Purpose:** Toxiproxy network-chaos gate — inject latency/timeout/slicer/down
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_toxiproxy.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE chaos/fault-injection gate. Stands Shopify's toxiproxy TCP proxy
  BETWEEN vl-web and one of its upstreams (Meilisearch on 7700 by default,
  or the outbound feed fetches), rewires the upstream through the proxy,
  then applies a sequence of toxics — latency(1000ms), timeout, slicer
  (partial writes), and finally a full connection cut (toxic "down") — while
  an independent curl health probe asserts vl-web degrades gracefully: no
  panic, bounded 5xx, timeouts surfaced not hung. Self-skips (exit 0) when
  toxiproxy-server / toxiproxy-cli are absent, the platform is unsupported,
  jaq is missing, or the target vl-web / upstream is not reachable. This gate
  self-skips on macOS and anywhere the tools are not installed — that is the
  expected, correct result. Report-only unless TOXIPROXY_STRICT=1, in which
  case an observed hard failure (panic / unbounded 5xx / hung request) is
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_turmoil.sh`

- **Purpose:** Run the standalone turmoil network-fault harness (turmoil-harness/).
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_turmoil.sh [arguments...]`

#### `vulnerability-lookup-rs/tests/scripts/test_typos.sh`

- **Purpose:** Run the `typos` spell-checker over the workspace, long + JSON.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_typos.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Invokes `typos` twice — once in long format for humans and once in
  JSON for machines — writing both reports under documentation/rust/
  lint/. Self-skips with rc=0 when typos is not installed; treats a
  findings exit (rc=2) as a real failure and surfaces the count.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_ui_browser.sh`

- **Purpose:** Curl-driven smoke test of the vl-web HTML UI and its routes.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_ui_browser.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Fetches each page of the web UI over curl and asserts on the returned
  markup — presence/absence of expected strings, minimum match counts,
  and HTTP status codes — accumulating pass/fail tallies. A lightweight
  substitute for a headless-browser suite; exits non-zero on any failed
  assertion.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_unknown_fields.sh`

- **Purpose:** Detect leftover "unknown"/UNKNOWN placeholder values in the API and web UI.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_unknown_fields.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Probes the running vl-web server's recent-vulnerability API,
  per-source samples, and the /recent and /kev HTML pages for
  UNKNOWN severities, unknown update dates, id-equals-title rows,
  and zero-value CVSS badges. Tallies pass / warn / fail counts and
  exits non-zero only when hard failures are found.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_vacuum.sh`

- **Purpose:** LIVE OpenAPI-spec lint gate — lint vl-web's generated /openapi.json
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_vacuum.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  LIVE spec-quality gate. schemathesis validates REQUESTS against the
  spec but never lints the spec ITSELF — vacuum fixes that. This project
  has NO static specs/openapi.yaml: the OpenAPI document is GENERATED at
  runtime by crates/vl-web/src/openapi.rs and served at GET /openapi.json
  (self-signed TLS). This gate fetches that document from a running vl-web
  (curl -k) into a temp file, then runs vacuum's very-fast Go linter over
  it: `vacuum lint -d` (rule violation details), `vacuum spectral-report`
  (machine-readable JSON), and `vacuum html-report` (self-contained HTML).
  The spectral JSON is parsed into a schema-valid SARIF 2.1.0 with jaq
  (ruleId = the vacuum rule id, level from severity). Defaults to vacuum's
  built-in `recommended` ruleset; a starter `.vacuum.yaml` documenting the
  recommended rules is scaffolded next to the reports. Self-skips (exit 0)
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_valgrind_extra.sh`

- **Purpose:** Valgrind helgrind + DRD + massif — races, lock-order, heap growth.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_valgrind_extra.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  The cargo-valgrind gate only runs Memcheck. This gate covers the other
  three Valgrind tools against a targeted first-party test binary: helgrind
  and DRD (data races + lock-order violations — the dynamic, real-code
  complement to Loom's model and TSan's compile-time instrumentation) and
  massif (heap-allocation growth shape over time — the allocation-level
  complement to the soak gate's process-RSS/fd trend). Linux only; Valgrind
  is unavailable / unreliable on macOS + Apple Silicon. Report-only unless
  VE_STRICT=1. Archives per-tool logs under
  documentation/rust/soundness/valgrind_extra_<TIMESTAMP>/.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_verus.sh`

- **Purpose:** Probe the `verus` deductive verifier; emit all formats + jaq SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_verus.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  the `verus` unbounded deductive verifier over the Cargo workspace,
  captures its verdict, derives a schema-validated SARIF 2.1.0 (no native
  SARIF reporter exists), and writes reports under documentation/rust/verus/.
  Analysis-only + idempotent; report-only unless VERUS_STRICT=1.  Self-skips
  (rc 0) when the verifier is absent.  See the sibling test_verus.bats.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_wardenscan.sh`

- **Purpose:** Run the wardenscan GitHub Actions security scanner and collect its reports.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_wardenscan.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Wraps the `warden` binary (crate `wardenscan`) to scan the repo's
  GitHub Actions workflows across 59 rules, emitting console, JSON,
  SARIF, and Markdown reports plus a non-destructive autofix plan
  under documentation/linter/wardenscan/. Self-skips (rc=0) when the
  binary is absent or no workflows exist; `--strict` gates on findings
  and `--apply-fixes` writes autofix changes back into the tree.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_web_check.sh`

- **Purpose:** Run the web-check container against the running vl-web target and collect results.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_web_check.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Launches the web-check Node container under podman, points it at the
  vl-web endpoint (rewriting localhost to host.containers.internal),
  runs a focused subset of security / DNS / TLS tests, and collects the
  JSON results under the output directory. Self-skips (rc=0) when
  podman, curl, jaq, or the target endpoint is unavailable.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_x509lint.sh`

- **Purpose:** Lint an X.509 certificate with x509lint and emit text, JSON, and SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_x509lint.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs the x509lint binary over a certificate (an explicit
  X509LINT_CERT or a freshly generated self-signed test cert),
  captures its native text report, parses it into normalised findings
  JSON via jaq, and derives a SARIF 2.1.0 document. Reports land under
  documentation/. Self-skips (rc=0) when x509lint, jaq, or a
  certificate is unavailable; X509LINT_STRICT=1 gates on findings.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_yamtam_rt.sh`

- **Purpose:** test_yamtam_rt — scan the repo for secrets/vulns/deps/supply-chain
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_yamtam_rt.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Part of the nvulnlookup quality-gate suite under `tests/scripts/`.  Runs
  `yamtam-rt hunt run` over a staging tree of the git-tracked files
  (excluding `.git/`, `skills/`, `documentation/`), emits text/json,
  synthesises SARIF 2.1.0 from the JSON via jaq, sorts the results for
  idempotency, and validates the SARIF.  See the inline comments and the
  sibling `test_yamtam_rt.bats` for the full contract this gate enforces.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_yara_x.sh`

- **Purpose:** Scan shipped binaries with yara-x (`yr`) and emit text, ndjson, JSON, and SARIF.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_yara_x.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Runs the yara-x `yr` scanner recursively over the release binaries
  using the ruleset built by collect_yara_rules.sh, emitting every
  native output format plus a jaq-derived SARIF 2.1.0 document under
  documentation/security/binary/yara_x/. Self-skips (rc=0) when yr,
  jaq, or the ruleset is missing; `--strict` fails on any rule match.
```

</details>

#### `vulnerability-lookup-rs/tests/scripts/test_zap_scan.sh`

- **Purpose:** Run an OWASP ZAP DAST scan (baseline / full / api) against the running server.
- **Usage:** `bash vulnerability-lookup-rs/tests/scripts/test_zap_scan.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Drives an OWASP ZAP scan against the vl-web HTTP/2 endpoint via a
  Dockerised ZAP image or a local zap.sh fallback, in baseline, full,
  or api mode. Writes HTML/JSON/XML/Markdown reports under the report
  directory, notes HTTP/3 reachability (unscannable over QUIC), and
  fails on any High-risk alert (Medium too when ZAP_FAIL_ON_MEDIUM=1).
```

</details>

### Other first-party scripts

#### `csaf/enrich_publisher_metadata.sh`

- **Purpose:** Idempotent enricher for ndaal CSAF advisories under csaf/2026/<NNN>/.
- **Usage:** `bash csaf/enrich_publisher_metadata.sh [arguments...]`

#### `csaf/generate_distribution_index.sh`

- **Purpose:** Idempotent generator for the CSAF 2.1 directory-based distribution
- **Usage:** `bash csaf/generate_distribution_index.sh [arguments...]`

#### `vulnerability-lookup-rs/create_sbom_with_cargo_sbom.sh`

- **Purpose:** Generate SPDX 2.3 + CycloneDX 1.6 SBOMs (rust deps + release artifacts) into release/v<version>/.
- **Usage:** `bash vulnerability-lookup-rs/create_sbom_with_cargo_sbom.sh [arguments...]`

<details>
<summary>Full description (from script header)</summary>

```text
  Generates a Software Bill of Materials for the nvulnlookup workspace in
  BOTH SPDX 2.3 and CycloneDX 1.6, covering the Rust dependency graph (via
  `cargo sbom`) AND the published release artifacts (binaries, tarballs,
  .deb / .rpm packages) under release/v<version>/, each annotated with the
  checksums read from its committed sidecar files.  Because `cargo sbom`
  only knows the cargo dependency graph, the release artifacts are merged
  in afterwards with jaq: SPDX gets extra `.packages` (with `checksums`) +
  `DESCRIBES` relationships, CycloneDX gets extra `.components` of type
  `file` (with `hashes`); artifacts are keyed by their release-relative
  path so per-triple builds get a unique SPDXID / bom-ref.

  Writes into release/v<version>/:
```

</details>

<!-- markdownlint-restore -->

## Security

### TLS

- TLS 1.3 enforced, no TLS 1.2 fallback
- ECC ciphers only, no RSA
- rustls (pure Rust, no OpenSSL)
- Self-signed certs auto-generated for dev
- Verify with: `testssl.sh localhost:8080`

### Secrets

- User passwords: Argon2id (RFC 9106)
- API keys: `secrets::token_urlsafe(32)`
- TOTP: RFC 6238 (authenticator apps)
- Ansible Vault for deployment secrets

### Supply Chain

- `cargo-audit`: 0 known vulnerabilities
- `cargo-geiger`: unsafe usage audited
- Binary checksum verification on deploy
- No external process spawning (pure Rust)

## Troubleshooting

### Server Won't Start

```bash
# Check port availability
ss -tlnp | grep 8080

# Check permissions
ls -la data/

# Verbose logging
RUST_LOG=debug ./vl-web
```

### Feeders Not Updating

```bash
# Check feeder logs
journalctl -u nvulnlookupd \
    | grep -E "Feeder|CSAF|NVD"

# Verify network connectivity
curl -sI https://services.nvd.nist.gov

# Check last update timestamps
vl-cli db count
```

### Database Corruption

Since v1.2.66 a damaged database **fails**
on open instead of panicking. Seven of the
fifteen tested damage shapes -- including
every truncation -- used to abort the process
with a panic rather than return an error, so
the operator got a backtrace instead of a
diagnosis. Page-0 underflow and
negative-timestamp key corruption are fixed
in `vl-core`.

Expect a reported error on open. A panic is
no longer the expected failure mode for a
corrupt store; report one as a bug.

```bash
# Backup current state
cp -r data/ data-corrupt-backup/

# Reset and re-import
vl-cli clear-db
vl-cli import-dumps --dir dumps
```