Add catatonit/nftables/docker-compose packages, fix CSRF/streaming/storage bugs found by live testing

- Package #9-11: catatonit (pod infra init), nftables (netavark firewall
  backend), docker-compose (external compose provider for `podman compose`)
  — all vendored prebuilt binaries, versions.env pinned, propagated through
  build-packages.sh/release.sh/podman.plg/verify+update-packages.sh.
- Fix WebUI: every POST action was silently failing (empty response body)
  because Unraid's own CSRF protection was never satisfied — app.js now
  sends the page's csrf_token as X-CSRF-Token.
- Fix WebUI: PodmanClient::pullImage() assumed a single JSON response, but
  /images/pull actually streams newline-delimited JSON — every successful
  pull was throwing "Expected a JSON object/array response".
- Fix WebUI: compose.php's up/down status detection had the same
  single-JSON-vs-NDJSON bug for `podman compose ps`, plus stderr was
  corrupting the parse.
- Add cache-busting (?v=<mtime>) to Podman.page's script/style tags so a
  redeployed JS/CSS fix isn't served stale from browser cache.
- Add a reusable modal dialog (app.js openFormModal) replacing
  prompt()/alert() for New Volume/Network/Pull Image.
- Add host-path (bind-mount) support when creating a named volume.
- Add Create Container (image, name, network mode incl. custom networks,
  ports, volumes, env, restart policy, privileged, start-after-create),
  auto-pulling the image on first use since /containers/create doesn't.

All fixes verified live against a real podman system service and, where
reachable, via the actual WebUI over the real socket — not just unit-level.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-12 11:51:17 +00:00
co-authored by Claude Sonnet 5
parent 5944ddf722
commit 5b47b4cc0a
33 changed files with 1075 additions and 87 deletions
+66 -8
View File
@@ -32,14 +32,16 @@
Structure of this file:
1. DOCTYPE entity block — plugin metadata + one version/file/md5 triple
per package (the seven upstream components plus this project's own
"unraid-podman" scaffolding package, see packages/unraid-podman/).
per package (the seven upstream components, catatonit/nftables/
docker-compose as vendored runtime dependencies, plus this
project's own "unraid-podman" scaffolding package, see
packages/unraid-podman/).
Entities are rewritten automatically by scripts/release.sh; never
hand-edit a *_txz_version/_file/_md5 entity — see that script.
2. <PLUGIN> body:
a. <CHANGES> — kept in sync with CHANGELOG.md by hand for now.
b. Pre-install architecture sanity check.
c. Eight <FILE> package install/update blocks.
c. Eleven <FILE> package install/update blocks.
d. Postinstall <FILE Run="/bin/bash"> — directory/config seeding,
install-manifest generation, first start.
e. <FILE Run="/bin/bash" Method="remove"> — uninstall.
@@ -65,8 +67,8 @@
<!-- Slackware package naming components — must match versions.env's
PKG_ARCH/PKG_BUILD/PKG_TAG (see that file). Kept as entities here so
the eight removepkg calls in the Method="remove" block don't have to
repeat "x86_64-1_unraidpodman" eight times by hand. -->
the eleven removepkg calls in the Method="remove" block don't have to
repeat "x86_64-1_unraidpodman" eleven times by hand. -->
<!ENTITY pkgArch "x86_64">
<!ENTITY pkgBuild "1">
<!ENTITY pkgTag "_unraidpodman">
@@ -106,6 +108,27 @@
<!ENTITY fuse_overlayfs_txz_file "fuse-overlayfs-&fuse_overlayfs_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY fuse_overlayfs_txz_md5 "00000000000000000000000000000000">
<!-- catatonit and nftables are runtime dependencies this plugin ships,
not upstream podman-ecosystem components — see packages/catatonit/
and packages/nftables/ READMEs for why each is needed (pod infra
container init; netavark's only viable firewall driver, since it
dropped iptables in 2.0 and Unraid has neither `nft` nor
systemd/dbus for firewalld) and why neither is built from source. -->
<!ENTITY catatonit_txz_version "0.0.0">
<!ENTITY catatonit_txz_file "catatonit-&catatonit_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY catatonit_txz_md5 "00000000000000000000000000000000">
<!ENTITY nftables_txz_version "0.0.0">
<!ENTITY nftables_txz_file "nftables-&nftables_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY nftables_txz_md5 "00000000000000000000000000000000">
<!-- docker-compose is the external Compose provider `podman compose`
shells out to (see packages/docker-compose/README.md) — without it
every Compose panel action fails outright on a clean install. -->
<!ENTITY docker_compose_txz_version "0.0.0">
<!ENTITY docker_compose_txz_file "docker-compose-&docker_compose_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY docker_compose_txz_md5 "00000000000000000000000000000000">
<!-- unraid-podman is this project's OWN scaffolding package (rc.podman,
sbin/ scripts, event/ hooks, config templates — see
packages/unraid-podman/README.md), not an upstream component. Its
@@ -145,7 +168,7 @@
<!--
Pre-install sanity check: this project only builds/ships x86_64 packages
(see versions.env's PKG_ARCH) — fail with a clear message on any other
architecture rather than letting eight package downloads 404 one by one.
architecture rather than letting eleven package downloads 404 one by one.
-->
<FILE Run="/bin/bash">
<INLINE>
@@ -157,7 +180,9 @@ fi
</FILE>
<!--
The seven upstream component packages. Each is downloaded straight into
The seven upstream component packages, plus catatonit, nftables, and
docker-compose (runtime dependencies vendored as-is — see the entity
block above for why). Each is downloaded straight into
its backup slot under /boot/config/plugins/&name;/backup/packages/&version;/
(grouped by PLUGIN version, not each component's own version — a rollback
targets "this plugin release" as one unit, see
@@ -232,6 +257,33 @@ fi
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&catatonit_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&catatonit_txz_file;
</URL>
<MD5>
&catatonit_txz_md5;
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&nftables_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&nftables_txz_file;
</URL>
<MD5>
&nftables_txz_md5;
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&docker_compose_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&docker_compose_txz_file;
</URL>
<MD5>
&docker_compose_txz_md5;
</MD5>
</FILE>
<!--
The plugin's own scaffolding package — rc.podman, sbin/ helper scripts,
the event/ hooks below, and default config templates. See
@@ -247,7 +299,7 @@ fi
</FILE>
<!--
Postinstall: everything that has to happen AFTER the eight packages above
Postinstall: everything that has to happen AFTER the eleven packages above
are on disk, but isn't itself package content — directory/config
seeding, the install-manifest that plugin/sbin/podman-verify-packages.sh
and podman-update-packages.sh read, and the first start. Runs on both
@@ -291,6 +343,9 @@ echo "NETAVARK_INSTALLED_VERSION=\"&netavark_txz_version;\"" >> "$MANIFEST"
echo "AARDVARK_DNS_INSTALLED_VERSION=\"&aardvark_dns_txz_version;\"" >> "$MANIFEST"
echo "PASST_INSTALLED_VERSION=\"&passt_txz_version;\"" >> "$MANIFEST"
echo "FUSE_OVERLAYFS_INSTALLED_VERSION=\"&fuse_overlayfs_txz_version;\"" >> "$MANIFEST"
echo "CATATONIT_INSTALLED_VERSION=\"&catatonit_txz_version;\"" >> "$MANIFEST"
echo "NFTABLES_INSTALLED_VERSION=\"&nftables_txz_version;\"" >> "$MANIFEST"
echo "DOCKER_COMPOSE_INSTALLED_VERSION=\"&docker_compose_txz_version;\"" >> "$MANIFEST"
echo "UNRAID_PODMAN_INSTALLED_VERSION=\"&unraid_podman_txz_version;\"" >> "$MANIFEST"
echo "Seeding /boot/config/plugins/podman/ configuration (existing files left untouched)..."
@@ -351,6 +406,9 @@ removepkg &netavark_txz_file;
removepkg &aardvark_dns_txz_file;
removepkg &passt_txz_file;
removepkg &fuse_overlayfs_txz_file;
removepkg &catatonit_txz_file;
removepkg &nftables_txz_file;
removepkg &docker_compose_txz_file;
removepkg &unraid_podman_txz_file;
echo ""
+2 -2
View File
@@ -23,7 +23,7 @@
# needed — see docs/ARCHITECTURE.md section 13.1.
#
# Usage:
# podman-update-packages.sh # reconcile all 7 packages
# podman-update-packages.sh # reconcile all 11 packages
# podman-update-packages.sh podman # reconcile a single package
# =============================================================================
@@ -34,7 +34,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "$SCRIPT_DIR/podman-common.sh"
INSTALLED_VERSIONS_FILE="/usr/local/share/unraid-podman/installed-versions.env"
ALL_PACKAGES="podman conmon crun netavark aardvark-dns passt fuse-overlayfs unraid-podman"
ALL_PACKAGES="podman conmon crun netavark aardvark-dns passt fuse-overlayfs catatonit nftables docker-compose unraid-podman"
if [ ! -f "$INSTALLED_VERSIONS_FILE" ]; then
podman_log_error "update-packages: $INSTALLED_VERSIONS_FILE missing — plugin install metadata not found"
+3 -3
View File
@@ -2,7 +2,7 @@
# =============================================================================
# plugin/sbin/podman-verify-packages.sh
#
# "Pakete prüfen" — verifies the seven packages this plugin ships are
# "Pakete prüfen" — verifies the eleven packages this plugin ships are
# actually installed, at the version the plugin expects, and that the
# backed-up .txz copies (see podman-backup.sh) haven't bit-rotted on disk.
#
@@ -34,7 +34,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "$SCRIPT_DIR/podman-common.sh"
INSTALLED_VERSIONS_FILE="/usr/local/share/unraid-podman/installed-versions.env"
PACKAGES="podman conmon crun netavark aardvark-dns passt fuse-overlayfs unraid-podman"
PACKAGES="podman conmon crun netavark aardvark-dns passt fuse-overlayfs catatonit nftables docker-compose unraid-podman"
QUIET=0
[ "${1:-}" = "--quiet" ] && QUIET=1
@@ -95,7 +95,7 @@ for name in $PACKAGES; do
esac
# --- Check 3: backup artifact integrity, if present --------------------
# Packages of all 7 components released together as one plugin version
# Packages of all components released together as one plugin version
# are grouped under a single PLUGIN_VERSION directory (not per-component
# version) — a rollback targets "go back to plugin release X", matching
# podman-backup.sh's restore-packages <plugin-version>.