• v0.5.6 631f2b414e

    brian released this 2026-09-26 14:23:18 +00:00 | 20 commits to main since this release

    Overview

    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/Statistic scaffolding 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 ≥1280px where 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/snapshots variables
      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 a Connected: X / Y indicator 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 / Y for My Instances, Running / Stopped X / Y for 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-instance owner tag, 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/instances for 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_total per disk device), falling
        back to the configured root-device size, 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.
    • 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.AsyncClient per
      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 wired finally: 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.warning on every previously-silent failure path (dashboard get_server_info,
        both instance-listing builders, and the host-info probe) so docker logs now shows the real
        exception at the moment a system drops, instead of the card just going quiet.
    • 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_AGAIN via 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 in ecdsa, 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: cryptography pinned 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-audit on 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-serializer maxDepth bypass (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) via docker 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 build clean; in-container verification (app import, RS256
      roundtrip, static asset serving) and a live smoke test against a Postgres sidecar
      (/api/health 200, container health healthy).

    Upgrade Notes

    • Pull bmcgonag/incus-commander:0.5.6 (or latest) 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