The FANGS orchestrator persists scan runs, raw eBPF events, baseline fingerprints, deviations, allowlist entries, notifier targets, and the npm package watch list in a relational database. Three backends are available: SQLite (the default, requires no external service), PostgreSQL (recommended for production and multi-runner deployments), and none (events are logged to stderr but nothing is stored). Both SQLite and PostgreSQL apply schema migrations automatically on every startup, so there is no separate migration step.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/irchaosclub/FANGS/llms.txt
Use this file to discover all available pages before exploring further.
Choosing a backend
SQLite
Default. Zero external dependencies. Ideal for single-operator setups, local development, and CI pipelines. The database is a single file on disk.
PostgreSQL
Production. Handles concurrent runners, long-term retention, and high event volumes. Requires a Postgres instance reachable from the orchestrator.
None
Smoke-testing only. Events are logged to stderr but never written to disk. The Differ, UI, notifier, and watcher are all disabled.
SQLite
SQLite is selected with-storage sqlite (the default). The orchestrator creates the database file and its parent directory on startup if they do not already exist.
Configuration
Must be set to
sqlite (or omitted) to use this backend.Path to the SQLite database file. The orchestrator calls
os.MkdirAll on the parent directory before opening, so the path can be nested under a directory that does not yet exist.Startup command
Implementation notes
- Driver:
modernc.org/sqlite(pure Go — no CGO, cross-compiles cleanly) - WAL mode and foreign keys are enabled on every connection via the DSN pragmas:
journal_mode=WAL,foreign_keys=ON,busy_timeout=5000 - Connection pool: max 8 open connections, max 2 idle
- Writes serialize via SQLite’s own locking; WAL mode allows concurrent readers
SQLite is a single-file database. Back it up by copying the file while the orchestrator is stopped, or use SQLite’s online backup API. Storing the file on a network filesystem (NFS, CIFS) is not recommended — SQLite relies on POSIX file locking which many network filesystems do not implement correctly.
PostgreSQL
PostgreSQL is selected with-storage postgres. You must supply a connection string either through the -postgres-dsn flag or the $FANGS_PG_DSN environment variable. If both are set, the flag takes precedence.
Configuration
Set to
postgres to use this backend.PostgreSQL DSN. Accepts URL form (
postgres://user:pass@host:5432/dbname) or keyword form (host=db.internal dbname=fangs user=fangs password=secret). Falls back to $FANGS_PG_DSN when empty.Startup commands
Implementation notes
- Driver:
github.com/jackc/pgx/v5/stdlib(pgx v5database/sqlwrapper) - Connection pool: max 16 open connections, max 4 idle, 1-hour max connection lifetime
- Schema migrations use the same migration helper as SQLite, with
$1-style placeholders instead of? - The unique-violation detection checks for PostgreSQL error code
23505to returnstorage.ErrConflict
The none backend
Setting -storage none disables persistence entirely. The orchestrator starts, accepts runner registrations, dispatches jobs, and logs events to stderr, but nothing is written to disk or a database.
Schema migrations
Both SQLite and PostgreSQL apply schema migrations automatically during theMigrate(ctx) call made right after Open. The migration helper in internal/orchestrator/storage walks a versioned set of SQL files and applies any that have not yet been recorded in the internal migrations table. Migrations are idempotent — restarting the orchestrator against an already-migrated database is safe and fast.
There is no separate migration CLI. If the orchestrator fails to start with a migration error, check that the database user has CREATE TABLE privileges and that the database itself exists.
Event retention
Raw eBPF events accumulate quickly in high-throughput environments. FANGS includes a built-in pruner that removes old events on a configurable schedule.How it works
- The pruner runs as a goroutine inside the orchestrator process
- A one-shot fires 30 seconds after startup — this gives operators an immediate confirmation in the logs that the pruner is wired correctly
- Subsequent runs happen on the
-retention-intervalticker (default: every24h) - Each pass deletes all rows from the
eventstable wherets_ns < cutoffand the event is not referenced by a row in thedeviationstable asevidence_event_id - The deletion count and cutoff timestamp are logged at
INFOlevel after each pass
Retention flags
Delete raw events older than this many days. Set to
0 to disable the pruner entirely. Deviation-evidence events are always pinned — they are never deleted regardless of this value.Cadence of the retention pruner. Accepts standard Go duration syntax:
12h, 24h, 168h.Example log output
Deviation-evidence pinning
When the Differ identifies a deviation, it stores the ID of the specific event that provided the evidence indeviations.evidence_event_id. The pruner’s DELETE statement excludes any event whose id appears in that column:
The placeholder syntax is
? for SQLite and $1 for PostgreSQL. Both backends run the same logical query.