-
released this
2026-09-26 14:23:18 +00:00 | 20 commits to main since this releaseOverview
A UI-focused release with a reliability fix. The dashboard is rebuilt as a responsive grid of
compact cards, the instance cards on the system detail page were redesigned, and the
intermittent "system/instance disappears" flapping was traced to a connection leak and fixed.
Plus a full dependency CVE audit and patch pass across the backend, frontend, and shipped Docker
image. No functional API changes — every item below is presentation, reliability, or
dependency hygiene.UI Improvements
Dashboard rebuilt as a responsive card grid
The whole dashboard was redesigned to match a new compact card layout. The antd
Row/Col/Card/Statisticscaffolding was replaced with a plain CSS grid.- Responsive grid, one scrollable page: 1 column on small screens, 2 at
≥768px, 3 at
≥1024px, and 4 at≥1280pxwhere the Systems card spans two columns. - Accent icon chip on each summary card (Systems, Total Users, Tenants, Backups, Snapshots),
each with its own theme token — new--accent-systems/users/tenants/backups/snapshotsvariables
defined for both light and dark mode (darker shades use lighter variants for contrast). - Systems card: shows the top 3 systems by CPU as nested panels, each with stacked
CPU/RAM bars and aConnected: X / Yindicator that turns amber when any host is down. - My Instances / Total Instances: show the top 5 running instances by CPU or RAM with an
in-card CPU | RAM toggle. Rows are name-first (long names ellipsize with a tooltip on hover),
followed by a bar and the metric value. Each card keeps an independent toggle and its own
footer pill —Total Running X / Yfor My Instances,Running / Stopped X / Yfor Total.
Running instances only (a stopped instance always reports 0% CPU, so it would never rank).
CPU bars are absolute 0–100%; RAM bars are scaled relative to the heaviest instance shown.
"Mine" is derived on the frontend from the per-instanceownertag, so no new API call. - Total Users shows the role split as pills (
Admin: N,User: N) instead of tags. - Tenants, Backups, and Snapshots move their detail lines into compact info panels
under the headline number. - All colors are theme-aware (light + dark) via the app's CSS variables; no hardcoded hex values
in the view.
Instance cards redesigned (system detail page)
- Redesigned the cards on
/systems/:id/instancesfor a cleaner, scannable layout:- Instance name on its own line with a tinted type badge (
container/virtual-machine)
beside it — labels no longer cover the name. - Status row beneath: colored status dot (Running/Stopped) and
@owner. - Metrics restyled: CPU, RAM Usage, and Disk Storage each show label + monospace
value on one line with a slim rounded bar below (purple/green/blue). - Network Throughput row with ▼ RX / ▲ TX live rates replaces the mini sparkline
(the sparkline remains in the expanded detail view). - CPU now shows live utilization % (delta-based, like the dashboard system graphs) —
e.g.38%with the bar scaled 0–100 — instead of cumulative "CPU Time" in seconds. The
label includes the allocation when set (CPU (2 cores)); percentage is computed against
limits.cpu, falling back to the host's total core count. The Instances table shows the
same %. - Disk Storage now shows used / total (e.g.
4.2 GiB / 9.3 GiB). The total comes from
the instance's live Incus state (size/filesystems.space_totalper disk device), falling
back to the configured root-devicesize, instead of previously showing bare usage whenever
no explicit size limit was configured. The global Instances table and detail panel use the
same totals. - Interfaces (N) footer lists IP chips with a Hide/Show IPs toggle; collapsed by
click, and toggling never triggers card expansion.
- Instance name on its own line with a tinted type badge (
- All colors are theme-aware (light + dark) via the app's CSS variables.
- Card click-to-expand (detail tabs) is unchanged.
Bug Fixes
Systems and instances intermittently disappeared from the dashboard
- Symptom: cards for a given host would periodically vanish and the "connected" count would
flap between e.g. 5/5 → 4/5 → 5/5. The frontend keeps stale data on failed fetches, so cards
only disappeared when the backend answered successfully with empty/false— meaning transient
Incus request failures were being silently swallowed. - Root cause 1 — connection leak: every polling path created a fresh
httpx.AsyncClientper
system per cycle and never closed it (dashboard summary,systems/host-info,instances-state,
and the 30s background instance sync). A steady socket/TLS-session leak in a long-running
container is a prime cause of intermittent Incus connection failures. - Root cause 2 — no retry: a single timeout or connection reset marked a system as
connected: false, which with 10s pollers reads as a card disappearing. - Fix:
- Added
IncusConnector.aclose()(closes the pooled client and clears the handle; idempotent)
and wiredfinally: await connector.aclose()into every polling path listed above, plus the
scheduled-backup worker. IncusConnector.get()now retries twice (3 attempts total, 0.5s pause) on
httpx.RequestError. GETs are idempotent, so this absorbs transient daemon hiccups without
hiding persistent failure.- Added
logger.warningon every previously-silent failure path (dashboardget_server_info,
both instance-listing builders, and the host-info probe) sodocker logsnow shows the real
exception at the moment a system drops, instead of the card just going quiet.
- Added
- Note: if flapping persists on a specific host, re-register that system with its static-IP
endpoint — a hostname-registered endpoint can intermittently fail DNS resolution from inside
the container (EAI_AGAINvia the router/mDNS resolver).
Security Fixes
Python dependencies
- Removed:
python-jose[cryptography]— the package is unused by the application (auth is
built on PyJWT) and dragged inecdsa, which carries the Minerva timing-attack advisory
(CVE-2024-23342 / PYSEC-2026-1325) with no upstream fix available. Dropping the dead
dependency eliminates it from the image entirely. - Added:
cryptographypinned explicitly (it was only present transitively via python-jose;
required for RS256 delegation tokens and hub key handling). - All packages resolved to latest (fastapi 0.141.1, starlette 1.6.0, pydantic 2.13.5,
cryptography 50.0.1, PyJWT 2.14.x, httpx 0.28.1, ...).pip-auditon the full dependency tree:
0 known vulnerabilities.
Frontend (npm) dependencies
- axios 1.x → 1.20.0 — fixes axios form-data recursion DoS (GHSA-42h9-826w-cgv3) and the
form-serializermaxDepthbypass (GHSA-hcpx-6fm6-wx23). - form-data → 4.0.6 — fixes CRLF injection in multipart field names/filenames
(GHSA-hmw2-7cc7-3qxx). - postcss → 8.5.28 (build-time) — fixes source-map path traversal / arbitrary
.map
disclosure (GHSA-fxqj-rqcc-2cmp, GHSA-r28c-9q8g-f849). - nanoid → 3.3.19 (build-time) — fixes generator loops with negative/zero size
(GHSA-28wg-ghj8-5hjv, GHSA-2v37-7h3g-55p8). npm audit(prod and dev trees): 0 vulnerabilities.
Docker base image
- Rebuilt from the latest
python:3.12-slim(Debian 13.7) viadocker build --pull; apt reports
no further upgrades available. - Known residual (unpatchable): 44 Debian 13 HIGH advisories flagged "affected, no fix in the
stable repos yet" — util-linux mount helpers (4 CVEs across its packages), ncurses,
libsystemd/libudev, libacl1, and perl-base (fix deferred upstream). None of these are on the
application's attack surface (the container runs uvicorn + nginx only; it invokes no mount,
terminal, or perl tooling). Re-evaluate when Debian ships point releases. - Trivy scan of the shipped image: 0 HIGH/CRIT in python-pkg and npm layers.
Test Results
- Backend pytest 743/743 against the exact shipped dependency resolution; vitest 215/215;
Playwright E2E 71/71;vite buildclean; in-container verification (app import, RS256
roundtrip, static asset serving) and a live smoke test against a Postgres sidecar
(/api/health200, container healthhealthy).
Upgrade Notes
- Pull
bmcgonag/incus-commander:0.5.6(orlatest) and restart; hard-refresh the browser. - Image digest:
sha256:6617b10490cb351a738b07f36d397de547f05427e34cc2e398adb003d6ef4f83 - The dashboard redesign is presentation-only — no schema migrations, no API changes, no config
changes. Existing sessions and settings carry over untouched.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
3 downloads
- Responsive grid, one scrollable page: 1 column on small screens, 2 at