Auto-patch (opt-in per host)
Auto-patch lets monsys handle CVEs autonomously on hosts that explicitly opt in. Without this flag monsys never patches automatically — that’s the default and how the rest of the platform behaves.
When to enable
Section titled “When to enable”- Hosts where a minute of downtime is acceptable (install → optional restart)
- Hosts where you trust distro-maintainer QA (Ubuntu/Debian/RHEL security updates)
- Fleet layers you no longer want to patch manually (dev boxes, staging, CI runners)
Don’t enable on:
- Production DB primaries (patch after canary)
- Hosts where an app restart is a customer-facing hit (use the EAT flow with a maintenance window)
- Kernel updates (deliberately NOT auto-patchable — reboot risk)
What gets patched
Section titled “What gets patched”| Category | Source | EAT action | Restart? |
|---|---|---|---|
| OS packages | apt / dnf / apk / zypper | install_package per (package, version) | handled by the package manager |
| Application deps | npm / pip / composer / RubyGems / Go | update_packages per (project, ecosystem) | install-only in v1 — no automatic service restart |
| Kernel | — | — | NOT auto-patchable in v1 |
Filtering:
fixed_version IS NOT NULL— only CVEs with a known fix- Severity ≥ configured threshold (CRITICAL or CRITICAL+HIGH)
acknowledged_at IS NULL— CVEs the operator previously dismissed are skipped- Max 25 packages per host per cycle — sanity cap against runaway
- Warmup: 2 minutes after hub start
- Interval: 30 minutes
- Per-host rate limit: at least 25 minutes since the previous tick
- Hosts with no open CVEs get touched too —
last_run_atupdate prevents re-polling
Enabling
Section titled “Enabling”Governance tab on agent detail → section Auto-patching (opt-in):
- Tick OS packages and/or Application dependencies
- Choose the minimum severity:
CRITICALorCRITICAL + HIGH - Click Save (TOTP) — a dialog asks for your TOTP code
- Confirmation + timestamp appears below the section
Disabling doesn’t need TOTP — flipping the flag back to false is by definition a safe fallback.
Attestation lifecycle
Section titled “Attestation lifecycle”Every phase of auto-patch produces an entry in the attestation chain.
| When | Entry kind | Payload |
|---|---|---|
| Flag flipped on host | remediation.auto_flag_set | os_packages, app_deps, min_severity, set_by, turned_on |
| Worker dispatches EAT | remediation.auto_proposed | category, package, target_version, cve_id, severity, eat_nonce, flag_set_by, flag_set_at |
| Agent reports success | remediation.auto_applied | eat_nonce, exit_code, note |
| Agent reports rollback | remediation.auto_rolled_back | same, with exit_code ≠ 0 or rollback note |
An external auditor walks from auto_applied → auto_proposed (via eat_nonce) → flag_set_by → auto_flag_set (via subject_ref = agent_id). Every autonomous patch is cryptographically linked to the user who gave consent.
Alerts
Section titled “Alerts”Every cycle always fires an alert, even on success:
- info —
Auto-patch dispatched: <pkg> → <version>on every EAT issued - warning —
Auto-patch rolled backon restart-fail or non-zero exit
That way you see in the standard alerts view which hosts run autonomously, even if you never look at the attestation chain.
Rollback
Section titled “Rollback”The agent-side wrappers (monsys-action install for OS packages, monsys-package-update for app deps) do:
- Snapshot — lockfile +
node_modules(or dpkg status for apt) is preserved - Install — the requested upgrade
- Restart (if
restart_serviceis set) — not present in v1 auto-patch - Rollback — if a
restartfails, roll back to the snapshot
If the install itself fails (dpkg config conflict, npm ERESOLVE): no rollback needed because nothing changed. Non-zero exit code comes back via PostEmergencyResult and emits auto_rolled_back.
Why v1 doesn’t auto-patch the kernel
Section titled “Why v1 doesn’t auto-patch the kernel”Kernel updates need a reboot to take effect. Reboots have side effects the wrapper can’t roll back (services that don’t autostart, filesystem mounts, network config). The risk doesn’t outweigh the convenience — kernel CVEs are urgent enough that an operator can do a manual TOTP through the kernel-CVE pipeline with canary + verify.
Why v1 app-deps is install-only
Section titled “Why v1 app-deps is install-only”npm install swaps files on disk, but the running process has already loaded the old code. A service restart is needed to make the fix effective. In v1 there’s no automatic mapping from (project_path, ecosystem) → systemd unit, so we don’t force a restart that could be wrong. The patch is staged; the operator restarts when convenient. A future restart_service field per project can make that linkage explicit.
Compared to Root/Aikido and OS auto-updates
Section titled “Compared to Root/Aikido and OS auto-updates”- Root (Aikido) does hardened container images — dependency-level, drop-in replacement. Complementary, not competitive. If you run containers: Root for the images, monsys for the host.
- Ubuntu unattended-upgrades / dnf-automatic patch OS packages too, but without attestation, without centralized policy, without a rollback-alert loop. Monsys auto-patch is useful on distros where unattended-upgrades gives too little context for NIS2/CRA audit.
SQL schema
Section titled “SQL schema”agents has (mig 113):
auto_patch_os_packages BOOLEAN NOT NULL DEFAULT FALSEauto_patch_app_deps BOOLEAN NOT NULL DEFAULT FALSEauto_patch_min_severity TEXT NOT NULL DEFAULT 'HIGH' CHECK IN ('CRITICAL', 'HIGH')auto_patch_enabled_by UUID REFERENCES users(id)auto_patch_enabled_at TIMESTAMPTZauto_patch_last_run_at TIMESTAMPTZThe partial index idx_agents_auto_patch_enabled keeps the worker query O(log n) on the enabled set regardless of total fleet size.
GET /api/v1/agents/:id/auto-patch— read (viewer role)PATCH /api/v1/agents/:id/auto-patch— write (admin role + TOTP purposeagent_auto_patch)
Body:
{ "os_packages": true, "app_deps": false, "min_severity": "HIGH"}All three fields are optional; only present ones are updated. enabled_by + enabled_at are only updated when you turn a flag on — turning off leaves those audit fields so the last consent actor stays traceable.