What's in 9.12.0
TOD 9.12.0 closes two reported issues and lands a round of hardening across the API, the poller and the WinBox worker. Existing installations need one new environment setting; a script adds it.
Event-stream connections
The API now releases its event-stream connection to the message broker whenever a browser disconnects, including when the client goes away mid-stream. Previously a reconnect could leave a connection behind, and on a busy installation the API ran out of file descriptors within a day (#18). The browser no longer closes and reopens its event stream every 25 seconds; it stays connected and reconnects only when the stream actually drops, and the connection badge reflects that. The API container also gets the same file-descriptor headroom as the poller.
RouterOS 7.18 and later
RouterOS 7.18 introduced a new reply for commands that return no rows. The poller's RouterOS library did not recognise it, so an empty wireless registration table logged “unknown RouterOS reply word” every cycle and could leave later commands in the same cycle reading the wrong reply, which emptied Monitor > Wireless (#11). The library is updated and a protocol test covers the empty-table case.
Authorization and API keys
Tenant-scoped checks are applied consistently across firmware jobs and rollouts, alert channels and targets, configuration backups, the alert evaluator and the backup scheduler. The roles a user may assign are limited to the application's own roles. Changing alert channels requires the new alerts:write API-key scope, which the API keys page offers, and channel URLs are shown as host and port only.
Poller
The adoption probe reports timeouts and connection resets as what they are instead of as TLS failures, treats “incorrect login” as an authentication failure, and in auto and insecure modes confirms the plain-text alternative without the device's real credentials. SSH host keys are pinned on first contact and never replaced silently; a pin cleared in the database takes effect at the next backup.
WinBox worker
The worker's control API requires a shared secret, WINBOX_WORKER_TOKEN, which the API presents. The browser reaches the WinBox client only through the API's per-session routes, which check the session cookie, the tenant and the session owner; the worker publishes no host port and the frontend's direct /xpra/ route is gone. WinBox starts through an owner-only launcher rather than with credentials on its command line. Keyboard input in the embedded client is reliable on the first session; it could previously be lost until the session was reopened.
Updating
Before pulling 9.12.0, run python3 scripts/upgrade_env.py in the installation directory. It appends WINBOX_WORKER_TOKEN with a generated value to .env.prod, backing the file up first; the API and the worker refuse to start without it. Then pull all four images and recreate the containers. A custom reverse proxy needs no /xpra/ route any more and must forward WebSocket upgrades on /api/; the bundled examples are updated. No database migration. See the update instructions.
Verification
New automated tests cover event-stream teardown under client disconnect, the RouterOS empty-reply protocol, tenant-scoped access across the affected endpoints, the probe and host-key behaviour, and the worker's authentication, validation and launcher. On a hAP ax³, the release images adopted the device, opened Remote WinBox through the new API route with working keyboard input, and upgraded it from RouterOS 7.20.6 to 7.24.5 from the Firmware page.