
Reef runs seven scan types against a monitored host. Each has its own tool and raw output format, but all of them are parsed server-side into the same Finding model, so triage, notifications, and filtering work identically regardless of which scan produced a result.
Job lifecycle
pending → claimed (agent polled it) → running (agent started it) → done / failed
A job expires instead if no result arrives within REEF_JOB_STALE_AFTER_SECONDS (default 3600s). canceled is a terminal state an operator sets from the scans table, a scan’s detail page, or the admin “Cancel selected jobs” action — the job moves to canceled immediately rather than waiting for the stale reaper. A queued job is simply dropped; a claimed/running one is stopped on the agent’s next check-in (canceled_job_ids), which kills the running scanner subprocess, discards the partial result, and lets the agent pick up its next job. A late result for an already-canceled job is refused, so it can’t resurrect.
How a scan gets started
- Scheduled — a
ScanSchedule, editable in the Django admin, dispatched bybeat. Default schedules (nightly file integrity monitoring, hourly AuditD, weekly Lynis, daily ClamAV/YARA/Grype, weekly OpenSCAP) are created on firstwebstart bymanage.py reef_seed. You can remove non-applicable scans as required. - Manual — the toolbar’s Run scan button (
POST /api/scans/). Manual jobs are claimed ahead of scheduled ones, andbeatwon’t stack a second scheduled run of a type that already has one queued.
Scan params
The Run scan dialog’s Params (JSON) field (and a ScanSchedule’s params) is merged over the type’s defaults, stored on the job, and passed verbatim to the agent runner. Unknown keys are ignored — there’s no validation. timeout (seconds, per-tool subprocess cap) works on every scan type. See each scan’s own page for its specific params.
Scan scope is bounded by default
Walking the entire host root takes hours on a real machine, so most scan types default to a bounded set of paths rather than scanning /:
fim→REEF_FIM_DEFAULT_PATHS(/etc,/bin, …)clamav→ writable / higher-risk dirs (/home,/root,/tmp,/opt, …)yara→ the same set as ClamAV, plus/etc; files over 64 MiB are skipped, and heavy package-cache/VCS/build trees (node_modules,.venv,.git, …) are pruned by basenamegrype→ fulldir:/host, but with heavy trees excluded during thesyftwalk (node_modules,.cache,var/lib/docker, …)
The scans
| Scan | What it checks |
|---|---|
| File Integrity Monitoring | New / changed / removed files vs. a per-agent baseline |
| Auditd | Kernel audit rule coverage + classified audit events |
| Lynis | General host hardening audit with plain-language explanations |
| ClamAV | Signature-based malware scanning |
| OpenSCAP | CIS/STIG/PCI-DSS compliance scanning |
| Grype | CVE scanning against an SBOM, with CISA KEV tagging |
| YARA | Rule-based malware / indicator matching over files and process memory |