Handbook sections▾
Foundations
Understanding the threats to a Linux hostWhy we hardenThe defense principles behind every ruleEffective configuration: the truth no file holdsThe standards Pavois maps toSOCLE control ID modelEvidence & exportsHow the A-E grade is computedWhat a PASS proves: the qualified verdictTrust model for the evidence bundleIs SOCLE just your own norm? (governance & the circularity question)What Pavois covers, and what it doesn'tDomains
Hardening SSHHardening PAMMandatory Access Control (SELinux / AppArmor)Hardening the host firewallHardening sudoFile Permissions & OwnershipMount & filesystem hardeningHardening kernel modulesHardening the kernel & network with sysctlAudit logging with auditdHardening logging with journald and rsyslogHardening systemd servicesPackage hygieneHardening the bootloader (GRUB)Synchronizing timeLogin banners and MOTDControlling cron and at accessHardening the GNOME desktop (dconf)Tooling
Undo a hardening run: restore pointsOperating Pavois: privileges, air-gap, timing, exceptionsRun Pavois in CI (GitHub Actions)Feature status: delivered, partial, roadmapGovernance: licence, versioning, provenance, securityEvidence & exports
Last reviewed
What a Pavois scan produces for an auditor: effective checks, graded reports, machine-readable exports (JSON/SARIF/JUnit/CSV) and the OSCAL baseline, and the limits to state honestly.
What evidence Pavois collects
For every control, a Pavois scan records the evidence check it ran and its evidence type (e.g. an effective-runtime check like sshd -T | grep -i permitrootlogin), the observed value, the verdict (compliant / gap / manual / not-applicable), the standards the control maps to, and the target context (host, OS, profile version). That is the raw material of an audit trail.
What a pass proves: the four evidence types
Not every check proves the same thing, and Pavois labels which on every control (see evidence types):
| Evidence type | What a PASS proves |
|---|---|
effective-runtime |
the live, resolved state (sshd -T, sysctl, systemctl show, auditctl -l). The running value, not that it survives a reboot |
persistent-config |
the content of a persistent config file (drop-ins resolved). Reboot-survivable intent |
inventory-state |
what is installed or registered (packages, accounts). Presence/absence |
filesystem-state |
a path's mode, owner, SUID/SGID. On-disk metadata |
A control's verdict is separate from its evidence type: it can be compliant, gap, manual (needs human judgement, Pavois delivers the question not a verdict) or not-applicable. The headline case stands for the effective-runtime controls: a file can read compliant while a drop-in re-enables the very thing it forbids, and the effective read is what holds up. Pavois states each control's type so the auditor knows what a pass does and does not establish.
Report formats
pavois scan writes the same result in several shapes (--format):
- HTML: a chaptered, per-standard report graded A-E, for humans.
- JSON: the full result plus the grade block, for tooling.
- SARIF: for code-scanning dashboards.
- JUnit: for CI test reporting.
- CSV: for spreadsheets and pivots.
pavois scan local --sudo --format html
pavois scan admin@server1 --format sarif --fail-under 80The exit code (--fail-under N) turns the grade into a CI gate. The JSON carries the grade and counts plus a findings array, each entry holding the control id, its evidence type, the observed value, the verdict and the norm mappings:
{
"grade": "B", "points": 84, "passed": 142, "total": 150,
"runtime_qualified": false, "qualified_passes": 0,
"counts": { "critical": 0, "high": 0, "medium": 2, "low": 1 },
"findings": [ { "id": "ssh-disable-root-login", "status": "passed" } ]
}OSCAL: a baseline, not yet an assessment package
The control catalogue is published as OSCAL 1.1.2 (the NIST format CIS and NIST adopt), so a GRC tool can import the Pavois baseline directly:
pavois oscal --out oscal/ # catalog + one profile per OSIt emits pavois-catalog.json (every control, its effective check, its per-OS CIS/STIG numbers and norm links) plus one profile per OS. Be precise about scope: Pavois emits the OSCAL catalog and profiles (the reusable baseline), it does not yet emit OSCAL assessment-results (the per-scan findings package). So today you get a machine-readable baseline to import, not a full OSCAL audit-result bundle; assessment-results is on the roadmap. The baseline is versioned in docs/reference/baseline.yml, tracked in the CHANGELOG, and downloadable (catalog, per-OS profiles, SHA-256 checksum) on the Downloads page.
The evidence chain
The pieces form one chain you can hand an auditor: scan target produces a per-control finding (check + evidence type + observed value + verdict + norms), which rolls up into the graded report (HTML for humans, JSON/SARIF/JUnit/CSV for tooling), while the reusable baseline is the OSCAL catalog + profiles with a checksum. Archive the JSON and HTML together and the chain is reproducible with --from.
How to archive a scan result
Keep the JSON (the source of truth) plus the HTML (the human view), stamped with the host, the OS, the profile/baseline version and the scan date. Re-running with --from <json> regrades an archived result without touching the host.
Known limitations
State these plainly in any audit package:
- Effective checks need the service installed and running, and often
--sudo; a control on an absent service reads not-applicable, not compliant. - Some controls ship no automated remediation (kernel rebuilds, judgement calls): Pavois delivers the recipe, it does not run it.
- Coverage is honest, not total: most controls map to several standards, but single-standard and source-only controls exist and stay visible.
- OSCAL output is a baseline (catalog + profiles), not an assessment-results package yet.
Evidence bundle
pavois bundle <before.json> <after.json> packages a whole campaign into one tamper-evident folder: the before/after scans, the plan that was applied (--plan), the reports (--report), an optional reboot-proof and an exceptions file, a campaign-delta.json (the transition matrix), a manifest.json (pavois and ruleset version, target, grade delta, per-artifact SHA-256) and a checksums.txt (verifiable with sha256sum -c). The manifest's own SHA-256 is the single digest to sign and publish (minisign, cosign or gpg), so the package becomes tamper-evident, and opposable audit evidence once signed under an accepted trust policy, rather than a screenshot. Who may sign, which identity is accepted, how keys rotate and how to verify offline: see the trust model. You sign checksums.txt with your own identity (cosign sign-blob or gpg --detach-sign); pavois does not own the key. pavois bundle verify <dir> then re-checks every artifact's SHA-256, the manifest digest and the signature, and exits non-zero on any tampering.
FAQ
Does Pavois emit OSCAL assessment-results? Not yet. It publishes the OSCAL catalog and per-OS profiles (the baseline). The per-scan assessment-results package is on the roadmap; today you export findings as JSON/SARIF/JUnit/CSV.
Which export should I archive? The JSON (the source of truth) plus the HTML (the human view). --from <json> regrades the archived result without re-touching the host.
How do I gate CI on the grade? --fail-under N sets the exit code from the grade; pair it with --format sarif or junit to surface findings in the CI dashboard.
What does a real Pavois report look like? See the sample report: a real Debian 12 scan, plus the before/after campaign report with the full transition matrix.
How do I produce audit-ready evidence? Run pavois bundle before.json after.json --plan <plan> --report <html>: it bundles the scans, plan, reports, transition delta, a manifest and checksums, and prints one SHA-256 to sign and publish.