Chapter 15 of 26
Running Compliance Scans
This page covers how to trigger a compliance scan, watch it progress, cancel it if needed, and set up scheduled scans across the fleet. All actions are from the web UI; everything runs against a logged-in session with the compliance module enabled.
You need can_manage_compliance to trigger, cancel, or install scanners; can_view_reports to watch progress without changing anything; and can_manage_hosts to change per-host compliance mode or scanner toggles.
Three Ways to Start a Scan
| Entry point | Best for | Scope |
|---|---|---|
| Host Detail → Run Scan button | Investigating a single host | 1 host, "all profiles" (whatever scanners are enabled for that host) |
| Security Compliance → Hosts tab → green Play button | Re-scanning a specific host from the fleet view | 1 host, "all profiles" |
| Security Compliance → Scheduled, via fleet interval | Ongoing coverage across hosts where compliance mode is enabled |
Every host with mode=enabled, runs periodically |
Bulk ad-hoc scans across a selected host set are also supported. See Bulk Scans below.
Triggering a Scan on One Host
From the Host Detail page
- Open Hosts → select the host → Compliance tab (also reachable via Security Compliance → host row → host name link).
- Look at the top-right of the Compliance tab. You'll see:
- A Connected or Disconnected pill: this is the agent's WebSocket connection status. Scans require a connected agent.
- A Run Scan button (green with a Play icon).
- Click Run Scan. The UI calls
POST /api/v1/compliance/trigger/{hostId}withprofile_type=all(run every scanner enabled for this host). - The button flips to a spinner with "Scanning…" and a toast confirms "Compliance scan triggered". The response includes a
jobIdyou can correlate with server logs if needed.
If the agent is disconnected, the button is disabled and the tooltip reads "Host is disconnected". Re-enable connectivity (see Managing the PatchMon Agent) before retrying.
You can also pick a specific profile instead of running all scanners:
- On the Host Detail Compliance tab, expand the profile selector (if visible for your role) and choose a profile, for example,
level2_serverinstead of the defaultlevel1_server. - Tick Enable Remediation if you want the agent to apply OpenSCAP's remediation scripts for any failed rule during this scan. Remediation in-scan is destructive, only tick this when you've reviewed what the rules would do.
- Click Run Scan. The request body includes
profile_type,profile_id, andenable_remediation.
From the Security Compliance Hosts tab
- Open Security Compliance → Hosts tab. You see a table of every compliance-enabled host.
- Click the green Play button in the Run column for the host you want to scan. This has exactly the same effect as Run Scan on Host Detail, with
profile_type=all. - Watch the row turn blue: the Last activity column shows an animated "OpenSCAP" / "Docker Bench" / "Scanning…" label while the scan is in progress.
The Play button turns into a red StopCircle button when the scan is active. Click it to cancel. See Cancelling a Scan below.
Watching Scan Progress
There is no live log stream for compliance scans (unlike patch runs). Instead, the UI relies on active-scan polling.
The active-scans widget
On the Compliance page Overview tab, when any scan is running, a blue Scans in Progress card appears with a spinner. Each running scan is shown as a pill with:
- Host name (link to Compliance Host Detail).
- Profile type badge (OpenSCAP or Docker Bench) and started-at timestamp.
- Connection indicator (green Wi-Fi icon if the agent is connected, red if not).
The list also appears inline above the hosts table and refetches via GET /api/v1/compliance/scans/active every 30 seconds while scans are active, and every 2 minutes when idle. The dashboard uses the same cadence.
The pending-scans window
Between the moment you click Run Scan and the moment the agent updates the DB row to running, there's a few-second gap where the scan exists as an asynq task but not yet as a database row. The UI bridges this with pendingScans state: the just-triggered host shows up in the active-scans widget with a "Triggering…" status immediately, and is replaced by the real DB row once it lands (or removed after 60 seconds if no corresponding scan shows up).
Completion notifications
When an active scan disappears from the /compliance/scans/active response, the UI compares against the previous poll's active-scan set and shows a success toast:
- "Compliance scan completed" for a generic completion.
- "Scan completed for host name" for a tracked pending scan.
The dashboard and the history tab refetch automatically at this point.
Per-rule progress during scanner install
If the host doesn't have OpenSCAP or the CIS benchmark content installed yet, the first action is usually to install the scanner, which has its own progress model. See Installing the Scanner below.
Cancelling a Scan
A scan can be cancelled while it is running. Unlike patch runs, there is no "Stop Run" confirmation modal. Cancel is a one-click action because scanners are read-only and safe to interrupt.
From the Hosts tab
- On the Hosts tab, find the row with the blue "Scanning…" indicator.
- Click the red StopCircle button in the Run column. The UI calls
POST /api/v1/compliance/cancel/{hostId}. - A toast confirms "Cancel request sent for host".
What cancel actually does
The CancelScan handler on the server does three things:
- Removes any queued
run_scantask from asynq, so a scan that hasn't yet reached the agent won't start. - Sets a
compliance_scan_cancelflag in Redis for this host, so if the worker picks up the task between DeleteTask and the agent message, the worker sees the cancel flag and skips execution. - Sends a
compliance_scan_cancelWebSocket message to the agent, so an already-running scan is interrupted at the process level.
If the agent is connected and busy scanning, it receives the cancel, terminates the OpenSCAP / Docker Bench subprocess, and submits whatever partial results it has. The scan record is marked cancelled.
If the agent is offline, only the queue-level cancel applies: the scan won't run when the agent reconnects because the task has already been removed from the queue.
Cancel is idempotent. Calling it on a host with no active scan returns success with "Scan cancel sent".
Scheduled Scans
Scheduled scans are the "set and forget" path. Every host with compliance_mode=enabled gets a scan on the fleet-wide interval, no operator intervention required.
Fleet-wide defaults
Set from Security Compliance → Settings:
- Default Compliance Mode: applied to newly registered hosts only. Existing hosts keep whatever mode they already have.
Disabled, new hosts register with compliance off. You must explicitly enable per host.On-Demand, new hosts register with scanning available but scheduled off. ManualRun Scanworks.Enabled, new hosts register ready for scheduled scanning.
- Scan Interval: how often
enabledhosts scan. Presets: 6h, 12h, 24h (default), 48h, 3d, 7d. Also accepts a raw minutes value between 60 and 10080 (7 days).
Saving Settings pushes the new interval to every connected agent on the next heartbeat. Offline agents pick it up when they reconnect.
Per-host mode overrides
The default is advisory; every host has its own compliance_mode. To change it:
- Open Hosts → host → Integrations tab.
- Scroll to Compliance.
- Pick Disabled, On-Demand, or Enabled.
- The change is queued as pending config and applied via the Apply Pending Config flow on the host's next agent heartbeat.
The Compliance page's Hosts tab shows the current mode in the Mode column (Disabled, On-demand, Scheduled).
Per-host scanner toggles
On the same Integrations → Compliance panel you'll find two checkboxes:
- OpenSCAP: default
on. Tick to have the agent run OpenSCAP CIS scans during each scheduled and on-demand scan. - Docker Bench: default
off. Tick only for hosts that actually run Docker and where the Docker integration is enabled.
These toggles are also reflected in the Hosts-tab Scanners column (OpenSCAP, Docker, OpenSCAP, Docker, or - if nothing is enabled).
Default profile
Set from Host Detail → Integrations → Compliance → Default profile. Pick between the available profiles exposed by the agent (typically level1_server, level2_server, and possibly docker-bench on hosts where Docker is present). This is the profile used for scheduled scans and for ad-hoc scans where no explicit profile is passed (profile_type=all).
Bulk Scans Across the Fleet
For ad-hoc "scan everything right now" operations, use the Bulk Scan modal (opened from the Compliance page; the exact entry point depends on your module / edition, usually a bulk action button on the Hosts tab).
The modal lets you:
- Choose a Profile Type.
All Profiles,OpenSCAP Only, orDocker Bench Only. - Tick Enable Remediation if you want OpenSCAP to apply remediation scripts during the scan.
- Tick the hosts you want to include (or Select All).
- Click Scan N Hosts.
The UI sends one POST /api/v1/compliance/trigger/bulk request with the full host list. The server enqueues one run_scan task per host. Hosts that are offline are still queued. They scan as soon as they reconnect and the worker dequeues their task (or the task is cleaned up if the queue drops it before reconnection).
The modal shows a results banner:
- Green if every trigger succeeded.
- Yellow if some failed, with the list of host names and the specific error per host.
After a successful bulk scan, the modal auto-closes after three seconds and each triggered host appears in the active-scans widget as pending / running.
Installing the Scanner
Compliance scanning on a host needs OpenSCAP (oscap binary) installed and the SSG content available locally. The first time you enable compliance on a host, the scanner usually isn't there yet. PatchMon handles this with an install job.
- Enable compliance mode on the host (set to
On-DemandorEnabled). - On next Apply Pending Config, the agent receives the new integration state and reports that the scanner is not installed.
- From the Host Detail Compliance tab, click Install Scanner. The UI calls
POST /api/v1/compliance/install-scanner/{hostId}. - The server enqueues an install task. The worker sends an install message to the agent.
- The agent installs the OpenSCAP scanner with the host's own package manager, then downloads SSG content from the server via
GET /api/v1/compliance/ssg-content/{filename}. Progress events are reported back to Redis and surfaced in the UI viaGET /compliance/install-job/{hostId}, which returns the current state plus a per-step message and progress percent. The states arenone(no install has been requested),waiting,active,completed,failed, andunknownwhen the job can no longer be found. Afailedstate also carries anerrorfield with the reason. - When the install completes, the Run Scan button becomes active.
The scanner package name is not the same on every release, so the agent asks the archive which one it has rather than assuming. Debian 12 and newer, and Ubuntu 24.04 and newer, provide openscap-scanner plus openscap-common; Debian 10 and Ubuntu 22.04 provide libopenscap8 instead. RHEL-family hosts use openscap-scanner and SUSE hosts use openscap-utils.
Content is handled separately from the scanner, and a host that gets one without the other is not a failure. Ubuntu packages no SSG content at all, so on Ubuntu the datastream always comes from the PatchMon server. The install only fails outright when the host ends up with no working oscap binary.
Install can be cancelled mid-flight from the same UI via POST /api/v1/compliance/install-scanner/{hostId}/cancel.
Platforms where the scanner cannot be installed
Some supported PatchMon hosts cannot run compliance scanning at all, because the platform publishes no OpenSCAP package, no SCAP content, or neither. On most of these the install reports the reason in plain terms. The exception is Amazon Linux 2, where the failure surfaces as raw yum output:
| Platform | Reason |
|---|---|
| Debian 11 (bullseye) | OpenSCAP was removed from the archive before bullseye released, so no package provides oscap |
| Amazon Linux 2 | The amzn2 repositories carry neither openscap-scanner nor scap-security-guide |
| Alpine Linux | No SCAP datastream is published for Alpine, so a scanner would have nothing to scan against |
| Arch Linux | OpenSCAP is available only from the AUR, and no datastream is published |
| FreeBSD | No OpenSCAP port and no datastream |
| Windows | The agent has no compliance integration on Windows |
Everything else in the supported matrix can install the scanner: Debian 10, 12, 13 and 14, Ubuntu 22.04 and 24.04, the RHEL family (Rocky, AlmaLinux, CentOS Stream, Oracle Linux, Fedora, Amazon Linux 2023), and openSUSE.
On Debian 10 the install succeeds but the results are not useful. PatchMon ships no Debian 10 datastream, so the host falls back to the very old content in buster's own ssg-debian package, and every rule comes back as "not applicable" because the content targets an earlier Debian release. Treat compliance scanning on Debian 10 as unavailable in practice.
If the status panel shows Partial Installation, some scanners are present and others are not. A common case is a host running Docker, where Docker Bench is ready but OpenSCAP is missing, so scans return Docker Bench results only and the scanner panel reports "No SCAP content found". The same button appears in that state, labelled Retry install, and installs whatever is missing.
Upgrading SSG content on a host
When the server is upgraded to a newer PatchMon version with newer bundled SSG content, existing hosts may still have older content cached locally.
You do not normally need to do anything. A daily check compares each host's reported SSG version against the version bundled with the server and pushes an upgrade to any host that is behind, so the fleet converges on its own within a day of a server upgrade.
To push it to one host sooner:
- Call
POST /api/v1/compliance/upgrade-ssg/{hostId}(requires thecan_manage_compliancepermission). The server enqueues anssg_upgradetask and the agent downloads the currentssg-*-ds.xmlfor its OS from the server. - Poll
GET /api/v1/compliance/ssg-upgrade-job/{hostId}forwaiting,active, orcompletedwith a message.
Re-running Install Scanner from Host Detail also re-syncs content from the server as part of the install.
The Compliance Settings page always shows the currently-active server-side SSG version under OpenSCAP Content → SSG x.y.z.
Handling Stuck Scans
Any scan that has been in running status for more than 3 hours is considered stalled. A recurring cleanup job (ComplianceScanCleanup, triggered at POST /api/v1/compliance/scans/cleanup) marks every such scan as cancelled with the error message:
Scan terminated automatically after running for more than 3 hours
This prevents orphaned "forever running" scans from clogging the active-scans widget. The cleanup runs on a schedule driven by the recurring automation queue; administrators with can_manage_compliance can also trigger it on demand from the Automation UI.
Seeing stalled scans
The GET /api/v1/compliance/scans/stalled endpoint returns every scan older than 3 hours that is still marked running. If the Compliance page shows a Stalled Scans widget (rendered when any stalled rows exist), clicking a row links into the host's compliance detail so you can inspect it.
Why a scan might legitimately stall
- The agent crashed mid-scan. There was no opportunity to submit a terminal result.
- The agent lost network connectivity mid-scan. Results were generated but not submitted; by the time connectivity returned, the 3-hour window had passed.
- A profile on an unusually large host simply exceeded 3 hours (uncommon for L1, possible for L2 with heavy file-integrity rules on deep filesystems). The cleanup will fire; re-run the scan manually afterwards.
What the operator should do
If a scan was cleaned up automatically and you need results:
- Check agent health (
sudo patchmon-agent diagnosticson the host, or review the host's recent logs from the Host Detail page). - If the agent is healthy, Run Scan again from the Host Detail or Compliance Hosts tab.
- If scans reliably take more than 3 hours on a specific host (typically an extra-large file server), consider switching that host to an on-demand schedule so it only scans when you're actively watching.
Rate Limits
Agent-side submission of scan results is rate-limited to 10 submissions per minute per host at POST /api/v1/compliance/scans. Legitimate use never hits this: a host only submits once per scan. The limit exists to contain a misbehaving agent that tries to re-submit results in a loop.
Server-side scan triggers are not individually rate-limited beyond the general-auth rate limits you configure for the API, but asynq's worker pool naturally paces execution: a fleet-wide "scan everything now" will queue 100+ tasks and work through them at a sensible rate.
Related Documentation
- Compliance Overview: module gate, permissions, scanner architecture, bundled SSG content.
- Results and Remediation: what to do with scan results once they land.
- Docker Monitoring: the Docker integration you need for Docker Bench scans.
- Managing the PatchMon Agent: diagnostics and the Apply Pending Config flow used to push compliance settings.