973 lines
56 KiB
XML
Executable File
973 lines
56 KiB
XML
Executable File
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!--
|
|
SysDeck - AppStream Metainfo (umbrella component)
|
|
|
|
This file follows the pattern used by cockpit-project itself in
|
|
src/appstream/org.cockpit_project.cockpit_*.metainfo.xml.in — see
|
|
e.g. org.cockpit_project.cockpit_networkmanager.metainfo.xml.in.
|
|
|
|
Pattern verified from the cockpit source code:
|
|
pkg/apps/watch-appstream.py:237 — reads <launchable type="cockpit-manifest">NAME</launchable>
|
|
pkg/apps/utils.tsx:152 — matches launchable.type == "cockpit-manifest"
|
|
src/appstream/*.xml.in — all use <launchable>, not <provides><cockpit-manifest>
|
|
|
|
Previous versions of this file (v0.0.17-v0.0.20) used
|
|
<provides><cockpit-manifest>NAME</cockpit-manifest></provides>, which is
|
|
NOT what the cockpit apps page reads. It is silently ignored — the plugin
|
|
would not appear in the Applications menu. v0.0.21 corrects this.
|
|
|
|
The <id> follows the reverse-DNS convention used by cockpit-project:
|
|
org.cockpit_project.cockpit_<name> (cockpit's own plugins)
|
|
net.dcos.sysdeck (this umbrella component)
|
|
|
|
The <launchable> text must match the `name` field of the plugin's
|
|
manifest.json — NOT the directory name. For sysdeck-containers, the
|
|
manifest.json has `"name": "sysdeck-containers"`, so the launchable
|
|
text is "sysdeck-containers".
|
|
|
|
This umbrella metainfo covers the whole SysDeck suite. Each individual
|
|
plugin does not ship its own metainfo (to avoid 18 components in the
|
|
AppStream cache). The umbrella component is what appears in Cockpit's
|
|
Applications page; clicking it could open the first plugin's page.
|
|
-->
|
|
<component type="addon">
|
|
<id>net.dcos.sysdeck</id>
|
|
<extends>org.cockpit_project.cockpit</extends>
|
|
<metadata_license>CC0-1.0</metadata_license>
|
|
<project_license>MIT</project_license>
|
|
<name>SysDeck</name>
|
|
<summary>Unified operations surface for Linux infrastructure — 27 Cockpit plugins plus a standalone web console</summary>
|
|
<description>
|
|
<p>
|
|
SysDeck is a suite of 27 standalone Cockpit plugins — containers,
|
|
firewall, integrity auditing, network security, service mesh,
|
|
encryption vaults, fleet compute, Kata Containers, firmware, image
|
|
building, mining, theme engine, hardware authentication, DAG-driven
|
|
build orchestration, system monitoring, hardware sensors, system
|
|
benchmarking, package management, policy & permissions, database
|
|
control, Jellyfin media server, photo manager (PhotoPrism/Piwigo/
|
|
Lychee/Nextcloud-Memories/LibrePhotos), remote filesystem manager
|
|
(Ceph/GlusterFS/MooseFS/BeeGFS/OrangeFS), the service/port
|
|
editor, the 3rd-party module installer, and the AI gateway
|
|
client. Each plugin appears as its own sidebar entry in the
|
|
Cockpit web UI.
|
|
</p>
|
|
<p>
|
|
The plugins ship as static HTML+JS+CSS plus a Python bridge helper
|
|
package. They install under /usr/share/cockpit/sysdeck-<name>/ and
|
|
are discovered automatically by cockpit-bridge. No separate web
|
|
server, no Node.js runtime, no database — the plugins run inside
|
|
the cockpit web service.
|
|
</p>
|
|
<p>
|
|
SysDeck also ships as a standalone web console — one Next.js process
|
|
serving the same module catalog with Unix-account (PAM) login, no
|
|
Cockpit required. The console additionally detects every installed
|
|
cockpit module on the host and loads it into its own navigation,
|
|
and every domain module loads in both front ends. The standalone
|
|
console ships in the master tarball (web/).
|
|
</p>
|
|
<p>
|
|
Each backend tool (podman, nftables, fwupd, etc.) is invoked as a
|
|
separate subprocess via the bridge helper; no third-party code is
|
|
bundled. See THIRD_PARTY.md for the full attribution matrix.
|
|
</p>
|
|
</description>
|
|
<url type="homepage">https://dcos.net</url>
|
|
<url type="bugtracker">https://dcos.net/sysdeck/issues</url>
|
|
<url type="help">https://dcos.net/sysdeck/quickstart</url>
|
|
|
|
<!-- The 27 <launchable> entries below match the `name` field of each
|
|
plugin's manifest.json. The cockpit apps page (pkg/apps/utils.tsx:152)
|
|
reads launchable.type == "cockpit-manifest" and uses the text to
|
|
link the AppStream component to the corresponding Cockpit plugin.
|
|
v0.0.35: SysDeck Kata as its own sidebar entry; added
|
|
sysdeck-jellyfin, sysdeck-photos, sysdeck-remotefs.
|
|
v0.0.46: added sysdeck-modules (in-suite 3rd-party module installer).
|
|
v0.0.47: added sysdeck-services (service/port editor promoted to
|
|
its own sidebar entry).
|
|
v0.3.0: added sysdeck-klanker (AI gateway client panel). -->
|
|
<launchable type="cockpit-manifest">sysdeck-containers</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-firewall</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-integrity</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-netsec</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-mesh</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-vault</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-fleet</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-kata</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-fester</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-firmware</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-builder</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-mining</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-themes</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-auth</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-glances</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-sensors</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-benchmark</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-packages</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-policy</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-db</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-jellyfin</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-photos</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-remotefs</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-monitoring</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-modules</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-services</launchable>
|
|
<launchable type="cockpit-manifest">sysdeck-klanker</launchable>
|
|
|
|
<categories>
|
|
<category>System</category>
|
|
</categories>
|
|
<keywords>
|
|
<keyword>cockpit</keyword>
|
|
<keyword>operations</keyword>
|
|
<keyword>monitoring</keyword>
|
|
<keyword>firewall</keyword>
|
|
<keyword>containers</keyword>
|
|
<keyword>firmware</keyword>
|
|
<keyword>jellyfin</keyword>
|
|
<keyword>photos</keyword>
|
|
<keyword>ceph</keyword>
|
|
<keyword>remote-filesystem</keyword>
|
|
</keywords>
|
|
<content_rating type="oars-1.1" />
|
|
<releases>
|
|
<release version="0.4.5" date="2026-09-17">
|
|
<description>
|
|
<p>v0.4.5: production-hardening release from a full
|
|
Mixture-of-Experts QA pass — security fixes in the bridge
|
|
(filename validation, single-statement SQL guard, CSS value
|
|
allowlist, subprocess timeouts), six structurally validated
|
|
nftables firewall templates with table-scoped flush, the web
|
|
console enforcing its type and lint gates, and packaging that
|
|
builds cleanly on all three distro paths. Comments state
|
|
standing decisions in the present tense.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.4.4" date="2026-09-12">
|
|
<description>
|
|
<p>v0.4.4: ten package managers on both editions — pacman,
|
|
emerge, lunar, sorcery, xbps, apk, zypper, dnf/yum, and apt
|
|
with the identical detection order, parsers, and mutation
|
|
table on the cockpit bridge and the web console, locked in by
|
|
fixture tests; honest capability reporting (lunar has no
|
|
update-preview subcommand, so its summary says so). BLOG.md
|
|
rebuilt as the long-form engineering essay; release history
|
|
lives in QA.md and worklog.md. Docs pass: standalone-first
|
|
positioning — the web console is the default shape, the
|
|
Cockpit plugin suite optional.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.4.3" date="2026-09-12">
|
|
<description>
|
|
<p>v0.4.3: the multi-expert QA pass. Privileged writes ride stdin
|
|
with post-write verification; rule comments are injection-guarded;
|
|
temp staging is mktemp'd; the smartcard PIN never touches argv;
|
|
mutating bridge commands require an admin session with an
|
|
opt-out for single-operator consoles; dry-runs preview exactly
|
|
what apply executes; rate-limit identity ignores client-supplied
|
|
X-Forwarded-For unless the operator opts in; the polling layer
|
|
shares TTL-cached single-flight probes; and the cockpit-side
|
|
bridges match the web side's step-down chains.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.4.2" date="2026-09-12">
|
|
<description>
|
|
<p>v0.4.2: the zero-demo release — production implementations
|
|
only. Sensor readings come from the real lm-sensors JSON; the
|
|
network-security ban layer enforces through real nftables or
|
|
iptables and merges the live fail2ban ban list; the firewall
|
|
panel reads the host's actual kernel ruleset and ships the full
|
|
seven-template catalog; absent backends render honest empty
|
|
inventories, never fabricated rows.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.4.1" date="2026-09-12">
|
|
<description>
|
|
<p>v0.4.1: every cockpit module installed on the host is
|
|
detected and loaded into the web console — distro modules
|
|
(cockpit-machines, cockpit-podman, networking, storage) and
|
|
addons alike, scanned from /usr/share/cockpit manifests. A
|
|
Cockpit sidebar group with per-module detail views, live
|
|
backend probes, and jumps to the native panels covering each
|
|
domain. UI codenames retired; the console subtitle is
|
|
dcos.net.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.4.0" date="2026-09-12">
|
|
<description>
|
|
<p>v0.4.0 UNIX LOGIN EDITION: the web edition signs in with a
|
|
Unix account, verified by the host's PAM stack — the same
|
|
mechanism Cockpit uses. Session cookies are bound to the
|
|
username (v2 tokens; 0.3.1 v1 tokens still verify). The shell
|
|
carries a cockpit-style account menu (avatar, user@host,
|
|
provenance, administrative-access badge, session countdown)
|
|
and the status bar shows user@host. Three auth modes: pam
|
|
(default), pam+local and local, with scrypt console accounts
|
|
managed by scripts/manage-users.mjs. The cockpit edition is
|
|
untouched — all modules keep working.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.3.0" date="2026-09-11">
|
|
<description>
|
|
<p>v0.3.0 AI GATEWAY EDITION: klanker-gate — the Frosty Deno
|
|
LLM gateway (independent version 0.9.0) — is vendored at
|
|
/klanker-gate with complete Arch Linux packaging. A new AI
|
|
Gateway module ships in both editions: the cockpit edition gets
|
|
bridge/klanker.py plus a full panel, the web edition a hybrid
|
|
live/demo panel. The Arch port needed zero upstream source
|
|
changes.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.2.0" date="2026-08-20">
|
|
<description>
|
|
<p>v0.2.0 MASTER EDITION: one tarball bundling the cockpit
|
|
edition, the new SysDeck Web Edition (web/), and Fester
|
|
pre-integrated (vendored at web/mini-services/fester, own
|
|
independent version 0.2.1). The fester bridge is a real REST
|
|
client now, the fester panel is fully built, and the Makefile
|
|
recipe indentation is fixed.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.1.3" date="2026-08-19">
|
|
<description>
|
|
<p>v0.1.3 — CRITICAL FIX: host package import was silently failing
|
|
+ mkosi still wasn't reading the profile config. Two root causes
|
|
fixed, plus new download/manage UI for builds.</p>
|
|
<p>IMPORT BUG: _detect_host_packages() relied on `from __init__
|
|
import PKG_MANAGER` which silently failed in the cockpit
|
|
superuser channel context (different Python path). PKG_MANAGER
|
|
defaulted to "unknown", the host query returned an EMPTY list,
|
|
and the import wrote nothing. The operator saw "tries to build
|
|
only 2" because the build used the profile's original template
|
|
packages. FIX: now uses shutil.which() to find pacman/apt-mark/
|
|
dnf directly — no import dependency, works in any context.</p>
|
|
<p>BUILD BUG: v0.1.2's --include flag does NOT work as a config
|
|
loader. mkosi's --include includes a drop-in fragment ON TOP OF
|
|
the base mkosi.conf — it does NOT replace the base config. If
|
|
there's no mkosi.conf in the cwd, mkosi uses defaults and
|
|
ignores the --include file entirely. FIX: build() now creates a
|
|
temp directory, symlinks the profile file as `mkosi.conf`, and
|
|
sets work_dir to that temp dir. mkosi finds the symlink, follows
|
|
it, reads the actual profile. Works for ANY profile path.</p>
|
|
<p>NEW: artifact download + management UI. Each artifact has a
|
|
Download button (reads via cockpit.spawn cat + Blob), a per-file
|
|
Delete button, and a per-profile Clear all button. Profile card
|
|
header shows total artifact size.</p>
|
|
<p>NEW: build management. Each build has a Delete button with
|
|
two-step confirm (state+log only, or also artifacts). New
|
|
subcommand: build-delete.</p>
|
|
<p>REGRESSION TESTS: 11 new unit tests in
|
|
TestBuilderArtifactManagement (7) + TestBuilderMkosiTempWorkDir
|
|
(3). Total: 254 tests (was 243; +11). All pass.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.1.2" date="2026-08-19">
|
|
<description>
|
|
<p>v0.1.2 — CRITICAL FIX: mkosi was not reading the profile
|
|
config at all. Packages were silently ignored. Operator
|
|
reported: "the builder absolutely does not work yet. it has
|
|
zero awareness of packages we tell it to add."</p>
|
|
<p>ROOT CAUSE 1 (config not loaded):
|
|
_backend_build_command() for mkosi had no flag telling mkosi
|
|
WHERE the profile config file is. mkosi only reads a file
|
|
literally named `mkosi.conf` from the cwd. For v0.0.x profiles
|
|
at /etc/mkosi/mkosi.conf.d/<name>.conf, mkosi ran in that
|
|
dir, found no `mkosi.conf`, and used EMPTY defaults — zero
|
|
packages, default distro, default everything.</p>
|
|
<p>FIX 1: _backend_build_command() now ALWAYS passes
|
|
--include <profile_path> on the CLI. This tells mkosi to
|
|
explicitly load the profile config by path, regardless of its
|
|
filename or location.</p>
|
|
<p>ROOT CAUSE 2 (legacy Packages= syntax): profiles created by
|
|
v0.0.x used the old indented Packages= syntax
|
|
(Packages=\n linux\n...). mkosi v22+ only understands
|
|
single-line (Packages=linux ...). The old form is silently
|
|
parsed as a single package name with embedded newlines, which
|
|
doesn't exist in any repo — so mkosi installs NOTHING.</p>
|
|
<p>FIX 2: new _migrate_legacy_mkosi_packages() function detects
|
|
the old indented syntax and rewrites it to single-line IN-PLACE
|
|
before the build command is constructed. build() calls this
|
|
automatically on every mkosi build. Migration is logged in
|
|
build state JSON and log file header. No-op on modern syntax.</p>
|
|
<p>REGRESSION TESTS: 4 new unit tests in TestBuilderBuildPath
|
|
cover migration (old syntax rewrite, modern no-op, no-section
|
|
no-op, end-to-end during build). Existing test_build_success_path
|
|
extended to verify --include is on the command line and points
|
|
at the profile file. Total unit tests now 243 (was 239 in
|
|
v0.1.1; +4). All build-time guards pass.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.1.1" date="2026-08-19">
|
|
<description>
|
|
<p>v0.1.1 — OUTPUT PATH SAFETY FIX. An operator reported:
|
|
"this is NOT a safe output path. fix this now." The v0.1.0
|
|
release relied on OutputDirectory= in the scaffolded
|
|
mkosi.conf to route build outputs to
|
|
/var/lib/sysdeck/builder/artifacts/<name>/. But when
|
|
the operator built an OLD v0.0.x profile (whose mkosi.conf
|
|
had no OutputDirectory= setting), mkosi defaulted to
|
|
writing image.raw into the cwd — which was
|
|
/etc/mkosi/mkosi.conf.d/, a system config directory owned
|
|
by root. mkosi then refused to overwrite the existing
|
|
image.raw, blocking every rebuild.</p>
|
|
<p>ROOT CAUSE: _backend_build_command() for mkosi was just
|
|
["mkosi", "build"] with no CLI output flags. It trusted the
|
|
profile's mkosi.conf to set OutputDirectory=, which doesn't
|
|
exist on v0.0.x profiles, can be hand-edited to anything,
|
|
and is ignored by mkosi if the profile is a drop-in fragment
|
|
mkosi never reads.</p>
|
|
<p>FIX: _backend_build_command() now ALWAYS passes --output,
|
|
--output-dir, and --force on the CLI for mkosi builds. CLI
|
|
flags override mkosi.conf, so the output path is forced to
|
|
/var/lib/sysdeck/builder/artifacts/<name>/<name>.raw
|
|
regardless of what the profile says. --force overwrites any
|
|
existing image so rebuilds don't fail with "Output path
|
|
exists already."</p>
|
|
<p>SAFETY CHECK: build() now refuses to proceed if the
|
|
resolved output_dir is not under /var/lib/, /tmp/,
|
|
/var/tmp/, or the configured BUILDER_ARTIFACTS_DIR. Blocks
|
|
/etc/, /usr/, /boot/, /bin/, /sbin/, /lib/, /root/,
|
|
/home/, etc. Belt-and-suspenders: even if an operator
|
|
passes options.output_dir=/etc/something via the JS bridge,
|
|
the build is refused before subprocess.run is called.</p>
|
|
<p>LEGACY PROFILE WARNING: build() now detects profiles in
|
|
/etc/mkosi/mkosi.conf.d/ (the v0.0.x drop-in layout) and
|
|
records a warning in both the build state JSON and the log
|
|
file: "WARNING: profile is in /etc/mkosi/mkosi.conf.d/
|
|
(legacy v0.0.x layout). mkosi may silently ignore this
|
|
drop-in fragment. Migrate to /etc/mkosi/profiles/<name>/
|
|
mkosi.conf for a real profile."</p>
|
|
<p>LOG IMPROVEMENT: build log header now includes the
|
|
resolved output_dir so the operator can see exactly where
|
|
the image will land before mkosi starts.</p>
|
|
<p>REGRESSION TESTS: 2 new unit tests in TestBuilderBuildPath
|
|
cover the safety check (refuses /etc/) and the legacy-profile
|
|
warning. The existing test_build_success_path was extended to
|
|
verify the mkosi command line includes --output, --output-dir,
|
|
and --force, and that --output-dir points at the per-profile
|
|
artifacts dir. Total unit tests now 239 (was 237 in v0.1.0;
|
|
+2). All build-time guards pass.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.1.0" date="2026-08-19">
|
|
<description>
|
|
<p>v0.1.0 — BUILDER PROFILE FIXUP + HOST PKG IMPORT. Three
|
|
compounding bugs in the v0.0.x mkosi build path were silently
|
|
producing empty 33M images with no kernel, no systemd, no
|
|
openssh — the operator clicked Build on a freshly-created
|
|
profile and got back a 33M image.raw containing only
|
|
iana-etc + filesystem. Plus a new operator feature requested
|
|
in the same release cycle: "import current os pkg list to
|
|
profile should be an option".</p>
|
|
<p>BUG 1 (scaffold location): profile-create wrote
|
|
/etc/mkosi/mkosi.conf.d/<name>.conf — a drop-in fragment
|
|
that mkosi only honors when a parent /etc/mkosi/mkosi.conf
|
|
exists to layer it onto. With no parent, mkosi ran with
|
|
empty defaults. Fix: each profile now lives in its own
|
|
directory /etc/mkosi/profiles/<name>/mkosi.conf (the
|
|
only filename mkosi reads automatically from the cwd).
|
|
MKOSI_DIRS updated to scan /etc/mkosi/profiles first.</p>
|
|
<p>BUG 2 (Packages= syntax): _MKOSI_TEMPLATE and
|
|
_write_packages_mkosi used the indented-continuation form
|
|
which was the old systemd-mkosi (<=v15) syntax. mkosi v22+
|
|
(Arch ships 25.x) expects single-line space-separated:
|
|
Packages=linux linux-firmware systemd openssh. Fix: template
|
|
+ writer now emit the modern single-line form. The reader
|
|
accepts both forms so v0.0.x profiles migrate cleanly on
|
|
first append/replace.</p>
|
|
<p>BUG 3 (output routing): mkosi wrote its output to the cwd
|
|
(/etc/mkosi/mkosi.conf.d/image.raw) but build() only scanned
|
|
/var/lib/sysdeck/builder/artifacts/<profile>/ for
|
|
artifacts — so every successful build looked like a failure
|
|
in the panel. Fix: _MKOSI_TEMPLATE now sets OutputDirectory=
|
|
to the per-profile artifacts dir so mkosi writes directly
|
|
there.</p>
|
|
<p>NEW FEATURE: profile-import-packages subcommand. Queries
|
|
the host's explicitly-installed package set (pacman -Qqe on
|
|
Arch, apt-mark showmanual on Debian, dnf repoquery
|
|
--userinstalled on Fedora) and writes it into a profile's
|
|
package list via the existing _write_packages dispatch.
|
|
Defaults to append mode so the profile's baseline (kernel,
|
|
systemd, openssh) is preserved. Supports --mode=replace,
|
|
--dry-run for preview, and --packages= for manual override.
|
|
New polkit exec paths for pacman/apt-mark/dnf added to
|
|
org.sysdeck.builder.modify.</p>
|
|
<p>PANEL UX: each profile row in the Builder panel now has
|
|
a "Import host pkgs" button. Click — dry-run preview —
|
|
window.confirm with package count, source distro, and first
|
|
200 packages — append write. Falls back to operator cancel
|
|
without writing.</p>
|
|
<p>REGRESSION TESTS: 7 new unit tests in
|
|
TestBuilderImportHostPackages cover _detect_host_packages
|
|
dispatch (pacman path + dedup), the --packages override
|
|
end-to-end, --dry-run no-write behavior, and the
|
|
unknown-profile / no-args / bad-mode / COMMANDS-registration
|
|
error paths. 4 existing tests in TestBuilderPackagesField
|
|
updated for the new single-line Packages= syntax; 1 new test
|
|
guards against a regression where the writer emits the new
|
|
form but the reader only understands the old one.</p>
|
|
<p>VERSION SYNC: bumped 0.0.50 → 0.1.0 across all 9 release
|
|
surfaces. Total unit tests now 237 (was 228 in v0.0.50; +8
|
|
TestBuilderImportHostPackages + 1 new
|
|
test_mkosi_modern_single_line_input_parsed). All build-time
|
|
guards pass.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.50" date="2026-08-19">
|
|
<description>
|
|
<p>v0.0.50 — BUILD PATH NameError FIX. An operator reported:
|
|
"NameError: name 're' is not defined. Did you forget to
|
|
import 're'? happens right away on build for a new profile i
|
|
created." The traceback pointed at _new_build_id() line 492:
|
|
safe_profile = re.sub(r"[^A-Za-z0-9_-]", "_", profile).</p>
|
|
<p>ROOT CAUSE: bridge/builder.py's module-level imports were
|
|
import json / os / shutil / subprocess / sys + from pathlib
|
|
import Path + from typing import Any. No `import re`.
|
|
_new_build_id has used re.sub since v0.0.31 (when the full-
|
|
featured build operations were added), but no test ever
|
|
exercised the build() code path. The bug went undetected for
|
|
18 releases (v0.0.31 through v0.0.49) until an operator
|
|
actually clicked Build on a freshly-created profile.</p>
|
|
<p>FIX: added `import re` to the module-level imports in
|
|
bridge/builder.py. Removed the now-redundant local `import
|
|
re` inside _write_packages_vmdb2 (it was a v0.0.49 workaround
|
|
that's no longer needed — the module-level import covers both
|
|
callers).</p>
|
|
<p>REGRESSION TESTS: 9 new unit tests in
|
|
tests/test_bridge_parsers.py TestBuilderBuildPath cover
|
|
_new_build_id (format, sanitization of unsafe chars,
|
|
preservation of safe chars, and an explicit assertion that
|
|
`re` is in the builder module's globals so the bug can't
|
|
recur if anyone refactors the imports). The class also
|
|
includes build() end-to-end tests with mocked
|
|
subprocess.run — success path (verifies state file + log
|
|
file written, response shape correct, subprocess actually
|
|
called), unknown profile, no args, backend-not-installed,
|
|
and non-zero returncode records state "failed". All tests
|
|
mock the module-level BUILDER_STATE_DIR / BUILDER_LOGS_DIR
|
|
/ BUILDER_ARTIFACTS_DIR so they run hermetically.</p>
|
|
<p>AUDIT: ran an AST-based audit of bridge/builder.py to find
|
|
any other names used at module level but not imported. No
|
|
real undefined names found — every flagged item was a
|
|
comprehension local, tuple-unpacking target, except-clause
|
|
target, or __file__. The build path is now fully exercisable
|
|
by tests.</p>
|
|
<p>VERSION SYNC: bumped 0.0.49 → 0.0.50 across all 9 release
|
|
surfaces. This is a Python-only fix — no JS changes, no new
|
|
bridge subcommands, no new plugin/polkit/bridge-helper files.
|
|
All 228 unit tests pass (was 219 in v0.0.49; +9
|
|
TestBuilderBuildPath).</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.49" date="2026-08-19">
|
|
<description>
|
|
<p>v0.0.49 — BUILDER INLINE PACKAGE LIST. Per user directive:
|
|
"we should allow adding a pacman -Sy applist.txt with a
|
|
literal list of baseline apps for the profile being generated."
|
|
Both the Create Profile and Copy shipped profile forms now
|
|
include a Baseline packages textarea, a file upload input
|
|
(applist.txt), and a merge-mode toggle (append | replace).
|
|
The package list is written to the backend-specific package
|
|
file in the same operation as the scaffold/copy.</p>
|
|
<p>BACKEND COVERAGE: all 4 backends supported (mkosi, vmdb2,
|
|
archiso, live-build). Each writes to its native package-list
|
|
location: mkosi → [Packages] section of <name>.conf,
|
|
vmdb2 → bootstrap.include list in <name>.yaml, archiso
|
|
→ packages.x86_64 in the profile dir, live-build →
|
|
config/package-lists/sysdeck.list.</p>
|
|
<p>INPUT: textarea for inline paste (one package per line, #
|
|
comments allowed) AND file upload (applist.txt / .list / .conf
|
|
accepted). File upload populates the textarea via the
|
|
browser's FileReader API so the operator can review/edit
|
|
before submitting. 1 MB cap on uploaded files.</p>
|
|
<p>MERGE MODE: operator chooses per-operation via a toggle.
|
|
append (default for Copy) preserves the baseline's existing
|
|
packages, adds the operator's, deduplicates. replace (default
|
|
for Create) overwrites the baseline's package file with the
|
|
operator's list.</p>
|
|
<p>NEW BRIDGE HELPERS in bridge/builder.py: _extract_opts
|
|
(splits argv into positional + --key=value opts),
|
|
_parse_packages_text (parses multiline text into deduped
|
|
list), _write_packages_mkosi/vmdb2/archiso/live_build
|
|
(per-backend writers), _write_packages (dispatcher).
|
|
Extended profile_create() and profile_copy() to accept
|
|
--packages=<json> and --mode=append|replace.</p>
|
|
<p>UPDATED shared/bridge.js: profileCreate(name, backend, base,
|
|
packagesText, mode) and profileCopy(srcName, newName, backend,
|
|
packagesText, mode). packagesText is JSON-encoded so newlines
|
|
and quotes survive the argv boundary. When omitted, no package
|
|
file is written (back-compat with v0.0.48).</p>
|
|
<p>NEW TESTS: 28 unit tests in tests/test_bridge_parsers.py
|
|
TestBuilderPackagesField cover _parse_packages_text (6),
|
|
_extract_opts (4), per-backend writers (10), dispatcher (3),
|
|
and end-to-end profile_create/profile_copy with --packages
|
|
(5). All use tempdirs; none touch real /etc/ paths.</p>
|
|
<p>VERSION SYNC: bumped 0.0.48 → 0.0.49 across all 9 release
|
|
surfaces.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.48" date="2026-08-19">
|
|
<description>
|
|
<p>v0.0.48 — BUILDER PROFILE-CREATE BUGFIX. An operator on an
|
|
archiso-only Arch host (or a live-build-only Debian host)
|
|
reported hitting "Error: profile-create supports ('mkosi',
|
|
'vmdb2'); archiso profiles are not scaffolded (use the shipped
|
|
ones)" when trying to create a build profile.</p>
|
|
<p>ROOT CAUSE: the v0.0.31 Create Profile dropdown in
|
|
plugins/sysdeck-builder/builder.js filtered backends to
|
|
mkosi/vmdb2 — correct — but fell back to primary.id when the
|
|
filtered list was empty. On a host whose primary backend was
|
|
archiso or live-build, the dropdown offered that backend, the
|
|
operator selected it, clicked Create, and the bridge rejected
|
|
it because archiso/live-build use shipped directory-based
|
|
profile trees, not single-file specs that can be scaffolded
|
|
from scratch.</p>
|
|
<p>FIX 1: renderCreateProfile no longer falls back to
|
|
primary.id. When no mkosi/vmdb2 backend is installed, the form
|
|
renders an inline install hint with the exact pacman/apt
|
|
command instead of a dropdown that would have errored.</p>
|
|
<p>FIX 2: a new "Copy shipped profile" form
|
|
(renderCopyProfile) lists every shipped archiso and live-build
|
|
profile discovered via profiles() and offers a one-click copy
|
|
into /etc/ via the new bridge.builder.profileCopy() method.
|
|
This is the supported way to create profiles for the
|
|
directory-based backends — the panel-side answer to the
|
|
bridge's "use the shipped ones" hint that previously had no
|
|
affordance.</p>
|
|
<p>NEW BRIDGE COMMAND: bridge/builder.py profile_copy() —
|
|
copies /usr/share/archiso/configs/<src>/ →
|
|
/etc/archiso/configs/<new>/ (and the live-build
|
|
equivalent). Validates new-name (no slashes, no "."/".." to
|
|
prevent path traversal), resolves source via profiles(),
|
|
refuses non-directory-based backends with a clear "use
|
|
profile-create" hint, refuses if destination exists. Same
|
|
polkit action as profile-create (org.sysdeck.builder.modify)
|
|
— no new polkit file needed.</p>
|
|
<p>NEW BRIDGE.JS METHOD: bridge.builder.profileCopy(srcName,
|
|
newName, backend) runs with { superuser: 'try' }, same as
|
|
profileCreate / profileDelete.</p>
|
|
<p>DESTINATION ROOTS REFACTOR: ARCHISO_COPY_DEST and
|
|
LIVE_BUILD_COPY_DEST are now module-level constants in
|
|
bridge/builder.py (was: hardcoded inside profile_copy).
|
|
Mirrors the existing ARCHISO_DIRS / LIVE_BUILD_DIRS pattern
|
|
and lets unit tests patch them with tempdirs.</p>
|
|
<p>NEW TESTS: 15 unit tests in tests/test_bridge_parsers.py
|
|
TestBuilderProfileCopy cover arg validation, source
|
|
resolution (not-found, wrong-backend, mkosi/vmdb2 rejection),
|
|
success paths (archiso + live-build), and failure modes
|
|
(dest-exists, source-not-a-dir, permission-error-with-polkit-
|
|
hint). All use tempdirs and mock.patch; none touch real /etc/
|
|
or /usr/share/ paths.</p>
|
|
<p>VERSION SYNC: bumped 0.0.47 → 0.0.48 across all 9 release
|
|
surfaces (Makefile, bridge/__init__.py, packaging/setup.py,
|
|
PKGBUILD, RPM spec, debian/changelog, compat-manifest.json,
|
|
metainfo.xml, README.md).</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.47" date="2026-08-18">
|
|
<description>
|
|
<p>v0.0.47 — LOGIC-FLAW FIXES. Per user directive: "we need to
|
|
fix a few logic flaws i do things a certain way on my servers
|
|
so ill correct the ports on a firewall script or two. the web
|
|
server template, and vps template i setup the webserver on
|
|
8080 and varnish on 80 for an automatic cache environment. we
|
|
should move the service/ports editor to its own module entry
|
|
for ease of access. the glances we should default to enabling
|
|
the built in webui and embedding that into our module instead
|
|
it visually looks stunning in comparison to ours."</p>
|
|
<p>FIREWALL: public-webserver.sh PORT-TOPOLOGY FIX. The v0.0.44
|
|
template had the cache topology backwards — it exposed Caddy on
|
|
:80 and Varnish on :8080. v0.0.47 flips it: Varnish is the
|
|
public cache front on :80, Caddy HTTP backend lives on :8080
|
|
(loopback only), Caddy HTTPS lives on :443 (public, terminates
|
|
TLS). The VARNISH_PUBLIC toggle is removed — :8080 is now
|
|
ALWAYS loopback-only (the previous default exposed the
|
|
cache-miss path to the internet, bypassing Varnish entirely).
|
|
Defense-in-depth drops added for :8080 alongside the existing
|
|
MariaDB + Caddy admin drops.</p>
|
|
<p>FIREWALL: vps-webserver.sh DEFAULT TOPOLOGY. When Varnish is
|
|
detected at all, the operator's documented setup is now the
|
|
explicit default — Varnish on :80, Caddy HTTP backend on :8080
|
|
(loopback only), Caddy HTTPS on :443. Previously this only
|
|
happened if Varnish was already listening on :80 at runtime;
|
|
now detecting Varnish is enough to flip Caddy HTTP to :8080
|
|
loopback.</p>
|
|
<p>NEW PLUGIN: sysdeck-services — first-class sidebar entry at
|
|
order 45. The Service/Port Editor card that lived at the bottom
|
|
of the Firewall panel since v0.0.44 has been lifted out into
|
|
its own module. Adds a filter box (search by name/id/port/
|
|
process), a show-only-editable toggle, and a Refresh button.
|
|
The bridge surface (bridge.firewall.services / service-info /
|
|
set-service-port / restart-service) is unchanged; a new
|
|
bridge.services proxy was added to bridge.js so the new panel
|
|
has a clean API.</p>
|
|
<p>GLANCES: DEFAULT-ON EMBEDDED WEBUI. The panel now auto-starts
|
|
the Glances built-in webserver (glances -w --bind 127.0.0.1
|
|
--port 61208) on mount — no click required. The iframe is now
|
|
the primary view, sized to fill the viewport (min-height:
|
|
calc(100vh - 200px)). The legacy SysDeck snapshot cards are
|
|
moved into a collapsed details element at the bottom of the
|
|
page so they don't push the iframe below the fold. Manifest
|
|
CSP updated to allow frame-src http://127.0.0.1:61208 +
|
|
http://localhost:61208.</p>
|
|
<p>VERSION SYNC: bumped 0.0.46 → 0.0.47 across all 9 release
|
|
surfaces. Also caught up bridge/__init__.py + packaging/setup.py
|
|
from 0.0.45 (the v0.0.46 release bumped PKGBUILD/spec/debian
|
|
but missed these two files).</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.46" date="2026-08-18">
|
|
<description>
|
|
<p>v0.0.46 — IN-SUITE 3RD-PARTY MODULE INSTALLER. Per user
|
|
directive: "i wanted the in ui module to handle showing license,
|
|
developer, 3rd party model name and ability to visit homepage
|
|
and install the plugin 1 click with license agreement inline."</p>
|
|
<p>NEW PLUGIN: sysdeck-modules — a first-class sidebar entry at
|
|
order 44 that replaces the side-channel cockpit-module-pull.sh
|
|
shell script. Each catalog row shows the module name, a license
|
|
badge (MIT / LGPL-2.1 / GPL-3.0 etc.), the developer/author,
|
|
the source URL, and a clickable homepage link — all rendered
|
|
INLINE next to a 1-click Install button. Clicking Install is
|
|
the operator's acceptance of the inline-displayed license. No
|
|
modal, no separate confirmation step.</p>
|
|
<p>NEW BRIDGE: bridge/modules3p.py — a 10-entry catalog covering
|
|
cockpit-machines, cockpit-podman, cockpit-storaged,
|
|
cockpit-identities, cockpit-navigator, cockpit-file-sharing,
|
|
cockpit-zfs-manager, cockpit-pacman, cockpit-sensors, and
|
|
cockpit-benchmark. Four install kinds: pacman (native package),
|
|
git (depth-1 clone), deb-tar (extract data.tar.xz from a .deb),
|
|
tarball (curl + tar -x). The bridge refuses silent installs
|
|
(no --accept-license=1 ⇒ license-not-accepted) as a guard
|
|
against malicious callers.</p>
|
|
<p>NEW POLKIT ACTION: org.sysdeck.modules3p.modify authorizes
|
|
/usr/bin/python3 /usr/lib/sysdeck/bridge/modules3p.py install|
|
|
uninstall <id> with auth_admin_keep for active sessions.</p>
|
|
<p>AUDIT LOG: every install / uninstall appends a JSON record
|
|
to /etc/cockpit/MODULE_LICENSES.log (shared with the legacy
|
|
cockpit-module-pull.sh). Legacy plain-text lines are preserved
|
|
as {raw: ...} records.</p>
|
|
<p>SHARED bridge.js: added bridge.modules3p surface with
|
|
catalog / status / preflight / install / uninstall / audit
|
|
methods. install + uninstall use { superuser: 'try' }.</p>
|
|
<p>THIRD_PARTY.md: appended v0.0.46 section documenting the
|
|
in-suite installer + per-entry catalog table. Updated existing
|
|
"see cockpit-module-pull.sh" notes to point at the new panel.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.35" date="2026-08-18">
|
|
<description>
|
|
<p>v0.0.35 — KATA SPLIT + THREE NEW MODULES. Per user directive:
|
|
"kata containers should be called SysDeck Kata and moved out
|
|
of the tools area. and dont call it hidden thats akward. next
|
|
we will integrate a jellyfin management module where it starts,
|
|
stops, and loads the admin panel in the module as well as a
|
|
photo manager of equal quality. with its own module. then a
|
|
remote fs manager such as ceph, and others but not nfs or
|
|
amanada fs"</p>
|
|
<p>KATA RESTORED AS STANDALONE SIDEBAR ENTRY. The Kata Containers
|
|
plugin was demoted to a hidden "tools" entry inside the merged
|
|
Containers & VMs panel in v0.0.34 — labeled "Kata Containers
|
|
(hidden helper)" with priority -1. v0.0.35 splits Kata back out:
|
|
renamed to <strong>SysDeck Kata</strong>, moved from
|
|
plugins/sysdeck-containers-kata/ to plugins/sysdeck-kata/,
|
|
converted from a "tools" manifest entry to a "menu" entry
|
|
(label "SysDeck Kata", order 27), removed the "hidden helper"
|
|
wording, dropped the priority -1, and added a dedicated
|
|
keywords list. The Containers panel now manages Podman only —
|
|
the Kata tab and its iframe were removed. The pre-built
|
|
cockpit-kata React bundle (index.js + index.css) is shipped
|
|
unchanged.</p>
|
|
<p>JELLYFIN MODULE. New plugin plugins/sysdeck-jellyfin/
|
|
(manifest.json + index.html + jellyfin.js) + new bridge helper
|
|
bridge/jellyfin.py. Surfaces: summary, status, start, stop,
|
|
restart, web-status, libraries. The bridge runs
|
|
<code>systemctl start/stop/restart jellyfin.service</code>
|
|
via the cockpit superuser channel (polkit
|
|
org.sysdeck.jellyfin.modify); the panel iframes the running
|
|
Jellyfin admin UI at http://127.0.0.1:8096 — same pattern as
|
|
the v0.0.34 Glances integration. Library list is best-effort
|
|
via GET /Library/VirtualFolders on the local Jellyfin instance.</p>
|
|
<p>PHOTO MANAGER MODULE. New plugin plugins/sysdeck-photos/
|
|
+ new bridge helper bridge/photos.py. Multi-backend design
|
|
(same shape as the DB Control module): PhotoPrism (port 2342,
|
|
MIT), Piwigo (port 80, GPL-2.0), Lychee (port 80, MIT),
|
|
Nextcloud-Memories (port 80, AGPL-3.0), LibrePhotos (port 3000,
|
|
MIT). Each backend is auto-detected via CLI tool / systemd unit
|
|
/ config-dir presence; the bridge runs <code>systemctl
|
|
start/stop/restart <service></code> for the chosen backend
|
|
and the panel iframes its admin UI when running. Polkit action:
|
|
org.sysdeck.photos.modify.</p>
|
|
<p>REMOTE FS MANAGER MODULE. New plugin plugins/sysdeck-remotefs/
|
|
+ new bridge helper bridge/remotefs.py. Multi-backend: Ceph
|
|
(LGPL-2.1), GlusterFS (GPL-2.0), MooseFS (GPL-2.0), BeeGFS
|
|
(BeeGFS EULA — free), OrangeFS (BSD-3). Each backend is
|
|
auto-detected; the bridge runs <code>systemctl start/stop/
|
|
restart <service></code> and the cluster-info subcommand
|
|
queries backend-specific cluster status (<code>ceph status
|
|
--format=json</code>, <code>gluster pool list</code>,
|
|
<code>moosefs-cli info</code>, <code>beegfs-ctl --listnodes</code>,
|
|
<code>pvfs2-server -m</code>). Polkit action:
|
|
org.sysdeck.remotefs.modify authorizes the systemctl binary plus
|
|
ceph/gluster/moosefs-cli/beegfs-ctl/pvfs2-server CLIs. NFS and
|
|
Amanda are explicitly EXCLUDED per directive — documented in
|
|
the panel footer and in bridge/remotefs.py:EXCLUDED.</p>
|
|
<p>PLUGIN COUNT: 20 → 23. The v0.0.34 hidden helper
|
|
(sysdeck-containers-kata) is renamed to sysdeck-kata and
|
|
promoted to a visible sidebar entry; three new visible modules
|
|
are added. tests/check_manifest_consistency.py expected count
|
|
updated to 23. scripts/generate-plugins.py updated to back
|
|
up + restore hand-maintained plugins (sysdeck-kata ships a
|
|
pre-built React bundle that can't be regenerated by the suite
|
|
generator).</p>
|
|
<p>VERSION SYNC. Makefile, bridge/__init__.py, packaging/setup.py,
|
|
packaging/PKGBUILD, packaging/sysdeck.spec, packaging/debian/
|
|
changelog, compat/compat-manifest.json all bumped to 0.0.35.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.30" date="2026-08-17">
|
|
<description>
|
|
<p>BUILDER MODULE REWRITE — target distros are now Arch Linux
|
|
and Debian. The previous bridge/builder.py was a thin
|
|
`systemctl is-active osbuild-composer.service` shim. osbuild-
|
|
composer is Fedora/RHEL-only and is not packaged for Arch or
|
|
Debian, so the Builder panel was permanently 'inactive' on
|
|
every distro this suite actually ships to.</p>
|
|
<p>Rewritten bridge/builder.py detects and surfaces the
|
|
canonical image-builder backends for the target distros:
|
|
Arch Linux uses mkosi (primary, systemd's image builder) plus
|
|
archiso (bootable Live ISOs); Debian uses vmdb2 (primary, the
|
|
Debian project's own image builder) plus live-build (Debian
|
|
Live ISOs). Detection is via shutil.which() — works on any
|
|
distro, and a Debian host with mkosi installed is still
|
|
surfaced correctly.</p>
|
|
<p>New Python subcommands: status, profiles, summary, backends,
|
|
install-hint. `summary` returns combined status + profiles in
|
|
one call so the panel renders from a single bridge spawn.
|
|
Profile discovery walks well-known config dirs per backend:
|
|
/etc/mkosi/mkosi.conf[.d/*.conf] + mkosi.profiles/*.profile for
|
|
mkosi; /usr/share/archiso/configs/* + /etc/archiso/configs/*
|
|
for archiso; /etc/vmdb2/*.yaml + /usr/share/vmdb2/specs/*.yaml
|
|
for vmdb2; any dir under /etc|/usr/share|~/.config/live-build
|
|
containing a `config/` subdir for live-build.</p>
|
|
<p>Rewrote plugins/sysdeck-builder/builder.js: replaces the
|
|
composer-cli blueprints list call with bridge.builder.summary().
|
|
Renders per-backend profile cards (grouped by backend) and
|
|
shows a distro-specific install hint when no backend is
|
|
installed (e.g. "sudo pacman -S --needed mkosi" on Arch,
|
|
"sudo apt install -y vmdb2" on Debian).</p>
|
|
<p>Updated shared/bridge.js builder surface — exposes
|
|
summary/profiles/status/backends/installHint. Updated
|
|
packaging/polkit/org.sysdeck.policy: org.sysdeck.builder.modify
|
|
action now authorizes /usr/bin/mkosi, /usr/bin/mkarchiso,
|
|
/usr/bin/vmdb2, /usr/bin/lb. osbuild + livemedia-creator
|
|
annotations removed (Fedora-only, no longer targeted).
|
|
Updated packaging/PKGBUILD optdepends: added mkosi and archiso.
|
|
Updated packaging/debian/control Suggests: added mkosi, vmdb2,
|
|
archiso, live-build. Updated compat/compat-manifest.json
|
|
builder entry: Arch and Debian distro_support upgraded from
|
|
'none' to 'full'; Fedora entry repointed from osbuild-composer
|
|
to mkosi (cross-distro). Updated plugins/sysdeck-builder/
|
|
manifest.json keywords and scripts/generate-plugins.py —
|
|
replaced 'osbuild' keyword with 'mkosi', 'vmdb2', 'archiso',
|
|
'live-build'. Synced docs (README.md, QUICKSTART.md, BLOG.md,
|
|
QA.md, docs/INSTALL.md, THIRD_PARTY.md).</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.29" date="2026-08-17">
|
|
<description>
|
|
<p>EMAIL MIGRATION: author/maintainer contact address changed
|
|
from jeremy@dcos.net to info@dcos.net across every release
|
|
surface (debian/changelog, debian/control, setup.py, PKGBUILD,
|
|
sysdeck.spec). The author name "Jeremy Anderson" is preserved
|
|
everywhere; only the email address is replaced — the project
|
|
moved to a shared info@ inbox.</p>
|
|
<p>REMOVED DUPLICATE CONTAINER ENTRY: deleted
|
|
standalone-plugins/cockpit-podman/. Podman ships its own
|
|
native Cockpit module upstream, so bundling a second
|
|
cockpit-podman manifest here was duplicating upstream —
|
|
installing both would produce two competing sidebar entries
|
|
pointing at the same backend.</p>
|
|
<p>NEW standalone-plugins/cockpit-incus/manifest.json: sidebar
|
|
link (order 46, gated on /usr/bin/incus) for Incus system
|
|
container and VM management. Incus is the LXC/LXD successor
|
|
maintained by the Linux Containers project. This slot was the
|
|
original intent for the third standalone plugin slot, which
|
|
had been mis-assigned to podman.</p>
|
|
<p>UPDATED compat/compat-manifest.json: the
|
|
standalone_plugins.cockpit-podman entry is replaced with
|
|
standalone_plugins.cockpit-incus. Per-distro install commands:
|
|
pacman -S incus (Arch), dnf install incus (Fedora 40+),
|
|
apt install incus (Debian 13 trixie / bookworm backports).
|
|
Distro support: full on all three target distros.</p>
|
|
<p>UPDATED sysdeck-diagnose.sh: section 13 reference loop now
|
|
iterates over cockpit-incus / cockpit-machines / cockpit-ostree
|
|
(was cockpit-podman / cockpit-machines / cockpit-ostree).
|
|
Section 14 comparison text updated to refer to "the reference
|
|
plugins above" instead of "the cockpit-podman reference".</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.28" date="2026-08-17">
|
|
<description>
|
|
<p>FIXED 2 BROKEN BRIDGE SUBCOMMANDS that slipped through v0.0.27's
|
|
"subcommand alignment" pass:</p>
|
|
<ul>
|
|
<li>firmware.py: bridge.js called `python3 firmware.py devices` but
|
|
the helper only implemented `summary`. Every visit to the Firmware
|
|
plugin page crashed with "Unknown subcommand: devices". Added a
|
|
real `devices` subcommand returning fwupdmgr's native
|
|
{Devices: [...]} shape (capital D, matches the panel's expected
|
|
access pattern).</li>
|
|
<li>benchmark.py: bridge.js called `python3 benchmark.py run-test
|
|
<name>` when the user clicked "Run" in the Available Tests
|
|
table, but the helper had no `run-test` subcommand. Added
|
|
`run-test` that runs `sysbench <name> run` and returns the
|
|
parsed result dict — same shape as run-cpu/run-memory/run-io.</li>
|
|
</ul>
|
|
<p>NEW BUILD-TIME GUARD: `check-bridge-subcommands` in `make check`.
|
|
Cross-checks every bridgeCmd() call in shared/bridge.js against the
|
|
COMMANDS dict declared in each bridge/<module>.py. Would have
|
|
caught both bugs above. Negative-tested: a summary-only firmware.py
|
|
its v0.0.27 state causes the guard to fail with a clear message.</p>
|
|
<p>FIXED MISSING CSS CLASSES: shared/sysdeck.css was missing
|
|
.suite-progress, .suite-progress-bar, .suite-progress-fill,
|
|
.suite-stat-value, .suite-stat-label, .suite-row, .suite-row-between,
|
|
.suite-grid, .cols-2, .cols-3, .suite-col-2, .suite-col-3,
|
|
.suite-btn-primary, .suite-badge.info, .suite-input, .suite-warn.
|
|
Without them, progress bars in glances/fleet/netsec were invisible
|
|
and multi-column layouts collapsed to a single column. All added.</p>
|
|
<p>FIXED COCKPIT-SMOKE-TEST.SH: the embedded manifest used
|
|
"requires": { "cockpit": ">=239" } — the broken pattern Cockpit
|
|
silently rejects. Smoke test would produce a false "Cockpit is
|
|
broken" diagnostic. Fixed to "cockpit": "239" (bare number).</p>
|
|
<p>IMPROVED DIAGNOSTIC: sysdeck-diagnose.sh now verifies
|
|
/usr/lib/sysdeck/bridge/*.py exists and is executable, and spot-
|
|
checks firmware.py `devices` and benchmark.py `run-test`
|
|
subcommands work end-to-end.</p>
|
|
<p>FIXED DOCS: bridge/__init__.py docstring still showed the broken
|
|
`python3 -m sysdeck.bridge.<module>` invocation pattern that
|
|
was fixed in v0.0.26. Updated to the absolute-path invocation.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.27" date="2026-08-17">
|
|
<description>
|
|
<p>FIXED 6 MISSING PYTHON HELPERS: mining.py, builder.py, fester.py,
|
|
kata.py, vault.py, mesh.py were never written — every plugin that
|
|
called one got "Module load failed: can't open file". Wrote minimal
|
|
stubs that return empty data so modules render with "no items".</p>
|
|
<p>FIXED 4 SUBCOMMAND MISMATCHES: bridge.js called subcommands the
|
|
Python helpers didn't have. Now aligned with the actual COMMANDS
|
|
dict in each helper: auth.smartcards→slots,
|
|
netsec.listeningPorts→sockets, integrity.trustScore→score,
|
|
integrity.runLynis→scan, firewall.listChains→chains,
|
|
firewall.listRules→ruleset, fleet.uptime/nodeCount derive from
|
|
summary, firmware.tpmInfo reads PCR0 directly via tpm2_pcrread.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.26" date="2026-08-17">
|
|
<description>
|
|
<p>ROOT CAUSE FOUND AND FIXED: every plugin that called a bridge
|
|
helper failed with ModuleNotFoundError: No module named
|
|
'sysdeck.bridge'. Cause: shared/bridge.js called
|
|
`python3 -m sysdeck.bridge.<module>`, which requires a Python
|
|
package layout (sysdeck/bridge/<module>.py) that doesn't exist
|
|
in the install. The actual layout is
|
|
/usr/lib/sysdeck/bridge/<module>.py (flat files, not a nested
|
|
package).</p>
|
|
<p>Fix: changed bridgeCmd() to call helpers by absolute path:
|
|
`python3 /usr/lib/sysdeck/bridge/<module>.py <args>`.
|
|
No package layout, no PYTHONPATH, no symlink needed.</p>
|
|
<p>Note: only firmware/fleet/themes 'worked' in v0.0.25 because they
|
|
use Promise.allSettled() (catches rejections silently) or
|
|
cockpit.file() (no Python helper needed) — they were showing
|
|
'unavailable' cards, not real data.</p>
|
|
<p>New guard: check-no-broken-python-module in `make check`.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.25" date="2026-08-17">
|
|
<description>
|
|
<p>ROOT CAUSE FOUND AND FIXED: every plugin page showed "Module load
|
|
failed: error loading dynamically imported module:
|
|
http://127.0.0.1:9090/cockpit/@localhost/sysdeck-common/bridge.js".</p>
|
|
<p>Cause: shared/sysdeck-common/ had bridge.js and sysdeck.css but NO
|
|
manifest.json. Cockpit only registers a directory as a package if it
|
|
contains manifest.json (packages.py:457 scans cockpit/*/manifest.json).
|
|
Without registration, every URL like
|
|
/cockpit/@localhost/sysdeck-common/bridge.js returned 404, and the
|
|
dynamic import("../sysdeck-common/bridge.js") failed.</p>
|
|
<p>Fix: added shared/manifest.json with name="sysdeck-common". Pattern
|
|
verified from cockpit's own pkg/static/manifest.json (just `{}`).</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.24" date="2026-08-17">
|
|
<description>
|
|
<p>THOROUGH UNINSTALLER: previous `make uninstall` only removed
|
|
/usr/share/cockpit/sysdeck-* (with dash). v0.0.9-v0.0.19 installed
|
|
to /usr/share/cockpit/sysdeck/ (no dash) — that directory was NEVER
|
|
removed by uninstall, leaving stale manifests that Cockpit would
|
|
discover alongside the new ones. v0.0.24 uninstall now removes
|
|
every prior-version install path.</p>
|
|
<p>VISIBLE ERROR REPORTING: every plugin's index.html now installs
|
|
window error handlers that replace "Loading…" with the actual
|
|
error message on the page. No devtools required.</p>
|
|
<p>COCKPIT.JS PRESENCE CHECK: every plugin's index.html checks
|
|
`if (!window.cockpit)` before importing bridge.js, and shows a
|
|
clear error if cockpit.js failed to load.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.23" date="2026-08-17">
|
|
<description>
|
|
<p>ROOT CAUSE FOUND AND FIXED: every plugin page was stuck on "Loading…"
|
|
because shared/bridge.js did `import cockpit from "../base1/cockpit.js"`
|
|
— an ES module import. But pkg/base1/cockpit.js is NOT an ES module:
|
|
it's a UMD/IIFE that sets window.cockpit as a global. The import
|
|
returned undefined, so cockpit.spawn() threw when mount() ran, and
|
|
the plugin page never rendered.</p>
|
|
<p>Fix: replaced the broken import with `const cockpit = window.cockpit`
|
|
— exactly how cockpit's own esbuild plugin (build.js:71-83) accesses
|
|
it after rewriting `import cockpit from "cockpit"` to
|
|
`module.exports = cockpit`.</p>
|
|
<p>New guard: check-no-broken-cockpit-import in `make check` scans
|
|
every JS file for the broken pattern. Regression-tested.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.22" date="2026-08-17">
|
|
<description>
|
|
<p>ROOT CAUSE FOUND AND FIXED: the requires.cockpit field was set to
|
|
">=239" in every manifest since v0.0.9. Cockpit's packages.py uses
|
|
sortify_version() (a 0-pad of numeric components) to compare versions,
|
|
NOT a semver parser. ">=239" becomes ">=00000239" which is GREATER than
|
|
any real cockpit version, causing packages.py:263 to raise JsonError
|
|
and silently reject every manifest at install time.</p>
|
|
<p>Fix: changed requires.cockpit from ">=239" to "239" (bare number) in
|
|
all 18 manifests. This matches the pattern in cockpit's own
|
|
pkg/systemd/manifest.json ("cockpit": "265").</p>
|
|
<p>Also renamed all 18 sidebar labels from "SD <Name>" to
|
|
"SysDeck <Name>" per user requirement: SysDeck should never be
|
|
abbreviated.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.21" date="2026-08-17">
|
|
<description>
|
|
<p>Fix AppStream metainfo: use <launchable type="cockpit-manifest">
|
|
instead of <provides><cockpit-manifest> — matching the pattern
|
|
used by cockpit-project's own plugins in src/appstream/.</p>
|
|
<p>Rewrite tests/check_manifest_consistency.py to validate against the
|
|
REAL Cockpit manifest contract from pkg/shell/manifests.ts and
|
|
src/cockpit/packages.py, not the invented contract used in v0.0.19-v0.0.20.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.20" date="2026-08-17">
|
|
<description>
|
|
<p>ARCHITECTURAL OVERHAUL: split the single SysDeck shell into 18
|
|
standalone Cockpit plugins.</p>
|
|
</description>
|
|
</release>
|
|
<release version="0.0.19" date="2026-08-17">
|
|
<description>
|
|
<p>Rewrote manifest to match cockpit-podman reference pattern.</p>
|
|
</description>
|
|
</release>
|
|
</releases>
|
|
</component>
|