fix: container installs, Tor, kiosk, GRUB, LUKS display, error messages

Critical:
- fix: container installs fail with "statfs: no such file or directory"
  Root cause: NoNewPrivileges=yes in systemd blocks sudo inside backend.
  Fix: use std::fs::create_dir_all + podman unshare chown (no sudo needed)
- fix: Tor services.json never written — \$ARCHY_TOR_DIR escaping bug
- fix: kiosk white screen — increase health wait to 60s, add --disable-gpu

Improvements:
- feat: LUKS encryption badge in Server disk stats (backend detects dm-crypt)
- fix: GRUB theme text scaling on 4:3 monitors — explicit fonts, wider menu
- fix: suppress default Debian MOTD (custom profile.d welcome is enough)
- fix: install error messages now show "Failed to pull/start" instead of
  generic "Operation failed" (middleware.rs allowlist expanded)
- fix: container-tests CI — source cargo env before running tests
- docs: interactive container architecture diagram (HTML)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-30 16:35:06 +01:00
co-authored by Claude Opus 4.6
parent 77765c90d0
commit 44bffee473
9 changed files with 522 additions and 37 deletions
@@ -472,18 +472,31 @@ impl RpcHandler {
if let Some(host_path) = volume.split(':').next() {
if host_path.starts_with("/var/lib/archipelago/") {
debug!("Creating directory: {} (owner: {})", host_path, uid_str);
let create_dir = tokio::process::Command::new("sudo")
.args(["mkdir", "-p", host_path])
.output()
.await;
if let Err(e) = create_dir {
debug!("Failed to create directory {}: {}", host_path, e);
// Create directory directly (service has ReadWritePaths access).
// sudo is blocked by NoNewPrivileges=yes in the systemd service.
if let Err(e) = std::fs::create_dir_all(host_path) {
tracing::warn!("Failed to create directory {}: {}", host_path, e);
}
// Set ownership to the mapped UID for rootless podman
let _ = tokio::process::Command::new("sudo")
.args(["chown", "-R", &uid_str, host_path])
// Set ownership to the mapped UID for rootless podman.
// This needs elevated privileges — use podman unshare to run
// chown inside the user namespace where UIDs are mapped.
let chown_result = tokio::process::Command::new("podman")
.args(["unshare", "chown", "-R", &uid_str, host_path])
.output()
.await;
match chown_result {
Ok(out) if !out.status.success() => {
tracing::warn!(
"podman unshare chown failed for {}: {}",
host_path,
String::from_utf8_lossy(&out.stderr)
);
}
Err(e) => tracing::warn!("Failed to chown {}: {}", host_path, e),
_ => {}
}
}
}
}