github LanternOps/breeze v0.104.0

latest releases: v0.116.0, v0.115.0, v0.114.0...
one month ago

Breeze RMM v0.104.0 — Quick Support sessions for agentless machines, two-person approval for high-stakes AI actions, third-party patch auto-approval on Update Rings, and a deep round of backup and connection-pool reliability work.

Summary

  • Quick Support — one-time-code remote sessions on machines with no agent installed, via a small self-destructing client. (#3153)
  • Two-person approval for AI actions — Tier-3 actions split into supervised (self-approve in chat) and four_eyes (a second admin must approve). (#3175)
  • Third-party patch auto-approval — a first-class Update Ring control with severity gating and a hold-after-release delay. (#3150)
  • Backup: VSS snapshots actually work now — the COM vtable indices were wrong, so locked-file capture never functioned; verified end-to-end on real Windows hardware this cycle. (#3005, plus #3030, #3029, #3012, #3003)
  • Connection-pool reliability — a watchdog that tells pool poisoning apart from a down database, held-connection warnings that name the caller, and worker DB contexts scoped to their statements. (#3224, #3221, #3222, #3220, #3235, #3024)
  • Partner-wide script writes now require full partner org access — closing a privilege gap for selected-access partner users. (#3263)

Added

  • Quick Support — generate a one-time code from /remote; the end user downloads a self-destructing client from /quick that redeems the code for a single session on an ephemeral device, then cleans itself up. (#3153)
  • Supervised / four-eyes approval scopes for Tier-3 AI actions — routine device work (run a script, restart a service) is self-approved by the requesting human with one click; financial issuance, tenant-shape changes, and M365/Google identity mutations require a second approver. Unclassified actions fail safe to four_eyes. (#3175)
  • Third-party auto-approval on Update Rings — per-ring severity gating and a "hold after release" delay for third-party app updates, replacing the legacy rule category (existing rules are converted by migration, with counts logged). (#3150)
  • VSS writer health on the device Backup tab — per-writer states and unprotected volumes, live from the last job. (#3030)
  • partial backup status — runs with a disproportionate number of unreadable files land as partial instead of reporting success. (#3012)
  • Chunked software package uploads — byte-accurate progress and mid-flight cancel; large packages no longer ride a single request. (#3113)
  • WAN/LAN IP columns on the devices list, sortable and persisted. (#2996)
  • Procurement / order tracking on accepted quotes — mark lines ordered, partly received, received, or cancelled; export CSV. (#3111)
  • Event-loop lag monitor — a stalled API main thread is reported as such (log + Prometheus gauges) instead of masquerading as a Postgres CONNECT_TIMEOUT. On by default. (#3024)
  • Connection-pool health watchdog — distinguishes pool poisoning (an API restart fixes it) from the database being unreachable (it won't), exposed via breeze_db_pool_health* metrics. On by default. (#3224)
  • apple-app-site-association is served, enabling iOS password-manager autofill for the mobile app. (#3171)

Improved

  • Duplicate enrollment is idempotent — re-enrolling an existing hostname returns 201 with a possible-replacement linkage persisted on the device (surfaced as a badge in the devices list), instead of failing with 409. (#3063)
  • The whole patch catalog is pageable — more than 200 pending patches can now be viewed and bulk-approved. (#3195)
  • SNMP polling backs off failing devices — the due-check runs off poll attempts with exponential backoff (5 min → 60 min cap), instead of re-polling an unreachable device every tick forever. (#3223)
  • Stale-execution reaper honours each script's own timeoutSeconds — long-running scripts are no longer failed at a flat 10 minutes, and short-timeout scripts no longer sit pending past their contract. (#3213)
  • Held-connection warnings name the opening caller (file:line), turning a needle-in-haystack hunt into a grep. (#3221)
  • /ready is evaluated per request instead of latching a boot-time snapshot, so a Redis/DB recovery is reflected without an API restart. (#2985)
  • Session expiry is handled cleanly — expiry notice on the login page, idle warning, and return-to-page after re-login. (#3086)
  • Update Ring and config-policy UIs: features column with human-readable badges, timezone picker search, enrollment-key capacity display. (#2978, #2977, #2993, #3045)

Fixed

  • Backup: VSS snapshot creation was completely broken — wrong IVssBackupComponents vtable indices meant locked-file capture never worked on any Windows device. Verified fixed on real hardware. (#3005)
  • Backup: system-state staging targeted a nonexistent snapshot path and degraded collection now surfaces a warning to the operator. (#3029, #3025)
  • Backup: helper death is reported within seconds instead of waiting ~10 minutes on the stale reaper. (#3003)
  • Dynamic device groups no longer blank the groups page — a phantom legacy rule stub plus an unguarded field read unmounted the whole island. (#3179, #3181)
  • AI chat answers while an approval is pending — a pending Tier-3 intent no longer mutes the assistant. (#3104)
  • Billing/catalog AI tools were unreachable from in-product chat — the Tier-2 read-only tool set is now contract-tested against the chat tool registry. (#3176)
  • AI token accounting — cache-read/creation input tokens are counted, and partner-scope users no longer show zero usage. (#3180, #3103)
  • Remote desktop start no longer self-collides — per-request IPC ids replace a shared constant. (#3194)
  • The reaper no longer stamps "no response from agent" on commands the agent answered. (#3172)
  • Automation script output is persisted for automation-triggered runs and shown in Run History. (#3186)
  • UniFi integration — manual type_source respected on reconcile, and collector-agent pickers show real device names with site gating. (#3185, #3184)
  • PAM elevation approvers exclude disabled and invited users. (#3183)
  • Enrollment-key "Hide expired" filter agrees with the status badge, and "Delete expired" spares keys with live installer tokens. (#3196, #2982)
  • A malformed device id returns 404 instead of 500. (#2970)
  • pnpm db:migrate actually applies migrations again (was a no-op wrapper). (#3070)

Security

  • CVE-2026-59870 — js-yaml pinned to >=4.3.1 <5.0.0 (quadratic CPU in !!omap resolution). Upper-bounded deliberately to stay a patch bump. (#3212)
  • CVE-2026-67213 — nanoid pinned to >=3.3.17 <4.0.0 (infinite loop); reachable via the mobile app's runtime dependencies. (#3241)
  • CVE-2025-71329 / -71330 — image-size DoS: no upstream fix exists. Sole dependent is metro (React Native bundler) — build-time only, never in a shipped image. Accepted in .trivyignore with justification and removal criteria. (#3241)
  • CVE-2026-18446 fast-uri → 3.1.5; CVE-2026-69152 brace-expansion → 5.0.9; RUSTSEC-2026-0221 event-listener → 5.4.2.
  • Partner-wide scripts require the partner-wide capability — a partner user with org_access = 'selected' could create, edit, or delete partner-wide scripts (which run as SYSTEM on every org under the partner, including orgs they hold no grant for). Create/edit/delete are now gated on full partner org access, matching every other partner-wide resource, and the web UI no longer offers the option to users who lack it. (#3263)
  • Sentry scrubs transaction events too, so a sampled trace can no longer ship a live API key. (#3081)
  • Plaintext threat-signature strings are no longer embedded in shipped agent binaries (they tripped AV heuristics); verified absent by string-scanning the release binary. (#2973)
  • Cloudflare Access logout redirect fails closed instead of trusting Host. (#2976)
  • redactLogFields no longer drops fields or reprototypes on __proto__. (#3164)
  • FORCE_HTTPS / proxy-trust misconfiguration is surfaced at the redirect itself. (#3067, #2988)

Self-hosters are encouraged to upgrade.

Known issues — backup (read if you rely on file backup)

Release QA verified the backup fixes on real Windows hardware, and found three problems that are not fixed in this release:

Update: all three are now fixed on main and ship with the next release. The fix for each is noted inline below; the workarounds still apply while you're on v0.104.0.

  • Large file sets don't report completion (#3001) — a 4,000-file run completes on the agent (files are stored) but the result never reaches the server, so the job is eventually marked failed by the reaper. ~1,200 files is fine; the threshold is between. Fixed on main (#3267) — the result is bounded to what the server accepts, and a rejected result is now logged loudly instead of vanishing. #3283 also raises the result payload cap from 1 MB to 5 MB (matching stdout/stderr), fixing restore browsing for backups with roughly more than 13,000 files.
  • Permission-denied files cost ~30 seconds each (#3259) — the fast-skip added in #3002 covers cloud-file placeholders but not plain NTFS ERROR_ACCESS_DENIED. Fixed on main (#3266) — plain ACL denials now take the fast-retry path too, so they cost milliseconds instead of ~30 seconds.
  • Enough denied files can destroy the whole backup (#3260) — the stalls can outlive the VSS shadow copy, after which every remaining healthy file fails too. In one reproduction, 15 denied files out of 40 produced a backup of zero files. Fixed on main (#3266) — a lost VSS snapshot now aborts the backup immediately and loudly instead of silently producing a bad backup.

Until you're on the next release: keep backup selections tight, exclude folders you know are permission-restricted, and confirm jobs reach completed rather than trusting the absence of an alert.

Self-Hosting / Upgrade Notes

No breaking changes. Standard upgrade:

# bump BREEZE_VERSION in .env, then:
docker compose pull api web portal && docker compose up -d binaries-init api web portal

(If you build from source, run pnpm install — dependency overrides changed.)

1. Check two env var values before you pull — a typo now refuses to boot

IP_ALLOWLIST_ENFORCEMENT_MODE and AGENT_AUTO_PROMOTE were declared but silently excluded from validation, so a typo (Off, disabled, falze) quietly fell back to a default. They are now validated (#2979) — the API refuses to start and names the variable. Valid values are unaffected:

grep -E '^(IP_ALLOWLIST_ENFORCEMENT_MODE|AGENT_AUTO_PROMOTE)=' .env
# IP_ALLOWLIST_ENFORCEMENT_MODE: enforce | off | (empty)
# AGENT_AUTO_PROMOTE:            true | false

2. Database — 19 migrations, no large-table rewrites

All idempotent, auto-applied on API boot via autoMigrate (unless AUTO_MIGRATE=false). No backfill touches a hot table; the one index on a large table is built CONCURRENTLY so it doesn't block writes. Five migrations write data and log row counts via RAISE WARNING (visible in your Postgres log):

Migration What it changes
2026-08-08-drop-custom-alert-conditions Deletes/deactivates dead custom alert rules. The retired condition type never had an evaluator and could never fire; rules whose conditions were all custom are deleted (config-policy) or deactivated (alert_rules). Mixed rules untouched. If you built one, it disappears on upgrade.
2026-08-13-ring-third-party-auto-approve-backfill Converts legacy third-party patch rules to the new ring toggle
2026-08-14-intent-approval-scope-and-deadlines Adds approval scope to AI action intents; pre-existing pending intents default to four_eyes (the stricter path)
2026-08-15-intent-release-lease-backfill Backfills execution leases on already-approved intents
2026-08-15-snmp-poll-attempt-backoff Seeds last_poll_attempted_at from last_polled

3. No new required environment variables

Every new variable is optional with a built-in default, and all are mapped in the shipped compose files:

  • DB_POOL_HEALTH_* (six knobs, #3224) — pool-health watchdog, on by default.
  • EVENT_LOOP_MONITOR_INTERVAL_MS / EVENT_LOOP_STARVATION_WARN_MS / EVENT_LOOP_MONITOR_DISABLED (#3024, mapped by #3238) — event-loop monitor, on by default. New boot log line [event-loop] Lag monitor started … and Prometheus gauges breeze_nodejs_eventloop_* on /metrics/scrape (alert on breeze_nodejs_eventloop_monitored == 0).

4. Behavior changes

  • Selected-access partner users can no longer create, edit, or delete partner-wide scripts (#3263). Full-access partner admins are unaffected. If a selected-access technician maintained partner-wide scripts before, a full-partner admin must take those over (or re-scope the scripts to specific orgs).
  • Duplicate hostname enrollment returns 201 instead of 409 (#3063), with the possible-replacement linkage persisted on the device row (not in the enroll response).
  • Pre-existing pending AI action intents become four_eyes after upgrade — they'll need a second approver or will expire.
  • Single-admin instances using four-eyes actions: approving your own four_eyes action requires a WebAuthn or hardware-key authenticator (assurance level 3) — password + TOTP is insufficient by design. Register a device under Settings → Profile first, or the approval returns 403 step_up_required.
  • Quick Support on plain-HTTP self-hosted stacks: the downloaded client derives https://<host>:<port> from its filename and cannot auto-connect over plain HTTP — pass --server http://… explicitly. (HTTPS stacks are unaffected.)

Full Changelog: v0.103.0...v0.104.0


What's Changed

Full Changelog: v0.103.0...v0.104.0

Don't miss a new breeze release

NewReleases is sending notifications on new releases.