Breeze RMM v0.129.0: a ticket triage board with an in-place focus view, notices when a backup destination keeps failing, a tool profile and context window for each AI model, a System Health tab for platform administrators, customer portal self-registration by verified email domain, and security hardening across sign-in, backup and remote access.
⚠️ This release needs action on upgrade. Local backup destinations must now be private to the agent, and network shares are no longer supported as local destinations. Read Action required on upgrade under Self-Hosting / Upgrade Notes before you update the server or promote the agent.
Summary
- ⚠️ Action required on upgrade. Several changes in this release are deliberately strict. Read Action required on upgrade before you update the server or promote the agent.
- Ticket workspace: a triage board and a focus view (#11575).
- Triage board.
/ticketsis a full-width board with two-line rows: number and subject, then organization, requester and device. Owner, SLA ("8h 14m left", Breached) and age are on the right. Priority and type chips are neutral, so red on the board means a breach. - Focus view. Opening a ticket shows it in place, with an "All open · 3 of 9" strip.
j/kstep between tickets; Esc or Back returns to the board with the row and scroll position restored. The conversation gets the room, the composer is pinned, and a recipient line says who a public reply emails. - Situation column. The right column leads with the requester and the linked device's live state (online, signed-in user, active alerts, Remote in), then SLA, linked alerts and the checklist. Below 1024px the view becomes Conversation and Details tabs.
- Unsent drafts are kept per ticket while you move between tickets.
- Triage board.
- Backup: notices when a destination keeps failing (#11777, #11770, #11771).
- A failing backup destination opens one Connection health incident, sends one in-app notice to the partner's backup admins, and appears in the daily digest. It is on by default and has no setting.
- The backup dashboard shows one critical destination failing item when two or more devices on one destination fail for a reason that belongs to the destination.
- Failed jobs name a specific cause (store access denied, not found, clock skew, storage operation failed, upload session ended, helper stopped, and others) in the job list, the device tab and the overview.
- A run that the destination refuses now ends, and the failure names the store's error code (for example
AccessDenied).
- AI models: tool profile and context window (#11393: #11680, #11786, #11761, #11795, #11801).
- Tools and context. Under AI Providers & Models → Models → (model) → Tools and context, a partner can set a model's tool profile (Auto, Full, Standard, Minimal, Custom) and, on OpenAI-compatible endpoint models, a context window override.
- Auto uses the model's real window. Breeze learns an OpenAI-compatible model's context window from the endpoint's model list, or from a context-length rejection, and Auto picks a smaller tool set and a shorter prompt when the full set does not fit. Platform, Anthropic bring-your-own-key and catalog models are not changed.
- Per-feature verify. Verify on an OpenAI-compatible model now runs a round trip for each feature the model is assigned to, with stand-in tools. The drawer shows each result. Verify is real traffic billed by the partner's provider.
- A profile only changes which tools are offered to the model. Permissions, approvals and guardrails are unchanged. See Behaviour changes.
- System Health tab (#10958: #11561). Platform administrators get a Health tab at Administration → System. It shows the connection-health reconciler and digest, each per-kind heartbeat, and the queue counts for connection health, alerts and event dispatch. It reads Redis only, so it works without the monitoring overlay, and it refreshes only when asked.
- Customer portal: self-registration by verified email domain (#11383: #11679, #11746). This completes the item listed as still to come in v0.128.0.
- A person with an address at one of an organization's verified email domains can ask for portal access at
/request-access. They confirm a single-use link sent to that mailbox, valid for 30 minutes. - In approval mode the request joins the organization's access-request queue, which now shows whether the requester's domain is still verified. In instant mode the account is created and the person sets it up from an invite.
- Off for every organization until an MSP turns it on. The login page shows Request access only on a verified custom portal domain whose organization has self-registration on and at least one verified email domain. On the shared portal host the page is reached by its URL.
- Still to come: Sign in with Google (in this release, switched off; see Added) and directory-driven provisioning.
- A person with an address at one of an organization's verified email domains can ask for portal access at
Added
- Sign in with Google for the customer portal: in this release, switched off (#11384: #11791, #11796). The API, the MSP settings row, the portal buttons and the docs are in place, and nothing appears until a server sets
PORTAL_GOOGLE_CLIENT_IDandPORTAL_GOOGLE_CLIENT_SECRET. Leave them unset until Google sign-in is announced as supported. See Environment variables and Known gaps. - Portal: a notice when sign-in falls back to password (#11594). When an organization's proven Microsoft tenant is lost while Microsoft sign-in was on, Breeze writes an
organization.portal_sign_in.password_fallbackaudit event and shows a notice on the Sign-in & registration card and on Organization → Domains, with the cause, the date, Re-run the tenant proof and Dismiss. The fallback itself is unchanged. - AI transcript retention settings, report-only (#4342: #11775, #11789). The partner and organization AI data-policy cards have a technician AI transcript window (365 days by default), and the AI for Office policy editor shows its own. Each field previews how many conversations are past the window. Nothing is removed in this release unless a server sets
AI_TRANSCRIPT_RETENTION_ENFORCE=true. See Behaviour changes. - Report-only retention jobs for high-volume tables (#4342: #11663, #11665, #11703, #11707, #11775). Five nightly jobs count the rows that are past their window in device commands, filesystem snapshots, network monitor results, device sessions, closed alerts, script executions, AI transcripts and eleven run and access history tables. They log a
REPORT-ONLYline, set thebreeze_retention_rows_eligiblemetric, and delete nothing. See Environment variables. - Possible reinstall detection (#8318: #10918). When a newly enrolled device matches an older record in the same partner by SMBIOS system UUID, by serial number and manufacturer, or by hostname, Breeze flags the new record as a probable reinstall and emits a
device.reinstall_suspectedevent. A built-in Possible Device Reinstall alert template is added; no rule is created, so alerting is opt-in. Nothing is reattached yet, and there is no screen for it yet. Hardware matching needs the 0.129.0 agent. - Agent: groundwork for reattaching a reinstalled machine (#8318: #10122). The agent can now carry out a signed, bounded identity rebind. Nothing uses it in this release: the server sends no directive until the reattach action ships.
- Breeze Assist branding and localization (#11204). Breeze Assist renders the configured locale (English and Brazilian Portuguese) and partner branding in its identity text: product name, welcome text, "Provided by", support and portal labels, window titles and the tray. The Helper tab of the Configuration Policies editor has the eight branding fields; blank inherits. Consent, elevation, approval and security text is localized only and cannot be replaced by branding. With no branding configured, Breeze Assist stays Breeze. See Known gaps.
- Sign-in welcome (#10272). After a successful sign-in the dashboard shows a short personalized welcome with the user's avatar instead of the credential form.
- Ticket import: Zammad 7.2.x module (#11296).
GET /ticket-imports/modulesnow listszammad. API only; there is no screen for ticket import yet. See Known gaps. - Portal API:
GET /portal/network/sites/healthreturns network health per site, behind the existing network visibility setting. The portal screen for it is not in this release (#11215). - API start on a read-only database (#11738).
/health/readyreportsdbReadOnlyand a singlereasonfield. See Behaviour changes. - Metrics:
breeze_retention_rows_eligible{job_name}(#11663) andbreeze_agent_eventlog_noise_dropped_total{event_id}(#11739).
Improved
- AI approval cards say what will happen (#11701). A ticket reply or note shows the ticket number and subject, who a public reply emails, and the message as plain text above Approve and Deny. A memory write shows what will be remembered and for whom. Approval requests name the ticket number and the device instead of ID fragments.
- Remote desktop: a missing permission is explained (#11666). A user whose role lacks
remote:accessnow sees why Connect Desktop is not available instead of "Connection failed". No role gains a permission. - Permanent device delete gives an actionable error. A deadlock, serialization failure or statement timeout answers a retryable 409, and other failures carry
code: DEVICE_PURGE_FAILEDwith a message the dashboard shows (#11657). - Windows Security event log volume (#11739). The API drops five high-volume Windows Security audit records (5038, 5157, 5152, 4957, 5061) before they are stored, and the 0.129.0 Windows agent collects a fixed list of audit events instead of every audit failure. Failed logons (4625), Kerberos pre-authentication failures (4771) and audit policy changes (4719) are kept. See Behaviour changes.
- Billing switched off for a partner is now honoured by background work: the contract billing sweep, hour-block close, scheduled quote sends, autopay and the autopay notices. Receipts, failure notices, reminders and overdue notices are still sent. There is no screen for the switch yet (#11124).
- Worker split: suspending, archiving, merging or offboarding a tenant, ending a Quick Support session and tearing down a remote session now close the agent's socket on whichever API instance holds it. Sixteen more background workers can run on the
workerservice (#11526). - Wisp (Breeze Cloud only): Wisp's standing state now carries what the user did to its check-ins and concerns in the last 24 hours, so it can say "you cancelled that check-in at 14:05" (#11759). The memory page marks a standing instruction that has passed its end date as Expired (#11700).
- Audit Trail uses the shared resource-type labels and UniFi action labels (#11696).
- Translations: original copy is restored for 95 strings that had been replaced by a humanized key, and placeholder strings have real copy across the 8 locales. The non-English text for 51 of them is machine-drafted (#11654, #11724).
- Mobile (Android): the build no longer asks for the overlay and storage-read permissions, which the app does not use (#11569). The store version is 1.0.5 (#11851).
- Agent build: the Go toolchain is 1.26.11 (#11708).
Fixed
- Custom roles: Inherit From now takes effect (#10641). A custom role's Inherit From parent grants its permissions at runtime, and every reader of privilege (approver lists, notification recipients, report access, access reviews) uses the same lookup. Removing an inherited grant ends live remote sessions and event sockets of the affected members. Members of a custom role that has a parent gain the parent's permissions on upgrade. See Behaviour changes.
- Backup:
- Remote desktop (macOS agent): a double-click from the viewer arrives as a double-click. Before, Finder treated it as two single clicks and started a rename. Needs the 0.129.0 agent. See Known gaps (#11670).
- Viewer (Linux): session windows now turn on WebRTC in the webview. This does not yet make the Linux viewer connect to devices whose agent runs as a service, which includes every Windows device: the WebKitGTK library that Ubuntu ships is built without WebRTC (#11642).
- Agent (Windows, security scans): quick, full and custom scans skip the agent's own compiled YARA rule cache, so a scan no longer reports its own rule files as threats. Needs the 0.129.0 agent. See Known gaps (#11748).
- Breeze Assist: "Using ..." lines settle to done or failed when the tool finishes instead of spinning (#11750).
- Microsoft 365: the Admin actions consent button now goes to Microsoft's approval screen instead of back to the dashboard (#11669).
- Customer portal:
- Login, forgot-password, the inbound-email sender lookup and the Outlook add-in sender lookup match a login's email address without regard to case. Where two logins differ only by case, each path refuses instead of choosing one (#11658).
- The Contacts list refreshes Roles after portal access is given, and removing the login removes the portal role (#11667).
- Sign-in: an SSO-only account with no passkey or authenticator app can now register an approver device after an SSO re-authentication (#11656).
- Billing: changing an organization's billing contact requires
billing:manage(#11683). - Quotes and tickets: catalog item ownership is validated on manual quote lines and ticket parts (#11682).
- Reports: decommissioned devices are no longer counted in report device populations (#11653).
- Alerts: patch failure details are kept up to 4,000 characters (#10965).
- Tickets:
- UniFi: partner-wide pickers list every organization the user can reach (#11695).
- Configuration policies: a tab whose Save was blocked now says why (#11661).
- Software Library: the Add Version form is validated on submit (#11660).
- AI chat: the typed message is kept when the session was closed elsewhere (#11668).
- Web: the organization switcher no longer overlaps at phone width, and the domain verification panel is no longer cut off (#11651). The AI Approvals legend lists Locks orgs (#11652).
- Wisp (Breeze Cloud only):
- A finished specialist's result reaches the next chat turn (#11752).
- Opening the Wisp pane on another page continues the thread's live session instead of starting a second one (#11751).
- A standing instruction is kept once per thread (#11742), and one that has passed its end date is no longer loaded into the session (#11700).
- "Tell me when this device is back online" schedules a check-in, not a watch (#11699).
- A check-in that should run an assessment is refused when no Triage agent can run it, and the post says why (#11662).
- Credentials are scrubbed from memory content before it is stored (#11697).
Security
Security — hardening
This release tightens checks across sign-in and account lifecycle, the Partner API, backup and recovery, remote tunnels, inbound email, the Outlook add-in and the agent. Self-hosters are encouraged to upgrade. Several of these changes are deliberately strict and need action on upgrade; read Action required on upgrade below before you update the server or promote the agent. (#11784, #11785, #11787, #11790, #11802, #11804, #11805, #11806, #11807, #11809, #11810, #11814, #11815, #11827, #11828, #11829, #11830, #11831, #11832, #11834, #11842)
Self-Hosting / Upgrade Notes
Action required on upgrade
Before you update agents
- Local backup destinations and local vaults must be private to the agent's service account. Earlier agents created local destinations, including the default
<data directory>/backups(/var/lib/breeze/backupson Linux), with mode0755. After the agent update, backup, restore, listing, retention, vault and bare-metal recovery operations against such a destination stop with "local backup store is not private" until it is migrated. The agent does not change the permissions of an existing destination. Migrate before updating agents: see "Local destination permissions" in the backup storage docs. The Windows default store under the Breeze data directory already meets the rule. (#11828) - Network shares are no longer supported as local destinations or vaults. UNC paths, mapped network drives and SMB or NAS shares are refused, and the SMB share vault type can no longer be created. A vault saved on a share can still be deactivated or deleted. Move these to a dedicated directory on an attached disk, or to S3-compatible storage. The path must be a dedicated directory, not a drive or filesystem root, with no link or reparse point in it. (#11828)
- If you redirect an old server hostname to a new one, update
server_urlon the agents first. Agents now follow a redirect only to the same scheme, host and port (an http to https upgrade on the same host is still followed). (#11785) - Update agents in stages. With
AGENT_AUTO_PROMOTE=false, a new agent release is registered but not promoted, so you can update a few devices, check their backups, and then promote. See "Controlled agent fleet rollout" in the upgrade docs.
Before you update the server
- Deploy the web app and the API together. The signup confirmation page now sends the password chosen at signup. (#11802)
- Deploy the API and the Outlook add-in together, so the add-in shows the new messages. (#11831)
- Do not start disaster recovery executions during the upgrade. Executions queued or running at upgrade stop with
execution_definition_unavailable; review them, because commands already sent are not recalled. Approvals granted but not yet carried out must be requested again. (#11805) BACKUP_LOCAL_ROOT(new, optional, self-hosted only). Server-side features for local backup destinations (connection test, file browse, verification, storage sweep, recovery downloads, recovery media) now read only from<BACKUP_LOCAL_ROOT>/<organization id>/<storage configuration id>/. Without it, those features pause for local destinations: the sweep skips them with a warning and deletes nothing, verification stays pending, and the connection test reports "Not tested here". Agents are unaffected. See the backup storage docs for setup steps, which move no data. (#11806)
After the upgrade, check
- Platform admins listed in
BREEZE_PLATFORM_ADMINS. An account is now promoted at API start only when it is active, its address is verified, it is a partner-level account and no other account shares the address. Accounts that already have platform-admin status keep it. Read the startup log warnings, and verify the address of any listed account that is not verified yet (POST /api/v1/auth/resend-verificationwhile signed in; needs a configured mail service). (#11834) - Partner API keys. A key whose owner has since been removed, deactivated, moved to a narrower role or limited to selected organizations is refused with
401 Invalid partner API credentialsuntil an admin who holds the needed access re-issues it or the owner's access is restored. (#11815) - Tunnel allowlist rules. A source rule written as a single address with no prefix length now matches only that address; widen it to the intended CIDR if users can no longer open tunnels. Stored IPv6 rules now apply. An IPv6 rule written with a host address and a short prefix (for example
2001:db8::5/32) stays inactive until it is rewritten. Agents that have not updated still ignore IPv6 rules, so IPv6 targets are refused on them. (#11787) - The inbound email review queue. Inbound mail is now attributed to the From header address, and a passing authentication verdict counts only when it is for the From domain. Expect more mail held for review (or dropped, where Drop mail that fails sender authentication is on) in the first days. Mailbox jobs queued before the upgrade are held for review, never dropped. For a ticket created from Mailgun mail whose recorded submitter differs from the customer's From address, a reply may no longer match the ticket by its subject token. (#11830)
Behaviour changes
- Custom roles and recovery credentials. Generating a bare-metal recovery token, creating a bare-metal recovery and reissuing a recovery code now need
devices:executeas well asbackup:write. Built-in roles are unchanged. Grantdevices:executeto a custom role that should keep this. (#11832) - Resending invites. An admin can resend a pending invite only for a role and sites they could invite; otherwise the request returns 403. (#11842)
- Site-restricted users can no longer create or control deployments, or change AI for Office mappings, policy and templates; they can still view deployments in their sites and retry their own failed devices. Deployment control buttons may still be shown to them and return 403. Patch package options and install-failure counts cover only devices in their sites. (#11790)
- Script Builder sessions are private to the user who started them. Mobile search returns only the result groups the caller has permission to open. (#11784)
- Sign-in lockout counts every password attempt before the password is checked, including attempts sent at the same moment. A member of a role can no longer turn off that role's MFA requirement. Pending email changes are cancelled by password reset or change, sign-out, removal and similar account events. (#11802)
- Outlook add-in linking follows the same rules as sign-in: lockout, the partner's SSO requirement and IP allowlist. Technicians at a partner that requires SSO, or outside the partner's IP allowlist, can no longer link the add-in with a password. Refusals return
401 invalid_credentials; the audit log records the reason. (#11831) - Removed accounts. Re-inviting a removed account, or setting it back to active or invited, starts it without platform-admin status and with its address unverified. This also applies to an account that never had a password (for example, SSO-only) when it is disabled and re-enabled. (#11834)
- Linux bare-metal recovery. The rebuild keeps the restored GRUB configuration and initramfs and no longer runs boot tools from the restored system. A restore onto different hardware may not boot if its initramfs lacks a needed storage driver.
grub-efiis no longer a required tool on the rebuild host. The new--restored-boot-toolsflags are accepted but always refused in this release. (#11829) - MSSQL restore under a new database name builds one statement with a
MOVEclause per database file. A database with many files (around 37 or more, depending on name and path lengths) fails with "sqlcmd: query is too long for one command line" and no database is created. Same-name restores are unaffected. Backup file paths with control characters are refused. (#11827) - Windows helper sessions are named after their verified account, as
DOMAIN\user. Message receipts and chat replies record that form. Notifications or script runs addressed toSYSTEMby name no longer reach a helper. While a domain controller is unreachable, only domain-qualified names are matched. (#11804) - Device file operations and scans accept only absolute local paths. UNC paths, device namespaces and relative paths are refused. Secure delete and encrypt refuse a file with other hard links. (#11814)
- Tunnels. The VNC tunnel type reaches only the local VNC endpoint. Under partner-trust enforce mode, a restriction ends open tunnels at their next check. (#11787)
- Huntress webhook. Every failure before the signature verifies now returns one
401 Webhook authentication failed; the reason is in the API log. Deliveries are limited to 600 per minute per source address. (#11810) - Selective restore can answer
503 index_query_timeouton a very large index; nothing is created. (#11810) - Images. PNG logos, quote images and signed-copy certificates over the size limits, or animated, are not decoded: a report shows the company name, a quote PDF leaves the image out, and a signed-copy download falls back to the original file. (#11807)
- Flows. For partner-wide flows, the active and running run limits now apply to each organization separately; monthly limits stay partner-wide. (#11807)
Upgrade command
Check how your install pins its images: grep '^BREEZE_API_IMAGE_REF=' .env.
- Digest-pinned (the value ends in
@sha256:…, which is everyguided-setup.shinstall from v0.112.0): fetch the currentguided-setup.shfrommain, then runbash guided-setup.sh --upgrade 0.129.0. It verifies the signed image inventory and updatesBREEZE_VERSIONand all four image digests together, then pulls and restarts. - Tag-form (the value ends in
:${BREEZE_VERSION}): setBREEZE_VERSION=0.129.0, then rundocker compose pull api web portal && docker compose up -d(andpnpm installif you build from source). If you run the optionalworkercontainer, pull and restart it too. - Do not edit only
BREEZE_VERSIONon a digest-pinned install. That re-pulls the images you already run. - Update the API, web and portal containers together. The new ticket board, the model drawer, the System Health tab and the portal request-access pages call routes the old API does not have. If you run the optional
workercontainer, update it with the API. --upgradedoes not change yourdocker-compose.yml. To pick up this release's new Compose mappings (listed under Environment variables), take the v0.129.0docker-compose.yml/deploy/docker-compose.prod.yml, or add the lines to theapiservice'senvironment:block yourself. A value that is only in.envdoes not reach the container.- See the Upgrade Guide.
Breaking changes
- ⚠️ Local backup destinations and network shares. See the first two items of Action required on upgrade above for what stops, who is affected and what to do.
- ⚠️ Do not roll the API back to v0.128.0 after this upgrade without restoring your backup. The upgrade drops the unused
patch_compliance_snapshotstable. A v0.128.0 API on the upgraded database fails organization erasure and organization merge, and the AI patch agent's evidence read fails. Recovery is to roll forward again (#11725). - No other change removes a feature on an install with default settings. Read Action required on upgrade, Behaviour changes and Other behaviour changes and feature flags for the changes that are strict by design.
Database
- 19 migrations. They are idempotent and apply automatically on first API boot via
autoMigrate, unlessAUTO_MIGRATE=false. Expect[auto-migrate] Applied 19 migration(s)from v0.128.0. No shipped migration was modified, renamed or removed. The set was verified to apply as a non-superuser role. - No table is rewritten and no large table is backfilled. Two things are worth planning for:
- Index builds on large tables. Seven files build 18 indexes with
CREATE INDEX CONCURRENTLY, ondevice_commands,network_monitor_results,device_sessions,alerts,script_executions,ai_agent_runs,patch_job_results,automation_runs,report_runs,user_notifications,remote_sessions,sessions,backup_jobs,ai_sessionsanddevice_hardware. Reads and writes continue during a build. Each build reads its table twice, so on an install with a long history the first boot can take from seconds to a few minutes per table;patch_job_resultsis likely the largest (#11663, #11665, #11703, #11707, #11775, #11777, #10918). - If a build is interrupted (for example the container is stopped mid-boot), it can leave an index marked INVALID. The next boot stops with a message that names it. Run
DROP INDEX CONCURRENTLY public.<name>and start the API again.
- Index builds on large tables. Seven files build 18 indexes with
- One table is dropped.
2027-01-24-150000-drop-patch-compliance-snapshotsdropspatch_compliance_snapshots. Nothing in Breeze ever wrote to it. The migration logs a warning with the row count if it finds any rows. This is one-way; see Breaking changes (#11725). - Short locks on busy tables. Two files take a brief exclusive lock under a 5-second lock timeout. If a long transaction holds a conflicting lock, the migration fails, the API exits, and the file runs cleanly on the next start:
2027-01-23-090000-device-possible-replacement-reasonadds two columns, a CHECK and a trigger todevices, and fills the two columns on rows that already carry a possible-reinstall link (#10918).2027-01-23-102000-alert-retention-fk-set-nullchanges two foreign keys intoalerts(fromlog_correlationsandnetwork_change_events) toON DELETE SET NULL, then validates each with one scan that does not block writes (#11665).
- Rows written.
2027-01-24-120000-ai-transcript-retention-columnssets the new technician transcript window to 365 days on every existing partner AI data-policy row; it has no effect while transcript retention is report-only (#11775).2027-01-23-090300adds the built-in Possible Device Reinstall alert template and creates no alert rule (#10918). - Other additions are nullable columns, columns with a constant default and CHECK constraints:
partner_ai_models(tool profile, allow-list and context window columns),ai_invocations(tool profile and exposure fingerprint),device_hardware.system_uuid,script_executions.output_purged_at,ai_sessions.transcript_purged_at,wisp_check_ins.cancelled_by, andportal_access_requests.google_hosted_domainwith its CHECK.2027-01-23-235000-role-inheritance-permissions-epochreplaces two trigger functions and writes no rows (#11680, #11761, #10918, #11703, #11775, #11759, #11791, #10641). - Rollback. Take a backup, or note a PITR point, before you upgrade. Rolling back to v0.128.0 keeps the new schema, and
patch_compliance_snapshotsstays dropped, so restore the backup if you roll back. Rollback was not tested.
Environment variables
- Required: none. No new required environment variables. The config validator refuses to boot only when one of the optional variables below is set to a malformed value.
- New, optional, in
.env.exampleand mapped in both Compose files (api, andworkerwhen split):BACKUP_LOCAL_ROOT: see Before you update the server above (#11806).PORTAL_GOOGLE_CLIENT_ID,PORTAL_GOOGLE_CLIENT_SECRETandPORTAL_GOOGLE_CALLBACK_BASE_URL(optional; falls back toPUBLIC_URL,PUBLIC_APP_URL,PUBLIC_API_URL): the customer portal's Google OAuth client. With them unset nothing changes: no Google row, button or copy appears and every Google route answers 404. Leave them unset until Google sign-in is announced as supported. Once the client is set, boot also needs a valid callback base. The only redirect URI to register ishttps://<your-breeze-domain>/api/v1/portal/auth/oidc/google/callback. The client id must be lower-case and end in.apps.googleusercontent.com; a malformed value stops the API at boot (#11384).PORTAL_SELF_REGISTRATION_ENABLED(true): set it tofalseto turn customer-portal self-registration off for every organization. Unset or empty means on; a value that is not true, 1, false or 0 stops the API at boot. Self-registration also needs a configured mail service (#11679).
- New, optional, mapped in both Compose files but not in
.env.example. These 54 belong to the report-only retention jobs. Leaving them out keeps the default. Each job counts and deletes nothing until its_ENFORCEvariable istrueor1. See "Report-only retention jobs" in the environment docs for each window.- Device telemetry (#11663):
DEVICE_COMMAND_RETENTION_*(120 days),FILESYSTEM_SNAPSHOT_RETENTION_*(7),NETWORK_MONITOR_RESULT_RETENTION_*(30) andDEVICE_SESSION_RETENTION_*(365), each with_DAYS,_BATCH_SIZE,_MAX_BATCHESand_ENFORCE. - Closed alerts (#11665):
ALERT_RETENTION_DAYS(365),ALERT_RETENTION_BATCH_SIZE,ALERT_RETENTION_MAX_BATCHESandALERT_RETENTION_ENFORCE. - Script executions (#11703):
SCRIPT_EXECUTION_OUTPUT_RETENTION_DAYS(90),SCRIPT_EXECUTION_RETENTION_DAYS(365),SCRIPT_EXECUTION_RETENTION_BATCH_SIZE,SCRIPT_EXECUTION_RETENTION_MAX_BATCHESandSCRIPT_EXECUTION_RETENTION_ENFORCE. - AI transcripts (#11775):
AI_TRANSCRIPT_RETENTION_BATCH_SIZE,AI_TRANSCRIPT_RETENTION_MAX_BATCHESandAI_TRANSCRIPT_RETENTION_ENFORCE. The windows are set in the AI data-policy settings, not here. - Run and access history (#11707):
HISTORY_RETENTION_BATCH_SIZE,HISTORY_RETENTION_MAX_BATCHES, and a_DAYSand_ENFORCEpair for each ofAI_AGENT_RUN_RETENTION_*(400),PATCH_JOB_RESULT_RETENTION_*(365),SECURITY_POSTURE_SNAPSHOT_RETENTION_*(365),CIS_BASELINE_RESULT_RETENTION_*(365),AUTOMATION_RUN_RETENTION_*(180),REPORT_RUN_RETENTION_*(365),USER_NOTIFICATION_READ_RETENTION_*(90),USER_NOTIFICATION_RETENTION_*(365),REMOTE_SESSION_RETENTION_*(365),SUPPORT_SESSION_RETENTION_*(365),AUTH_SESSION_RETENTION_*(30) andNETWORK_CHANGE_EVENT_RETENTION_*(90).
- Device telemetry (#11663):
- Changed meaning, no new name:
BREEZE_PLATFORM_ADMINS(see After the upgrade, check above, #11834). - Compose:
docker-compose.ymlanddeploy/docker-compose.prod.ymleach gain the same 66 lines in the sharedapienvironment block: the 54 retention mappings,BACKUP_LOCAL_ROOT, the threePORTAL_GOOGLE_*variables andPORTAL_SELF_REGISTRATION_ENABLED, plus comments. No mapping was removed and no service was added.
Other behaviour changes and feature flags
- Custom roles with an Inherit From parent gain the parent's permissions (#10641). On upgrade, members of such a role get the parent's permissions, and they start to appear in approver lists, notification recipients, report access and access reviews. The role editor already showed these permissions as held. To see which roles widen before you upgrade, run the read-only report
scripts/ops/role-inheritance-gain-report.sqlagainst your database:psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -P pager=off -f scripts/ops/role-inheritance-gain-report.sql. It returns one row per role that has a parent. A parent chain is followed for at most 8 levels, and creating or editing a role past that depth is refused. - AI tool profiles: Auto can narrow OpenAI-compatible models with no action from you (#11786). After the first model discovery sync (daily at 06:48 UTC, or a manual sync), a model whose endpoint states a context window gets the tool set that fits it. For example, chat on a 128k model moves to the Standard set, and an 8k model gets Minimal everywhere. A model whose window is too small for Breeze chat tools is refused at the start of the conversation with
409 context_window_too_small, where before the first request failed. The first request'smax_tokensis capped from the known window. To keep the full set on a model, set its profile to Full in the model drawer. Platform, Anthropic bring-your-own-key and catalog models are not affected. - AI tool profiles: a saved change restarts open conversations on that model at their next message; the user is asked to resend (#11801). A write that would take a required tool away from a feature the model serves is refused with
422 tool_profile_underpowered. - AI model Verify can now refuse one feature for a model (#11795). Only after an admin re-verifies an OpenAI-compatible model that is explicitly assigned to that feature, and it fails that feature's round trip. Existing verification records refuse nothing.
- Backup destination notices are on by default (#11777). Partners' backup admins (
backup:write) start to receive one in-app notice per failing destination, and the incident appears in Connection health and the daily digest. Only failures on the destination's current storage settings in the last 72 hours count. - Retention is report-only (#4342). Every
_ENFORCEvariable defaults tofalse. Review the nightlyREPORT-ONLYlog lines or thebreeze_retention_rows_eligiblemetric before you turn one on. WithSCRIPT_EXECUTION_RETENTION_ENFORCEon, script output is removed after 90 days and the dashboard shows "Output removed after the retention window". WithAI_TRANSCRIPT_RETENTION_ENFORCEon, conversations past their window are emptied to a stub and flagged conversations are held. - Customer portal self-registration (#11746).
PORTAL_SELF_REGISTRATION_ENABLEDdefaults to on, and each organization's self-registration mode defaults to off, so nothing is offered until an MSP turns it on for an organization that has a verified email domain. The/request-accesspage answers on any host and gives every address the same reply. MSP approval of a request re-checks that the requester's domain is still verified and answers409 PORTAL_ACCESS_REQUEST_DOMAIN_NOT_VERIFIEDif it is not (#11679). - Conflicting portal access requests (#11384). A Microsoft (or Google) portal sign-in in approval mode at an address that already has a pending request for a different identity (another account, another provider, or a pending self-registration) is now refused instead of silently keeping the first request. The portal tells the person a request for their address is already waiting (
/login?sso=request_pending) instead of the generic failure. The MSP denies the pending request, then the person signs in again. - Sign in with Google is off until
PORTAL_GOOGLE_CLIENT_IDandPORTAL_GOOGLE_CLIENT_SECRETare both set. Leave them unset. - Windows Security events (#11739). Records 5038, 5157, 5152, 4957 and 5061 are no longer stored, shown in the Events view, matched by
event_logmonitors or forwarded to a SIEM. The response to the agent's upload reports the count asnoiseDropped. Once a Windows device runs the 0.129.0 agent, it collects only the audit events on its list; NTLM credential-validation failures (4776) are not on it. /health/readyon a read-only database (#11738). It answers 503 with"dbReadOnly": trueand"reason": "db-read-only";/healthstays 200. With no migration pending, the API now starts against a read-only database instead of restarting in a loop, and withBINARY_SOURCE=localit reports"binarySyncPending": trueuntil the database accepts writes. With a migration pending it stops with an error that names the read-only condition. The API's 503 body now carries onereasonvalue (shutting-down,db,db-read-only,redisorworkers-pending).- Reports: decommissioned devices are no longer in report device populations, so device counts in reports can go down (#11653).
- Ticket queue age is measured from when the ticket was created; the tooltip shows created and updated. The
#caller-verificationhash on/tickets/[id]is gone (#11575). - Billing contact: changing an organization's billing contact needs
billing:manage(#11683). - Billing switched off for a partner: organization-scoped callers of the invoice and autopay routes are now refused while the partner's billing is off (#11124).
- Linux devices that reported a placeholder serial number (for example "To Be Filled By O.E.M.") record one serial-number change when they update to the 0.129.0 agent (#10918).
- API changes to check if you integrate:
POST /authenticator/register-grantacceptsssoReauthGrantId, and a rejected proof answers 400 instead of 401 (#11656).PATCH /ai/models/offerings/:idacceptstoolProfile,toolAllowlistandcontextWindowOverride(#11801). Model records carrycontextWindowandtoolProfile(#11786, #11801).- Session starts can answer
409 context_window_too_smallor409 tool_profile_underpowered(#11786, #11680). GET /ticketsrows includesubmitterName(#11575).- Backup job and dashboard routes return
failureCausebesidefailureCategory(#11770). GET /portal/auth/methodsreturnsrequestAccess(#11679) andgoogle(#11796).- Script execution reads return
outputPurgedAt, and AI session reads returntranscriptPurgedAt(#11703, #11775, #11789). - The AI data-policy routes carry
transcriptRetentionDays, and three…/transcript-retention-previewroutes are added (#11775).
- Wisp (Breeze Cloud only,
BREEZE_WISP_ENABLED): no default changed. - No flag in this release has to be turned on.
Known gaps
Verification gaps in this release. Stage your own rollout if one of these applies to you.
- macOS on Apple Silicon: the upgrade-in-place check (no permission prompt, helper reloaded, remote desktop working) was run on an Intel Mac on macOS 15 only. It was not run on Apple Silicon or on a second macOS version.
- MSSQL backup and restore (#11827): verified against SQL Server Express before merge; not re-run on the release build.
- Linux bare-metal recovery (#11829): a full rebuild and first boot was not run on lab hardware for this release. Test a recovery on your own hardware before you rely on it.
- Agent redirect handling (#11785): ordinary operation was checked on Linux and Windows agents; a redirecting proxy in front of the server was not.
- Not exercised for want of an external account or device: inbound email through a mail provider (#11830), Outlook add-in linking (#11831), Portal Sign in with Google (#11384; it stays switched off), Zammad ticket import against a live instance (#11296), the UniFi integration change (#11695).
- Tool profiles (#11393): the lab leg against a real small-context model was not run.
- The macOS Local Network prompt for the agent (#11311) was not lab-verified.
- The RDP-session preference of the Windows sign-in screen capture (#9583) is still not lab-verified.
- Breeze Assist branding and localization (#11204) was not checked on Windows. The Brazilian Portuguese strings of the System Health tab (#11561) are machine-drafted.
Known issues
- Breeze Assist on macOS stays in English when the system language is Portuguese (Brazil) (#11204).
- A partner API key that is refused because of its owner's access returns the general
401 Invalid partner API credentialsmessage (#11815). - Built-in H.264 encoder fallback: the picture can stay blocky after a burst of change on an otherwise static screen (#11639, still open).
- Linux viewer: it still cannot connect to devices whose agent runs as a service (#11642).
- Found during release testing, and older than this release: #11854, #11856, #11857, #11858.
What's Changed
- docs(qa): pre-release sweep — lab legs on v0.128.0-rc.2 by @ToddHebebrand in #11640
- docs(ai): approve small-model tool profiles spec + 5-wave plan (#11393) by @ToddHebebrand in #11400
- feat(api): ticket import W5 — the Zammad 7.2.x module (#8313) by @lennonflima in #11296
- feat(admin): System Health tab with shared background-work observations (#10958) by @fabicarvano in #11561
- feat(agent): reattach wave 1b-3 — the bounded rebind, agent side (#8318) by @lennonflima in #10122
- chore(deps): Bump the aws-sdk group across 1 directory with 5 updates by @dependabot[bot] in #10947
- chore(deps): Bump react-redux from 9.3.0 to 9.3.1 by @dependabot[bot] in #11459
- chore(deps): Bump tauri-plugin-shell from 2.5.0 to 2.6.0 in /apps/helper/src-tauri in the tauri group across 1 directory by @dependabot[bot] in #11130
- chore(deps): Bump vitest from 5.0.5 to 5.1.0 in /e2e-tests by @dependabot[bot] in #11438
- fix(viewer): enable WebRTC in the Linux webview; report whether the bundled WebKitGTK has it (#9557) by @ToddHebebrand in #11642
- docs(release-notes): clear the next-release draft after v0.128.0 by @ToddHebebrand in #11645
- docs: v0.128.0 release docs by @ToddHebebrand in #11646
- fix(web): AI Approvals legend lists Locks orgs (#11601) by @ToddHebebrand in #11652
- fix(web): phone-width org switcher overlap and cut-off domain verification panel (#11597 #11598) by @ToddHebebrand in #11651
- feat(auth): welcome users after successful sign-in (#10268) by @JonathanPitre in #10272
- feat(web): ticket workspace as a triage board and an in-place focus view by @ToddHebebrand in #11575
- feat(api): enforce billing_enabled in workers, autopay and notices (#8807, PR 3a) by @fabicarvano in #11124
- feat(helper): runtime branding and localization rendering (Phase 2, Wave 3) by @fabicarvano in #11204
- fix(web,i18n): restore original copy for 95 humanized-key regressions (#7376) by @ToddHebebrand in #11654
- test(agent): deflake bare-metal rebuild budget and collector pipe-cleanup tests (#9062) by @ToddHebebrand in #11655
- feat(api): add portal network site health endpoint (CPEV-W2) by @fabicarvano in #11215
- chore(deps): Bump @sentry/cli from 3.7.0 to 3.8.2 by @dependabot[bot] in #11456
- fix(api): SSO re-auth road for approver-device register-grant (#9007) by @ToddHebebrand in #11656
- fix(portal): case-insensitive login-email lookups for login, reset, inbound email and add-in (#11541) by @ToddHebebrand in #11658
- chore(agents): issue workers select by priority then age, not the 60 newest by @ToddHebebrand in #11648
- fix(api): actionable errors when permanent device delete fails (#11627) by @ToddHebebrand in #11657
- fix(web): validate the Software Add Version form on submit (#11606) by @ToddHebebrand in #11660
- chore(deps): Bump @playwright/test from 1.64.1 to 1.65.0 in /e2e-tests by @dependabot[bot] in #11440
- fix(web): pin device Tickets tab to the device's org (#11644) by @ToddHebebrand in #11650
- fix(web): reveal why a config-policy tab Save was blocked (#11554) by @ToddHebebrand in #11661
- fix(remote): explain a missing remote:access grant instead of "Connection failed" (#11621) by @ToddHebebrand in #11666
- fix(alerts): retain patch failure details up to 4,000 characters by @PJF16 in #10965
- chore(deps): Bump the github-actions group across 1 directory with 7 updates by @dependabot[bot] in #11448
- fix(ai): keep the typed message when the bound session was closed elsewhere (#11609) by @ToddHebebrand in #11668
- fix(reports): exclude decommissioned devices from report device populations (#11562) by @ToddHebebrand in #11653
- fix(relay): cross-process agent socket teardown; flip 16 workers global (#11507) by @ToddHebebrand in #11526
- fix(web): send M365 admin-actions consent to Microsoft, not the dashboard (#11572) by @ToddHebebrand in #11669
- fix(wisp): run-mode check-in refused when no Triage agent can run it; degraded post names why (#11610) by @ToddHebebrand in #11662
- ci(shepherd): budgeted re-queue and hold decisions, one local writer, shadow by default (#10750) by @ToddHebebrand in #11664
- test(api): fix two tests that time out on a loaded runner by @ToddHebebrand in #11681
- test(unifi): W4 Wi-Fi integration/rollout verification (#7690) by @fabicarvano in #11060
- feat(portal): audit event and admin notice when sign-in falls back to password (#11582) by @ToddHebebrand in #11594
- fix(agent): rebind tests wait for the flow's goroutines (race + restart-log flake) by @ToddHebebrand in #11689
- chore(deps): Bump @types/office-js from 1.0.615 to 1.0.616 in the typescript-tooling group across 1 directory by @dependabot[bot] in #11449
- fix(contacts): refresh Roles after portal access and drop portal role with the login (#11599) by @ToddHebebrand in #11667
- fix(agent): stop helper watchers before crashingAssist restores its test seams by @ToddHebebrand in #11693
- fix(agent): give synthesized macOS clicks a click state so double-click works (#11549) by @ToddHebebrand in #11670
- chore(deps): Bump the mobile group across 1 directory with 3 updates by @dependabot[bot] in #11447
- feat(agent,api): reattach wave 2-1 — hardware hints and reinstall candidates (#8318) by @lennonflima in #10918
- feat(portal): self-registration API, ships dark — W06a (#11383) by @ToddHebebrand in #11679
- fix(quotes,tickets): validate catalog item ownership on manual quote lines and ticket parts by @ToddHebebrand in #11682
- chore(deps): Bump @tiptap/pm from 3.32.0 to 3.33.0 by @dependabot[bot] in #11455
- fix(web): UniFi partner-wide pickers span all accessible orgs (#11604) by @ToddHebebrand in #11695
- docs(plan): W08 8A capture-feasibility spike — go/no-go finding (#10190) by @ToddHebebrand in #11705
- fix(web): Audit Trail uses shared resource-type and UniFi action labels (#11605) by @ToddHebebrand in #11696
- docs: end-user experience page and prompt updates (W09 9A, #10190) by @ToddHebebrand in #11706
- chore(deps): Bump @reduxjs/toolkit from 2.13.0 to 2.14.0 by @dependabot[bot] in #11460
- fix(wisp): lapsed standing instructions no longer load into the session prompt (#11630) by @ToddHebebrand in #11700
- docs(release): record lab checks owed before the next release by @ToddHebebrand in #11716
- fix(web): ticket composer attachments — permanent errors drop Retry, restored drafts warn (#11710, #11711) by @ToddHebebrand in #11723
- ci: W05 G3 prerequisites — nightly full run, runnable N3, shepherd thin faults (#10749) by @ToddHebebrand in #11709
- fix(web): real copy for humanized-key placeholders across 8 locales (#11553) by @ToddHebebrand in #11724
- chore(go): bump toolchain to 1.26.11 (GO-2026-6859 net/http fix) by @ToddHebebrand in #11708
- docs(macos): document the Local Network prompt for Breeze Assist by @ToddHebebrand in #11734
- feat(ai-models): tool profile record, resolver and surface floors — ships dark (#11394) by @ToddHebebrand in #11680
- chore(deps): Bump the expo-sdk group across 1 directory with 13 updates by @dependabot[bot] in #11452
- fix(agent,api): stop ingesting Windows Security Audit Failure noise (#11735) by @ToddHebebrand in #11739
- fix(wisp): a standing instruction is kept once per thread, not again on a later turn (#11614) by @ToddHebebrand in #11742
- chore(deps): Bump werift from 0.25.2 to 0.26.0 in /e2e-tests by @dependabot[bot] in #11446
- feat(api): report-only retention for device telemetry tables (#4342 W1) by @ToddHebebrand in #11663
- feat(portal): customer self-registration pages, queue badge and capability flip (W6b, #11383) by @ToddHebebrand in #11746
- fix(api): start against a read-only database when no migration is pending (#11731) by @ToddHebebrand in #11738
- fix(helper): settle tool-call indicators when the tool finishes (#11727) by @ToddHebebrand in #11750
- fix(wisp): opening the pane on another page continues the thread's live session (#11672) by @ToddHebebrand in #11751
- fix(wisp): a finished specialist's result reaches the next chat turn (#11671) by @ToddHebebrand in #11752
- test(wisp): exploratory-pass harness and scenario benchmark (known-red scenarios for #11671–#11678) by @ToddHebebrand in #11684
- fix(agent): security scans skip the agent's own YARA rule cache (#11728) by @ToddHebebrand in #11748
- docs(portal): W7 Sign in with Google implementation plan by @ToddHebebrand in #11758
- feat(api): report-only closed-alert retention (#4342 W3) by @ToddHebebrand in #11665
- feat(api): report-only script execution retention (#4342 W2) by @ToddHebebrand in #11703
- test(web): fix WispTalkButton tests failing on main since #11751 by @ToddHebebrand in #11763
- fix(backup): tolerate an unparseable x-amz-abort-date from S3-compatible stores (#11764) by @ToddHebebrand in #11767
- fix(billing): require billing:manage to change an org's billing contact by @ToddHebebrand in #11683
- fix(backup): end a run the destination refuses or whose session died; surface the store's error code (#11765) by @ToddHebebrand in #11771
- fix(backup): specific failure causes and a destination-level attention item (#11768) by @ToddHebebrand in #11770
- chore(deps): Bump twilio from 6.0.2 to 6.3.0 by @dependabot[bot] in #11457
- chore(deps): Bump the astro group across 1 directory with 4 updates by @dependabot[bot] in #10308
- fix(rbac): a custom role's "Inherit From" parent grants its permissions at runtime, and every privilege reader honours it (#9600, #11702) by @ToddHebebrand in #10641
- feat(api): report-only retention for run and access history (#4342 W5) by @ToddHebebrand in #11707
- feat(ai-models): W03 constrained prompt, compact descriptions, gateway schema compaction, prefix pins, ledger provenance (#11395) by @ToddHebebrand in #11761
- feat(backup): notify when a backup destination is failing (#11772) by @ToddHebebrand in #11777
- fix(wisp): standing state carries the user's actions on check-ins and concerns (#11611) by @ToddHebebrand in #11759
- fix(wisp): scrub credentials from memory content before it is stored by @ToddHebebrand in #11697
- fix(wisp): route one awaited event to schedule_check_in, not create_watch (#11685) by @ToddHebebrand in #11699
- fix(mobile): drop overlay and storage-read permissions from the Android build by @ToddHebebrand in #11569
- fix(ai): approval card shows the reply, the memory and the ticket number (#11674) by @ToddHebebrand in #11701
- feat(ai): report-only AI transcript retention, API and job (#4342 W4) by @ToddHebebrand in #11775
- feat(patches): drop the writer-less patch_compliance_snapshots table (retention W6.a, #11593) by @ToddHebebrand in #11725
- feat(web): transcript retention fields, previews and removed-by-retention viewers (#4342 W4) by @ToddHebebrand in #11789
- feat(ai-models): learn gateway context windows; auto tool profiles go live (W02, #11396) by @ToddHebebrand in #11786
- feat(portal): Sign in with Google, API half — ships dark (#11384 W07a) by @ToddHebebrand in #11791
- test(connection-health): stable index-plan contract on a production-shaped fixture (#11713) by @ToddHebebrand in #11794
- feat(portal): Sign in with Google, web + portal + docs — ships dark (#11384 W07b) by @ToddHebebrand in #11796
- feat(ai-models): per-surface verify with inert stubs; refused tool-batch measurement (W04, #11397) by @ToddHebebrand in #11795
- test(agent): bound backup helper-death waits by the condition, not 2 s by @ToddHebebrand in #11798
- docs(portal): W8 plan — directory deprovisioning (Entra complete snapshots, Google Directory) by @ToddHebebrand in #11799
- feat(ai-models): tool profile and context window in the model drawer — W05 (#11398) by @ToddHebebrand in #11801
- Read API-side local backup storage only from an operator directory by @ToddHebebrand in #11806
- fix(auth): tighten account lifecycle checks (sign-in lockout, signup confirmation, pending email changes, role MFA, access reviews, invite links) by @ToddHebebrand in #11802
- fix(api): apply site restrictions consistently to deployments, patch summaries, discovery, AI for Office and AI artifacts by @ToddHebebrand in #11790
- fix: bound the work the API does on large input by @ToddHebebrand in #11807
- fix(agent): quote generated PowerShell and cmd command lines consistently by @ToddHebebrand in #11809
- fix(agent,api): one set of path rules for device file operations and scans by @ToddHebebrand in #11814
- fix(agent): name helper sessions from their verified account; keep Request Support tied to the clicked prompt by @ToddHebebrand in #11804
- fix(dr): a DR execution runs exactly the plan definition it was approved and started with by @ToddHebebrand in #11805
- Don't hold database connections while calling other hosts; bound outbound requests, index walks and membership lock order by @ToddHebebrand in #11810
- fix(agent): keep agent credentials on the control-plane origin by @ToddHebebrand in #11785
- fix(api): keep Script Builder sessions and mobile AI search private to their creator by @ToddHebebrand in #11784
- fix(tunnels): IPv4/IPv6 allowlist rules, per-address destination checks, live partner-trust checks by @ToddHebebrand in #11787
- fix(office-addin): apply Breeze sign-in rules to add-in account linking by @ToddHebebrand in #11831
- fix(backup): require devices:execute to create recovery credentials by @ToddHebebrand in #11832
- fix(backup): bind MSSQL backup paths and MOVE values as variables and check restore inputs by @ToddHebebrand in #11827
- fix(backup): keep rebuild file operations inside the restored volume; run no restored boot tools by @ToddHebebrand in #11829
- fix(inbound-email): attribute inbound mail to the authenticated From address by @ToddHebebrand in #11830
- fix(partner-api): bound service principal keys by their owner's current access by @ToddHebebrand in #11815
- fix(backup): require private local backup destinations and refuse network shares by @ToddHebebrand in #11828
- fix(users): resend-invite applies the same rank and site checks as member management by @ToddHebebrand in #11842
- fix(auth): promote platform admins only from active, verified accounts by @ToddHebebrand in #11834
- chore(release): What's New entry for 0.129.0 and mobile store version 1.0.5 by @ToddHebebrand in #11851
Full Changelog: v0.128.0...v0.129.0