warehouse — guide
Class:
guide· audience: someone opening the shared catalog to import advisories or scan a fleet. The what is inwarehouse-design.md; the why inwarehouse-reasoning.md. Needs--features warehouse.
f0 — open, import, scan (CLI)
# import an advisory generation (see feeds-guide.md for the feed flags)
modgunn warehouse import --warehouse <root> --rev 2026-07-04-a --osv advisories/osv/
# full fleet scan: every repo's sbom_components × the latest advisories
modgunn warehouse scan --warehouse <root>
# incremental CDC scan: only components added since a snapshot; prints next watermark
modgunn warehouse scan --warehouse <root> --since 4211
# what's imported
modgunn warehouse stats --warehouse <root> --ecosystem cargo
# persist an A23 package-behaviour analysis (verdict ledger), then read it back
modgunn behavior --path package.json --warehouse <root> # append the vector + verdict
modgunn warehouse behavior-log --warehouse <root> # latest per (ecosystem, subject)
modgunn warehouse behavior-log --warehouse <root> --ecosystem npm --subject left-pad-helper
scan prints one line per vulnerable dependency (repo name version advisory_id severity) then a summary with the high/critical count and, for --since, the next --since <watermark> to poll from. Add --vex <dir> to drop consumer-suppressed advisories, --sql to use the DataFusion pushdown (needs warehouse-sql; degrades to in-memory otherwise).
f0 — in code
use modgunn::warehouse::Warehouse;
use std::path::Path;
let wh = Warehouse::open(Path::new(root))?; // or open_read_only when a server holds the lock
wh.ensure_modgunn_tables()?;
wh.append_advisories("2026-07-04-a", &advisories)?; // a new generation
let db = wh.load_advisory_db(Some("cargo"))?; // latest db_rev, one ecosystem
let findings = wh.scan_fleet()?; // Vec<FleetFinding>
// A23 behaviour verdict ledger — persist a parsed PackageBehavior, read it back.
let behavior = modgunn::behavior::parse_npm_package(package_json)?;
wh.append_package_behavior("npm", &behavior)?; // vector + derived verdict, append-only
let records = wh.load_package_behaviors()?; // Vec<BehaviorRecord>, latest per (eco, subject)
assert_eq!(records[0].behavior, behavior); // round-trips field-identical
f2 — incremental refresh loop
// remember the last watermark; poll cheaply, only scan the delta
let (findings, next) = wh.scan_sbom_delta(Some(last_watermark))?;
// … act on findings …
last_watermark = next.unwrap_or(last_watermark);
Use wh.commit_seq()? as an even cheaper "did anything change at all?" poll before calling scan_sbom_delta. wh.table_delta("cve_advisories", from)? gives the raw changed rows for any owned table.
f3 — capturing an Engine B snapshot (feature scip + warehouse)
wh.capture_world_snapshot(&snapshot)?; // world_snapshots + dep_edges + scip_symbols
wh.record_behavior_delta_findings(&delta)?; // behavior_deltas rows
Gotchas
- If a running
nornir-serverholds the redb write lock, useWarehouse::open_read_only— it copies the catalog aside and reads a consistent snapshot without contending. scan_fleetassumescargofor SBOM rows until nornir adds an ecosystem column (DEFAULT_ECOSYSTEM); cross-ecosystem fleets will mis-match until then.- A missing
sbom_componentstable is not an error — it just means "no watermark" / an empty fleet, so a fresh warehouse scans cleanly. - Imports and a live server writer are single-writer coordinated — schedule imports when the server is down, or import through the read-only-safe path.