github LanternOps/breeze v0.115.0

6 hours ago

Breeze RMM v0.115.0 — automatic network topology mapping, a single unified alert-delivery resolver, and billing profiles land as connected infrastructure, alongside disk cleanup that actually frees space and a broad bare-metal recovery hardening pass.

⚠️ Two behavior changes to read before upgrading:

  • POST /devices/:id/move-org now requires a step-up MFA grant while two-factor authentication is enabled (#6310, #6400, #6309). See Self-Hosting below.
  • Billing Profiles automatically converts every partner's legacy labour-rate configuration into billing profiles on upgrade — this can change what is billable for existing partners (#6393, #6422). Run the dry-run report before upgrading. See Self-Hosting below.

Summary

Network devices now assemble themselves into a live logical topology map from passive agent evidence — interfaces, routes, neighbor tables — with shared config templates and on-demand diagnostics (#5996/#5997 W01–M1). Alerting consolidation replaces the old per-channel "send to everything enabled" fallback with a single delivery resolver, a real Delivery page (Channels · Routing · Escalation policies), and the first pass of a legacy-alert-to-monitor converter (#6367 W05a–W05c1). Disk Cleanup v2 finishes: cleanup now permanently deletes and actually frees space, scans any fixed volume, and gains OS-native cleaners (Windows Disk Cleanup/DISM, macOS snapshots/Homebrew, Linux caches/journal) reachable from the UI and a new AI tool (#6326 W01–W05). Billing Profiles + Work Types replace scattered legacy rate fields with one Rates screen, minimums, and rounding (#4628/#4615 W01–W03). Partner Sending Domains let a partner send customer email from their own domain, ships dark until configured (#6180 W01–W06). Bare-metal recovery gets a Restore-as-VM VHDX path, a fix for cross-snapshot incremental recovery, and a 24-hour restore timeout ceiling. Device move-org now requires an interactive session and, with 2FA on, a step-up grant (#6301 W01–W03). A broad fix sweep (SNMP, monitors, backup, DR races, tenant-isolation edges) rounds out the release, alongside a five-PR hardening pass and helper-auth / script-parameter security fixes.

Added

  • Network topology mapping (#5996/#5997 W01, W02/M1): automatic logical site maps built from passive agent evidence, shared configuration templates appliable across many sites at once, automatic layout, and on-demand ping/traceroute-style diagnostics from the map. Ships agent-side collection code — full effect needs the updated agent. (#6028, #6115)
  • Disk Cleanup v2, W01–W05 (#6326): cleanup now permanently deletes instead of moving files into agent-local trash, so reclaimed space is real (#6346); scans and cleans any fixed volume, not just the system drive (#6360); the Disk Cleanup tab becomes a full select/execute/history workflow (#6366); new OS-native cleaners — Windows Disk Cleanup handlers and DISM component cleanup, macOS local snapshots and Homebrew, Linux package caches and journal — reachable from the tab and from a new system_cleanup AI/MCP tool, needs the updated agent (#6386, #6442).
  • Alerting consolidation, W05a–W05c1 (#6367): legacy alert-rule authoring frozen in favor of Monitors, with a "Create monitor" shortcut and a Recommended strip (#6381, #6392); one delivery resolver replaces the old implicit all-channels fallback, with a new Delivery page (Channels · Routing · Escalation policies) and a delivery preview (#6385, #6387, #6390); a composite monitor kind, conversion-ledger foundation, and the first legacy-rule-to-monitor converter (preview, equivalence check, convert/revert/retire) (#6394, #6395, #6416).
  • Partner sending domains (#6180 W01–W06): a partner can configure a custom sending domain and per-stream sender identities so customer email comes from their own domain, with DNS verification, test-send, delivery health, bounce/complaint webhook handling, and automatic suspension on sustained bounce/complaint rates. Dark until EMAIL_DOMAINS_PROVIDER is set. (#6194, #6196, #6199, #6211, #6208, #6217)
  • Branded transactional email: quote, invoice, portal-invite and ticket-notice emails now render as editable HTML templates instead of bare stubs. (#6088, #6089)
  • Billing Profiles + Work Types (#4628/#4615 W01–W03): one Rates screen replaces scattered legacy category/org rate fields; time entries can be tagged with a Work Type; billed time now reflects per-profile minimums and rounding. (#6347, #6393, #6422)
  • Bare-metal recovery: Restore-as-VM and DR rehearsal/failover can target a VHDX image directly, including Linux guest images, with a new DR plan step type (#6320, #6321); server-side manifest indexing lets recovery resolve cross-snapshot object references, superseding the interim hard-refusal guard shipped as a stopgap (#6487, #6469).
  • Device move-org step-up (#6301 W01–W03): moving a device between organizations now requires an interactive session, and, while 2FA is enabled, a single-use step-up MFA grant. See breaking-change note above. (#6310, #6400, #6309)
  • MFA required by default for new partners (#6305 W01), with an MfaPolicyOffBanner nudging existing partner admins who have it off. Existing partners are unchanged on upgrade. (#6308)
  • Admin → Users MFA status column (Enrolled / Pending / Overdue). (#5690#6257)
  • AI tool efficiency program, A-W01/A-W02/A-W06 + MCP B-W01: tool-selection capture/eval harness and baseline, registry metadata driving the system prompt, 13 new Tier-1 read tools closing API/AI-tool coverage gaps, and an MCP protocol refresh (version negotiation, tool titles/annotations, structured results, pagination). (#6345, #6341, #6414, #6406)
  • Fleet Designer one-click enable — sets itself up instead of requiring a manual detour through Settings → AI Agents. (#6218)
  • Curated device detail tabs: a focused primary tab row with items like Anomalies/Tickets surfacing automatically when they need attention, count badges, and a grouped "More" menu for the rest. (#6259)
  • QuickBooks: confirmed mappings now sync automatically in the background instead of requiring a manual click (#6082); confirming a mapping now pulls the customer's address into the org/site when Breeze has none on file (#6080); an "Owed QuickBooks operations" panel surfaces stuck-pending payment syncs (#6083).
  • Settings consolidation, W01/W02: Ticketing gets its own settings page; Billing splits into Defaults/Documents/Connections; tax-rate and invoice-footer resolution consolidated to one resolver each. (#6233, #6231)

Improved

  • Site and organization picker dropdowns now load every match instead of silently truncating around 50–100 rows — most consequentially in the "move device" dialog, where an unreachable target site previously blocked the move outright. (#6412#6459)
  • Disk Cleanup preview and history now show reclaimable bytes, not just a candidate count. (#6454)
  • Fleet Designer reports show "Not measured" for evidence sections it couldn't collect, instead of silently omitting them. (#5735#6079)
  • Consecutive-failure ceiling for service/process/network_check monitors raised from 20 to 100; policy-link inheritance gains cumulative/replace semantics. (part of #6370#6394)

Fixed

  • Bare-metal / DR: cross-snapshot incremental recovery no longer fails partway through after the target disk is already wiped (#6487, superseding #6469); a system-image rebuild can no longer report "completed" with no OS state applied (#6316); whole-machine restore/rebuild commands get a 24-hour timeout ceiling instead of being killed at 60 minutes (#5415#6434); DR execute failures now name the actual missing prerequisite instead of a generic error, and plan saves no longer partially apply (#6382#6440); bare-metal restore failures report a specific reason, and the post-restore health probe no longer flags template/one-shot systemd units as failures (#5479#6431); Windows bare-metal restores preserve Hidden/System/Sparse file attributes (#5407#6430); lab-found defects fixed — unsized VHDX target, refused-result surfacing, no longer converting a still-mounted disk image (#6404); closed two DR/bare-metal race conditions around stale-worker resurrection of terminal executions (#6322#6451); recovery session refresh is now bounded and single-flight instead of retrying per failed file (#5635#6256).
  • Backup: incremental backups were silently going full every time due to an unsatisfiable base-selection condition — now correctly pick a small delta (#6351#6439); retention could delete the full snapshot an active chain's differentials/logs still depend on — now held until no longer needed (#5421#6433); backup jobs that fail server-side schema validation now fail loudly instead of hanging in "running" (#5413#6424); uploads between 16 MiB and 100 MB to MinIO/S3-compatible storage over HTTPS now succeed, and a partial run no longer verifies as fully passed (#6350#6427); the file Restore Wizard is now reachable from the UI instead of requiring a raw API call (#6349#6453); backup helper processes that exit on their own or get replaced by a respawn are properly reaped instead of leaking as zombies (#5980#6255).
  • Monitors: a network_check monitor could raise duplicate alerts, or none if its alert device was offline — now raises exactly one (#6353#6410); http_check monitors ignored their configured expected status code (#6352#6409); restart_service actions lost their restart configuration on save (#6343#6380); monitors of kind "offline" never fired (#6342#6378); role/OS filters on monitor policy assignments were ignored (#6344#6377); editing a script-check monitor could silently lose the selected script (#6207#6254).
  • SNMP: GetMulti now surfaces packet-level errors instead of null values (#6020#6069); agent honors SNMPv3 profile credentials in network discovery instead of falling back to v2c (#6234#6250); a template change now enqueues an immediate poll instead of waiting for the next interval (#6209#6245).
  • AI / agents: a budget-enforcement race let two concurrent client-AI requests both pass the budget check before either was charged (#5557#6458); MCP tool calls returning an error payload were logged as successes, hiding real failure rates (#6408#6420); agent-proposed fleet writes approved by a technician failed to execute because they were mis-attributed to the AI agent instead of the approving human (#6200#6205); a newly created patch schedule could fire a backdated catch-up run before its own creation time (#6201#6204); a tool-output redactor was wiping legitimate non-secret data such as session counts and credential-presence flags (#6140#6324); organization-scoped roles could hold every AI permission and still be blocked from opening AI chat at all — added a dedicated ai_sessions:use permission (#6396#6399).
  • Network proxy now correctly rewrites root-relative and same-host links instead of breaking out of the proxy mid-navigation. (#5906#6067)
  • Remote desktop launcher now explains why a session was revoked instead of silently dropping to idle. (#6120#6240)
  • Login fails closed with 503 instead of a server error when Redis is unavailable at the MFA gate. (#6177#6241)
  • QuickBooks mapping picker shows the organization's name immediately after "Create new" instead of only after reload. (#6221#6236)
  • Organizations board: clicking a name opens its detail pane instead of navigating away. (#6215#6242)
  • Backup verification list surfaces the actual failure reason instead of a bare "failed". (#6146#6239)
  • Occurrences drawer shows a proper empty state (with next planned date) instead of a blank panel before the first sweep. (#6219#6237)
  • Automations can no longer be created with a newly-requested elevated run-as privilege; existing elevated automations are flagged with an "Elevated" badge. (#4918#6070)
  • AI Assistant no longer fails importing loose .ps1 scripts with no category; bundle imports show a proper success screen. (#6005)
  • Script library import can target "All orgs" (partner-wide), not just one organization. (#5002#6074)
  • A new hourly sweeper recovers script-verification proposals stuck in "executed" without completing verification. (#5641#6076)
  • Report edit page no longer caps at a narrow fixed width on wide screens. (#6210#6244)
  • Remote tool launcher no longer fails on devices with a numeric custom-field identifier. (#6191#6238)

Security

  • Helper (device) authentication now enforces the device-credential lifecycle, and partner trust review requests require partner-wide manage access (#6507).
  • Script parameter values are now rendered as data — never code — consistently across bash, PowerShell, and Python interpreter frames on the agent, including nested constructs (command substitutions, heredocs, f-string fields) (#6508).
  • PAM actuator gate scoped to its own route: an unmatched /devices/:id/* request now correctly returns 404, and the homebrew-bootstrap endpoint (previously unreachable on any stack without PAM_ACTUATOR_ENABLED set) is reachable again (#6504).
  • Resource-agnostic copy for the partner-wide write-denial message, so it no longer misleadingly says "policy" for non-policy partner-wide state like branding or trust review (#6293).
  • Persisted device-memory text read by the AI agent is now routed through the same untrusted-data sanitizer/delimiter used elsewhere, so it reads as data rather than instructions (#6294).
  • The startup check that the API's request-pool database role is unprivileged (no SUPERUSER/BYPASSRLS) now runs unconditionally in every environment instead of only when NODE_ENV=production, with an explicit, logged, production-refused break-glass opt-out for local dev (#6295).
  • Non-routable/private IP-range classification (SSRF guards on integration endpoints, outbound connect-time resolution) is now driven from one shared table instead of two hand-maintained lists that had drifted apart. (#6296)
  • CSV/TSV export escaping is consolidated to one implementation and now applied to header rows too, closing a header-injection gap in custom-field/SQL-alias-derived headers. (#6297)
  • Four dispatch paths (backup, software remediation, backup test-restore, sensitive-data scan) now re-check a device's current organization at dispatch time, closing a window where a device moved between orgs mid-flight could dispatch against the wrong tenant. (#5567#6073)
  • Automation dispatch now re-checks device organization at dispatch time and cancels in-flight CIS remediation on an org move. (SEC-118 — #5562)
  • Tenant offboarding: aborting a drain now locks queued uninstall commands before flipping tenant status, closing a race that could leave a stale uninstall command deliverable fleet-wide after an abort; the credential-mint path was also removed from the offboarding drain surface so a draining tenant's agent cannot mint a fresh, never-revoked credential set via rotation. (#3996#6222; #3997#6216)
  • Moving a device to a new organization now correctly follows its tickets' partner_id, and ticket assignees are re-validated after the move so a ticket cannot stay assigned to someone who has lost access. (#5551#6075)
  • Site-restricted monitoring routes no longer distinguish "exists but you can't see it" (403) from "doesn't exist" (404) — both now 404, closing an existence-oracle leak. (#5777#6133)
  • The MFA-assured-session contract is pinned, and partner-scope user invites can no longer reference organization IDs outside the caller's own partner (Strix scan finding). (#6299)
  • Dependency hardening and open Dependabot/Trivy/CodeQL cleanup. (#5938)

Self-Hosting / Upgrade Notes

Upgrade: bump BREEZE_VERSION in .env, then docker compose pull api web portal && docker compose up -d (or pnpm install when running from source).

⚠️ Before you upgrade — Billing Profiles conversion. The 2026-10-24-200200-labour-pricing-conversion.sql migration automatically converts every partner's existing legacy category/org labour-rate configuration into billing profiles at migration time. There is no toggle to defer this. It can change what is billable for existing partners: an org that had a rate configured but no explicit billable flag was previously silently non-billable and becomes billable at that rate after conversion, and orgs with no org-settings row move from "excluded from billing" to "billable, no rate" (surfaces as missingRate at invoice time rather than being silently skipped). Run pnpm --filter @breeze/api dry-run:labour-pricing before upgrading and review the "WILL START BILLING" section. A new time_entries:manage_billing permission is now required to hand-edit a rate or billable flag on a time entry from any surface; Partner Admin (*:*) is unaffected, other roles that previously did this need it granted explicitly.

⚠️ Breaking — POST /devices/:id/move-org now requires a step-up grant while two-factor authentication is enabled. The request must carry stepUpGrant, a single-use grant minted by POST /auth/mfa/step-up with operation: "device_move_org" and a resource of { deviceId, targetOrgId, targetSiteId, acceptCurrencyMismatch }. Requests without it receive 403 { code: "STEP_UP_REQUIRED" }. API keys and MCP tokens are refused outright (403 Interactive user session required) whether or not 2FA is on. Accounts with no enrolled MFA factor cannot move devices — enroll an authenticator app or passkey first. There are no web, mobile, AI-tool, or MCP callers of this route as of this release, so nothing in the product itself is affected; only scripted/API callers.

Site-restricted technicians (intentional): a technician limited to certain sites now loses an entire parent software deployment, not just its out-of-ceiling child results, when any target device sits outside their site ceiling — including multi-site deployments they created themselves. (#5545/#5777)

Migrations: 39 new migration files, all idempotent and auto-applying on boot via autoMigrate (unless AUTO_MIGRATE=false). Two worth calling out beyond the billing conversion above:

  • 2026-10-21-110000-filesystem-multi-volume.sql (Disk Cleanup v2 W02) changes device_filesystem_scan_state's primary key from (device_id) to (device_id, scan_path), backfilling from existing scan data. It ships paired with its writer-code change in the same release. Hosted Breeze replaces its single API container, so this is a non-issue there. On a multi-replica self-host, any old replica still draining after the migration applies will fail its scan-state upsert with 42P10 until it drains (the snapshot insert itself still succeeds); re-running the scan once every replica is on the new build repairs the state. Single-replica self-hosts are unaffected. The follow-up migration 2026-10-22-160000-filesystem-scan-path-not-null.sql contracts the column to NOT NULL and promotes the composite key.
  • 2026-10-24-110100-topology-m1-runtime.sql backfills site_id on network_monitors from discovered-asset data, and deactivates any monitor whose device/asset association no longer resolves to a valid site — a small number of orphaned network monitors can go inactive on upgrade. Row counts are logged.

No new required environment variables. New optional env vars, all defaulted/off unless explicitly configured:

  • EMAIL_DOMAINS_PROVIDER (+ EMAIL_DOMAINS_STATIC_ALLOWED, EMAIL_DOMAINS_RESEND_API_KEY, EMAIL_DOMAINS_RESEND_SENDING_KEY, EMAIL_DOMAINS_REGION, EMAIL_DOMAINS_MAX_PER_PARTNER, EMAIL_DOMAINS_DAILY_SEND_CAP, EMAIL_DOMAINS_PARTNER_ALLOWLIST, EMAIL_DOMAINS_DENYLIST, EMAIL_DOMAINS_WEBHOOK_SECRET, EMAIL_DOMAINS_AUTOSUSPEND_*) — unset (the default everywhere, hosted and self-hosted) means the sending-domains feature is fully dark: the settings tab is hidden, its routes 404, its worker never registers, and every email sends exactly as before.
  • BREEZE_ALLOW_UNSAFE_DB_ROLE — a break-glass opt-out for the now-unconditional (previously production-only) startup check that the API's request-pool database role is unprivileged. Prints an unmissable banner on every boot when set, and is ignored entirely when NODE_ENV=production. Deliberately absent from .env.example and every compose file.

Disk Cleanup v2's new OS-native cleaners and the system_cleanup AI/MCP tool need an agent at v0.115.0 or newer; older agents return 409 agent_update_required. Network topology mapping's collection needs the updated agent for full effect.

No other breaking changes.

Full Changelog: v0.114.0...v0.115.0

What's Changed

New Contributors

Full Changelog: v0.114.0...v0.115.0

Don't miss a new breeze release

NewReleases is sending notifications on new releases.