Skip to content

Release v0.12.0

Latest

Choose a tag to compare

@github-actions github-actions released this 25 Oct 18:11
· 1 commit to main since this release

Release Notes v0.12.0

Released: 2026-10-25

The big addition in 0.12.0 is mouse and touch input across the whole TUI, so unifly tui can run on a touchscreen kiosk. Most of the rest is correctness work. In unifly-api, commands no longer hang on dead connections, network updates are no longer silently dropped, and the CSRF token is kept current. Config handling no longer loses profiles or leaks secrets. --demo now actually hides PII. CLI output and exit codes have been tightened, and rustls is bumped to fix four security advisories.

🌟 Highlights

✨ Mouse and Touch Input in the TUI

You can now click or tap tabs, list rows, key hints, dialogs and dashboard panels. One tap selects a row and a second tap opens it. An open device detail follows a tap on another device and stays on the same tab, so you can step from switch to switch and stay on their ports. Key hints work as buttons, including help, settings, quit and search in the status bar. Confirmations accept y/n taps, a tap outside an overlay closes it, and a tap dismisses a notification. The mouse wheel scrolls lists and the event feed (scrolling back pauses a live feed), zooms the topology and moves through the theme picker. Dragging pans the topology map. You still need a keyboard to type text.

🐛 Config Files No Longer Lose Profiles

Before this release, a single typo in config.toml (for example timeout = "thirty") made config set, config use, config init, cloud switch and TUI saves fall back to defaults and write them over every profile. These commands now stop with an error that names the file and the bad key, and leave the file untouched. config init adds a profile instead of replacing the file. The TUI edits the session's profile instead of always editing default. Saves are atomic: they write an owner-only staging file and rename it into place.

🔒 Secrets Stay Masked

config show now masks api_key, password, totp_command arguments and credentials embedded in URLs in every output format. Before, only the table view masked them. vpn servers and vpn tunnels no longer print pre-shared keys in clear text. The session cookie cache is now created owner-only under a unique name and renamed into place, which closes a symlink and race window.

🐛 --demo Now Hides Real Data

CLI controller and cloud commands in demo mode now exit 5 before connecting, because only the TUI sanitizes output. In the TUI, dialogs, toasts, the status bar, SSIDs/BSSIDs, event messages and the WAN details in the Gateway panel now use the same stand-ins as the lists. MACs, clock times and Rust paths no longer get turned into fake IPv6 addresses.

🐛 API Client Fixes

Commands sent while disconnected now fail right away instead of waiting forever. Calling connect() again no longer makes the next disconnect() hang. Network updates now apply subnet and DHCP changes. A NAT rule the controller rejects (an HTTP 200 response with an error body) is no longer reported as created.

🖥️ TUI Fixes

  • The tab bar draws all nine tabs from 74 columns up. Before, the WiFi tab (and Stats at some widths) was cut off on common terminal sizes.
  • Typing in the Networks edit form stays in the form. Tab, digits and q no longer switch screens or quit. Ctrl+C still quits.
  • An Esc that closes part of a screen (network detail, WiFi channel map, roaming focus) stays on that screen.
  • Tab in a client detail switches the type filter.
  • Firewall policy moves now reach the controller. Before, J/K on the Policies tab only swapped rows on screen. A move now reads the zone pair's ordering, steps the policy once and writes it to the controller. Moving past the system-defined block jumps over all of it, and the toast says so.
  • Lists keep their scroll position past the first page.
  • Search keeps its filter on Enter and clears it on Esc. / only opens search on Devices, Clients and WiFi.
  • The WiFi client detail and roam history follow the selected client, and retry failed fetches every 15 seconds.
  • Roam history loads under --demo with MAC redaction on.
  • The Stats screen reloads the period it shows and resizes its charts when you switch periods.
  • A paused Events feed holds still when new events arrive.
  • Clicks in the Settings form redraw immediately.
  • The status bar says "connecting" on the first connect and names the real cause of a failure.
  • The help overlay only lists keys that work everywhere. The Firewall hint bar no longer advertises Enter detail.

🔧 API Correctness (unifly-api)

  • last_full_refresh(), last_ws_event() and data_age() now return real values. Late subscribers see the correct connection state, and a failed connect reports Failed.
  • A non-ASCII response body no longer panics the error preview builder, which could crash the TUI's refresh task.
  • Network DHCP ranges show their end address. Turning DHCP off keeps range, lease and DNS settings. Turning DHCP on without a range is refused with a clear error.
  • NAT, WireGuard, VPN and unifly api requests now pick up rotated CSRF tokens and surface errors the controller returns with HTTP 200.
  • Platform detection probes now honor the configured TLS mode and --timeout, and run concurrently.
  • Timeout errors now report the configured --timeout value instead of "0s".

💻 CLI Output and Errors

  • YAML output stays valid and reads the same in YAML 1.1 parsers such as PyYAML. Apostrophes, booleans like off, nulls, 1_000, dates, << and = are now quoted correctly.
  • events watch -o yaml emits one --- document per event. acl reorder -o yaml emits a YAML list.
  • wifi channels renders data from multiple countries as one document, with country and country_code on each row.
  • topology -o json and -o yaml now emit structured data (gateway, devices with their clients, and clients with no uplink). Before, they printed the ASCII tree.
  • A malformed --filter is now a usage error (exit 2) that shows the accepted syntax.
  • -q silences the "Showing N of M results" hint.
  • UNIFI_INSECURE and --insecure accept 1/0, yes/no and on/off.
  • Missing credentials exit 3 with a hint specific to what is missing (config set-password, config set or --api-key).
  • wifi get reports the actual failure type instead of always saying "not found".
  • Error hints name commands that exist and the profile in use.
  • Unusable controller URLs (foo:bar, ftp://...) are now configuration errors (exit 2), with any password in the URL masked.
  • UNIFI_DEMO and UNIFI_DEMO_SEED no longer collide with the [demo] table and hide every profile.
  • Setup wizards store keyring secrets only after the last prompt, and put the old ones back if the save fails.

🔒 Security

  • rustls bumped to 0.23.46 for RUSTSEC-2026-0346 through 0349: TLS secrets exposed by Debug impls, data sent after an ECH rejection, a 1 GiB allocation during Brotli certificate decompression before authentication, and a ServerHello downgrade to classical key exchange.

📝 Documentation

  • The README now plays the 0.11 promo at the top. The tour GIF (docs/images/tui-tour.gif) has been removed.
  • The TUI, CLI, configuration, cloud and troubleshooting references and the agent skill files in crates/unifly/skill/ have been updated to match current behavior. This adds the U firmware-upgrade key, removes a promised PoE power cycle that no key triggers, and corrects what cloud mode allows.

⚠️ Breaking Changes

  • VPN JSON/YAML output no longer duplicates raw keys. Fields the typed record already has (localNetworks, peerIp, psk and similar) are no longer repeated under their raw names. Scripts should read the typed fields.
  • A broken config.toml stops every command, even when the controller and API key come from flags or environment variables. The command exits 2 and names the file and the problem.
  • Cloud fleet commands with no profile and no --api-key exit 1 (configuration error) instead of 3.
  • Demo mode now blocks CLI controller and cloud commands with exit 5. config, skill, completions and --demo-fleet still run.
  • A malformed --filter now exits 2 instead of matching nothing and exiting 0.
  • Invalid profile values and unusable controller URLs exit 2 instead of 1.

🔨 Upgrade Notes

  • Check that config.toml parses cleanly. A typo that older versions ignored will now stop every command until you fix it.
  • Update scripts that read the raw duplicate keys from vpn servers / vpn tunnels JSON or YAML.
  • Review CI or wrapper scripts that check exit codes for cloud commands, --filter, and invalid config or URL values.
  • If you set UNIFI_DEMO or [demo] enabled = true in environments that also run CLI commands, turn demo mode off for those runs.
  • If you scripted networks update --from-file with subnet or dhcp_enabled, those fields now take effect. Make sure the values are what you intend.