Releases: sysiblesoftware/Sysible-Controller
Release list
Sysible Controller 3.0.2
3.0.2 — 2026-07-16
A fleet-management and reliability release on top of 3.0.1: a much sturdier host enrollment lifecycle (kill-switches and clean-up for runaway/stale hosts), new system-administration tooling (full firewall management, a time-daemon installer, an Environment & Shell section), a console that scales to large fleets, and another round of web-surface hardening. No breaking changes — upgrade in place with sysible_controller update.
Added
Full ufw firewall management — reads status and the rule list, turns the firewall on/off, and adds/deletes allow/deny rules (by port/proto/source), not just an installer.
"Environment & Shell" tools section — manage system-wide environment variables (/etc/environment, profile.d drop-ins) and shell aliases from the console.
Time Synchronization — explicit Install buttons for chrony and NTP (previously the only path was "Configure chrony", with no NTP install at all).
Update Hosts — "Defer to maintenance window" — schedule the install into a recurring maintenance window instead of running it immediately (creates a managed Schedule).
Pause Enrollment kill-switch — one-click emergency brake that stops the controller accepting new enrollments; plus Revoke Checked and robust bulk Disenroll / Force Delete for runaway fleets.
disenroll_agent.sh and migrate_agent.sh in the agent bundle — host-side cleanup and controller-failover re-pointing, no console round-trip.
Deployed build version shown in the console ("Current build: v… · commit (branch)").
Changed
SSH host connections are being phased out in favour of the managed agent — existing SSH records are marked, individually deletable, and clearable via "Remove all SSH hosts"; tool pickers no longer offer SSH-only hosts.
Firewall tool — each installer sits with its own backend (ufw / firewalld / nftables) rather than a separate install group.
Busy tool pages auto-tab instead of one long vertical scroll.
SSH Auth Policy uses explicit intent buttons instead of a checkbox-then-apply toggle.
User & Group Administration — redesigned account list for fleet scale (keyed on the distinct account, coverage counts, per-environment drill-down + "create on the N missing hosts", clickable filter tiles).
Enrolled Hosts footer polish — only the primary action is solid red; Force Delete/Revoke are outline-danger, disabled until a host is checked; Pause/Resume drops its ⏸/▶ glyphs.
Agent terminal defaults to bash, not the systemd /bin/sh.
Fixed
Duplicate enrollment when a host reported an empty hostname (reconciler now adopts the existing record by IP).
Runaway host enrollment — stable host-id derivation + mass-revoke / robust bulk ops.
openSUSE / SLES user management crash (capture_output/text 3.7-only kwargs → 3.6-safe PIPE/universal_newlines, with a regression test).
Updater gives a clear remedy when tracked files are locally modified.
Ported four shared console fixes from Enterprise.
Security
Hardened web-facing defaults — Secure cookie on by default, CSRF Origin/Referer backstop, loopback-only /openapi.json, clamped list limits.
fstab-line injection via mount options (fixed) — whitespace/newlines rejected.
_validate_path rejects CR/LF as well as NUL.
Additional QA-sweep + infra/reliability hardening across command paths.
Pre-release enterprise security & UX audit findings:
HIGH — command injection via an admin username → root on SSH-managed hosts (fixed) — usernames charset-validated at ingest and the run-as status echoes shlex-quoted.
fstab-line injection via fstype / mount options / NFS export path / CIFS share (fixed) — all reject CR/LF/NUL; fstype is a single token.
Session & bearer tokens hashed at rest (SHA-256) — a leaked DB snapshot no longer yields replayable sessions (existing sessions re-login once).
Local-package upload is size-bounded (413) so an operator can't OOM the console.
Removed a stray NUL byte from a console source file.
Console reliability & hardening (audit follow-through):
No more wedging on a hung request or expired session — request timeout, a global 401→login handler, and a top-level error boundary.
Durable login brute-force lockout — moved to the database so it survives a restart/crash-loop; per-IP throttle now mutation-locked.
Python dependencies pinned for reproducible builds (agent keeps a compatible range).
Configurable controller bind via SYSIBLE_CONTROLLER_BIND; firewalling :9000 stays primary.
Sysible Controller 3.0.1
Sysible Controller — Community 3.0.1
Released 2026-07-10
A large security-hardening and reliability release on top of 3.0.0, plus new fleet-management conveniences. Every managed-host command path, the agent↔controller protocol, and the web console were re-audited from scratch; the highlights below group the results by theme. No breaking changes — upgrade in place with sysible_controller update.
Security
Command execution & injection
- Grub command injection → root on the managed host (fixed).
cmd_set_grub_defaultconcatenated the raw menu entry into an echo, so an entry like0'; <cmd>; echo 'ran<cmd>as root. The value is nowshlex-quoted viaprintfand never enters the shell string. - SSH argument injection → controller root code execution (fixed). A stored SSH host's
user/ipflowed into thesshcommand line; a value like-oProxyCommand=…was parsed by ssh as an option and ran on the controller as root (and could be triggered automatically by the read-only fleet sweeps). Hostuser/username/ip/nameare now charset-validated at ingest and the ssh argv carries an explicit--before the destination. - Defense-in-depth on the unit/mount builders. The systemd service/timer builders reject newline breakout of the unit-file heredoc and
//..in a unit name; the mount builder rejects newlines in a mount point (no injected/etc/fstabentry); and an agent-reportedipis charset-validated at ingest.
Authentication, sessions & authorization
- Forced first-login password change is enforced server-side — every write/dispatch route (and the interactive terminal WebSocket) returns 403 until the temporary password is rotated, and a username-only credential change no longer lifts the gate. Previously this was only a frontend modal an operator could skip.
- The console session is revalidated against the live account. A demoted or removed admin's signed cookie used to keep BFF-gated powers until the 12h token expiry. Each request now re-checks the admin token against the controller (new
GET /admin/whoami, TTL-cached to one call/minute/session) and drops the session the moment the token is revoked (SYSIBLE_SESSION_REVALIDATE_TTL). - Admin-login throttle is per-username, and login is constant-time. The lockout was keyed on the caller's IP — which for every console login is the single BFF, so ten failures locked out all admins; it's now per-account. A decoy PBKDF2 verify runs when the username doesn't exist (admin and portal logins), closing a username-enumeration timing oracle.
- Pure-SSH file upload/download now requires superuser on the controller (was API-key-only), matching the BFF's separation of duties for the SFTP-as-root path.
- Logout revokes the controller token, not just the stateless cookie, so a captured token can't linger to expiry.
/api/mefails closed toauditoron a missing role.
Secrets, keys & TLS
- TLS pinning is fail-closed. A missing pin file on an
https://controller used to silently fall back to system-CA verification (any CA in the store could MITM the agent/BFF→controller channel); it now refuses to connect (SYSIBLE_ALLOW_SYSTEM_CA=1to opt into the system trust store). - Secrets are created
0600atomically (O_EXCL|O_NOFOLLOW) — the sudo-store key, the admin API key, and the cookie-signing secret — closing a world-readable umask race a local user could exploit to read the key or forge admin cookies. - The install-time default admin password is passed via the environment, not argv, so it's no longer visible to any local user through
ps//proc/<pid>/cmdline. - The agent no longer puts its secret in a URL. The interactive-terminal long-poll sent the agent secret as a query parameter, recording a live credential in the controller access log every ~25s; it now uses the
X-Agent-Secretheader.
Enrollment & host identity
host_idis charset-validated at enrollment (alphanumeric plus._-, reserved sentinels refused) — an injection-shaped or*-style id is rejected outright.- Enrollment adoption can no longer bypass revocation or hijack a host. The re-enroll "supersede" path matched on the unauthenticated request-body IP and could resurrect an admin-revoked host or seize an offline host's identity. Adoption is now narrow (same hostname and IP, never a revoked record, never a live host), and a revoked host must be explicitly Restored from the console.
- Alert webhook delivery is pinned to the verified IP — the SSRF guard checked the resolved host was public but
urlopenre-resolved it (DNS rebinding); the request now connects to the exact IP that passed the check (TLS cert/SNI still validated against the hostname).
New features & capabilities
- The controller enrolls itself as a managed host. On first start it installs a privileged local agent pointed at loopback and enrolls itself, so it appears in the fleet like any other box — patch it, run scripts on it, open a terminal into it. Idempotent, best-effort, opt-out via
SYSIBLE_NO_SELF_ENROLL=1; run on demand withsudo sysible_controller self-enroll. - Restore a revoked host in place — a Restore button (and
POST /agents/{id}/restore) un-revokes without a destructive re-enroll, keeping the agent secret so a still-installed agent resumes immediately. - Force Delete now permanently removes a zombie host by also purging the enrollment token bound to it, so a still-running agent can't re-enroll onto the same id with the old token.
tools/unenroll_agentgained the same purge, plus--ip/--namematching, DB auto-detection, and--dry-run. - Deployment guard. The controller reports which directory and git commit the live process is running from (
GET /version, Settings → Controller Configuration), and shows a red "restart needed" banner when the on-disk code has moved since start. - On-demand certificate management — a "Regenerate self-signed certificate" action reissues for the current address and restarts atomically; a "Download / Regenerate agent bundle" button re-mints a fresh bundle (new single-use token) after a hostname/IP change.
- URL-addressable navigation — every console view has a URL (
?view=<key>), so you can ⌘/Ctrl-click, middle-click, open in a new tab, and bookmark/share a view. - Run a script across the hosts you choose — clarified in Sysible Connect and added as a "Run a script" panel in Quick System Actions.
- Standalone New Environment button, and an offline documentation download (
GET /api/docs/download).
Reliability & fixes
- Host updates no longer fail on far-behind hosts — the agent command cap moved 5→30 min (
SYSIBLE_AGENT_CMD_TIMEOUT) so a realdnf/apt/zypperupgrade isn't SIGKILLed mid-transaction; "Refresh metadata & rescan" allows 180s for a slow mirror; zypper security updates no longer skip license-gated patches. - Dashboard host counts are consistent and stable — enrolled/online/offline come from the instant agent inventory instead of the slow probe sweep, so a host no longer "falls off" to 0 during a sweep; revoked hosts are excluded from counts, donut, and fleet-action set.
- Quarantined hosts fail fast instead of hanging (install reports the reason immediately; sweeps skip them).
- Re-enrolling a host no longer auto-quarantines it or creates a duplicate "zombie" record at the same IP.
- "Set Environment" no longer times out — hot enroll/disenroll DB writes release the SQLite WAL writer even on error, and the console write timeout was raised above the DB busy-timeout.
- Self-update is robust — read-only
git ls-remotefor the update-check, stale-lock cleanup, and auto-repair of a corrupted ref store instead of dead-ending on "reference already exists";/update-statusbounds its remote check (no phantom agent); "Update agents" excludes revoked hosts. - Regenerating the self-signed cert no longer leaves the controller down (restart scheduled via a detached
systemd-runtimer outside the service cgroup); changing the controller address only flags the cert stale rather than breaking pinned clients. - Terminal to an offline agent fails fast; abandoned agent-terminal sessions no longer leak memory. "Upload & install a local package" works on agent-managed hosts. Username-only self-service change works. Host Enrollment refreshes are lighter (lazy portal data).
- Web console display fixes from a full click-path audit: Webserver Portal timestamps, Environmental Policies "Save" actually persisting, Performance chart edge buckets, Lock/Unlock/Delete confirmations, self-disenroll serialization.
Performance
- Posture / fleet-health sweeps are much faster — integrity
find /walks capped at 8s (SYSIBLE_POSTURE_FIND_TMO), up to 32-way concurrency (SYSIBLE_SWEEP_CONCURRENCY); the ~5s reverse-DNS host-list stall onGET /agentsis gone.
Platform & compatibility
- openSUSE / SLES fixes across the host command builders — sudo policy detects the
wheelgroup (nosudogroup on SUSE/RHEL, so the policy was silently ineffective); kernel listing, sshd, and firewalld paths/deps corrected; installer seedspython3-gobjectwhere needed. - TLS material is written atomically (cert/key/trust) so an interrupted install can't leave a half-written trust bundle.
Testing
- New regression coverage: SSH host-injection rejection, the self-enroll bundle,
/admin/whoami+ per-username throttle, and theunenroll_agentforce-removal path.
Want me to draft this as a GitHub Release via the API if you can grant the session tag/release permission, or is creating it from the UI/your machine easier? Either way, the commit and notes are ready on main at 15519ad.
Sysible Controller 3.0.0
Sysible Controller 3.0.0
First official tagged release. Sysible Controller is now fully browser-based — the legacy desktop (PySide6) GUI, X11-forwarding, and FreeRDP/RDP paths are gone. Everything is delivered through the web console, so the controller can live on a headless server and administrators can work from any browser on Windows, macOS, or Linux.
🔒 Security
- Closed a client-controlled audit/authorization bypass — an operator could set
log=falseon an SSH exec to skip both the read-only-auditor block and the audit record. The auditor block is now unconditional. - Enrollment-token replay hardening — a leaked token can no longer take over a still-live host or resurrect an administrator-revoked one.
- Agent integrity — a host that sealed a measurement baseline and then stops reporting is quarantined (evasion-by-omission closed); the integrity state store is locked and written atomically at
0600. - Payload size caps — agent-channel payloads (metrics / snapshot / measurements / task result / PTY output) are size-capped to bound controller memory against a hostile agent.
- Secret scrubbing — audit-log command text is scrubbed of secret-bearing arguments (
--password,--token,Authorization: Bearer,KEY=value, …). - No cross-host SSH clobber — an agent-reported IP can no longer delete or repoint another host's SSH record; the collision is surfaced instead.
- Terminal auditing — interactive terminals are audited (open/close) and bound to the operator who opened them.
- Forced password change is now enforced in the console (previously ignored).
⚙️ Reliability & operations
- Fixed a web-console startup crash (module-level use of
threadingbefore its import). - Serialized the heartbeat-path JSON stores to end lost-update races under concurrent heartbeats.
- Hottest DB writers release their SQLite connection even on exception — no leaked WAL reservations compounding lock contention.
- Fleet-health is cached and shared across concurrent dashboard loads instead of re-probing every host per load.
- A failed agent task reports back immediately instead of hanging until a 15-minute reclaim rewrites it as a fabricated timeout.
- Foot-gun guardrails: the last superuser can't be deleted; an "all hosts" reboot/power-off skips the controller's own node;
destroy's DB backup is0600; deleting an environment with hosts is refused; duplicate environment names return a clear error. - Force Delete for zombie hosts — Enrolled Hosts can immediately drop a broken agent build that keeps heartbeating but can't cleanly disenroll, skipping the graceful teardown that would otherwise stall. The record deletion also locks the agent out on its next heartbeat.
- Replacing the TLS certificate now warns and confirms (it breaks pinned agents until the trust bundle is redistributed).
- Agent install now works on SUSE and other minimal images —
run_agent.shinstalls Python 3 if absent, prefers the distropython3-requestspackage (no PyPI/compiler, sidesteps PEP 668), only falls back to pip and only passes--break-system-packageswhen that pip supports it, and hard-fails with clear per-distro guidance ifrequestsstill can't be installed. The systemd unit points at the python3 actually found rather than a hardcoded/usr/bin/python3.
✨ Usability
- Host-enrolled notification — when a new host enrolls, the console pops a toast from any page and records it in the Live Activity feed.
- Community Edition: all host/administrator seat caps removed; a small "Community Edition" badge replaces the counts.
- Nav reordered to follow the fleet workflow; consistent file-transfer/browse controls; de-cramped Enrolled Hosts rows.
- Schedule builder validates its fields (no more
*/0/NaNcron) and notes that jobs run in the target host's local timezone. - Accessibility & consistency pass: focus rings, colour contrast, missing confirmations, and loading indicators.
🧪 Testing & tooling
- Exhaustive API test-suite covering authentication, RBAC/permissions, input validation, SQL/XSS injection, size caps, duplicate requests, and rate limiting. Run with
pytest. - SessionStart hook that provisions the test environment for Claude Code on the web.
🧹 Housekeeping
- Removed legacy backward-compat shim scripts (
sysible,start_sysible.sh,stop_sysible.sh). Usesysible_controller {start|stop|…}. - Removed all desktop-GUI / xserver / RDP / FreeRDP references and host/user seat-cap language from the README, SECURITY, and docs.
📚 Documentation
- README and SECURITY updated for the current feature set, plus a Known limitations & operational notes section (TLS trust-bundle refresh, SIEM forwarding for durable audit, single-node SQLite write ceiling, bearer enrollment tokens, host-local schedule timezones).
Upgrading: run the update flow for the controller and agents as usual. Agent bundles are regenerated with the more robust Python bootstrap, so previously-failing SUSE/minimal hosts will install cleanly.