Skip to main content
PathMon

Chapter 15 of 26

Running Compliance Scans

Updated Read the full guide

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

  1. Open Hosts → select the host → Compliance tab (also reachable via Security Compliance → host row → host name link).
  2. 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).
  3. Click Run Scan. The UI calls POST /api/v1/compliance/trigger/{hostId} with profile_type=all (run every scanner enabled for this host).
  4. The button flips to a spinner with "Scanning…" and a toast confirms "Compliance scan triggered". The response includes a jobId you 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:

  1. On the Host Detail Compliance tab, expand the profile selector (if visible for your role) and choose a profile, for example, level2_server instead of the default level1_server.
  2. 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.
  3. Click Run Scan. The request body includes profile_type, profile_id, and enable_remediation.

From the Security Compliance Hosts tab

  1. Open Security ComplianceHosts tab. You see a table of every compliance-enabled host.
  2. 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.
  3. 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

  1. On the Hosts tab, find the row with the blue "Scanning…" indicator.
  2. Click the red StopCircle button in the Run column. The UI calls POST /api/v1/compliance/cancel/{hostId}.
  3. A toast confirms "Cancel request sent for host".

What cancel actually does

The CancelScan handler on the server does three things:

  1. Removes any queued run_scan task from asynq, so a scan that hasn't yet reached the agent won't start.
  2. Sets a compliance_scan_cancel flag 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.
  3. Sends a compliance_scan_cancel WebSocket 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. Manual Run Scan works.
    • Enabled, new hosts register ready for scheduled scanning.
  • Scan Interval: how often enabled hosts 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:

  1. Open Hosts → host → Integrations tab.
  2. Scroll to Compliance.
  3. Pick Disabled, On-Demand, or Enabled.
  4. 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:

  1. Choose a Profile Type. All Profiles, OpenSCAP Only, or Docker Bench Only.
  2. Tick Enable Remediation if you want OpenSCAP to apply remediation scripts during the scan.
  3. Tick the hosts you want to include (or Select All).
  4. 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.

  1. Enable compliance mode on the host (set to On-Demand or Enabled).
  2. On next Apply Pending Config, the agent receives the new integration state and reports that the scanner is not installed.
  3. From the Host Detail Compliance tab, click Install Scanner. The UI calls POST /api/v1/compliance/install-scanner/{hostId}.
  4. The server enqueues an install task. The worker sends an install message to the agent.
  5. 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 via GET /compliance/install-job/{hostId}, which returns the current state plus a per-step message and progress percent. The states are none (no install has been requested), waiting, active, completed, failed, and unknown when the job can no longer be found. A failed state also carries an error field with the reason.
  6. 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:

  1. Call POST /api/v1/compliance/upgrade-ssg/{hostId} (requires the can_manage_compliance permission). The server enqueues an ssg_upgrade task and the agent downloads the current ssg-*-ds.xml for its OS from the server.
  2. Poll GET /api/v1/compliance/ssg-upgrade-job/{hostId} for waiting, active, or completed with 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:

  1. Check agent health (sudo patchmon-agent diagnostics on the host, or review the host's recent logs from the Host Detail page).
  2. If the agent is healthy, Run Scan again from the Host Detail or Compliance Hosts tab.
  3. 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.


  • 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.