From a896ecd4315dc4715fa9081815e3e4aea1ac84b8 Mon Sep 17 00:00:00 2001 From: Dorian Date: Tue, 31 Mar 2026 17:35:34 +0100 Subject: [PATCH] fix: container security hardening, onboarding viewport scaling, boot screen cleanup Container security: - Add --cap-drop ALL + --security-opt no-new-privileges:true to 12 containers missing hardening in first-boot-containers.sh (mempool-db, electrumx, mempool-api, mempool-web, electrs-ui, btcpay-db, nbxplorer, nostr-rs-relay, strfry, tailscale, bitcoin-ui, lnd-ui) - Mirror same hardening in deploy-to-target.sh for consistency - Add --read-only + tmpfs to nostr-rs-relay - Fix filebrowser deploy to include security flags - Remove duplicate UI image definitions in image-versions.sh - Separate Jellyfin capabilities (needs FOWNER, exec tmpfs for CoreCLR JIT) - Harden archy-net creation with existence check and error handling UI fixes: - Fix onboarding viewport scaling: all 7 screens now use h-full + max-h-full pattern so containers never overflow viewport regardless of padding - Remove path-option-card wrappers from seed verify inputs, left-justify labels - Remove batteries/barbarian icons from boot screen (keep bitcoin, cloud, github, save) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../archipelago/src/api/rpc/package/config.rs | 10 ++- .../src/api/rpc/package/install.rs | 35 ++++++++++- image-recipe/build-auto-installer-iso.sh | 16 ++--- neode-ui/src/components/BootScreen.vue | 2 - neode-ui/src/views/OnboardingDone.vue | 6 +- neode-ui/src/views/OnboardingIdentity.vue | 10 +-- neode-ui/src/views/OnboardingOptions.vue | 8 ++- neode-ui/src/views/OnboardingPath.vue | 9 ++- neode-ui/src/views/OnboardingSeedGenerate.vue | 4 +- neode-ui/src/views/OnboardingSeedRestore.vue | 4 +- neode-ui/src/views/OnboardingSeedVerify.vue | 9 ++- scripts/deploy-to-target.sh | 27 +++++++- scripts/first-boot-containers.sh | 63 ++++++++++++++++--- scripts/image-versions.sh | 8 +-- 14 files changed, 160 insertions(+), 51 deletions(-) diff --git a/core/archipelago/src/api/rpc/package/config.rs b/core/archipelago/src/api/rpc/package/config.rs index 22c04941..92a89c82 100644 --- a/core/archipelago/src/api/rpc/package/config.rs +++ b/core/archipelago/src/api/rpc/package/config.rs @@ -59,13 +59,21 @@ pub(super) fn get_app_capabilities(app_id: &str) -> Vec { "--cap-add=NET_RAW".to_string(), ], "nextcloud" | "btcpay-server" | "btcpayserver" - | "jellyfin" | "onlyoffice" | "onlyoffice-documentserver" | "portainer" => vec![ + | "onlyoffice" | "onlyoffice-documentserver" | "portainer" => vec![ "--cap-add=CHOWN".to_string(), "--cap-add=SETUID".to_string(), "--cap-add=SETGID".to_string(), "--cap-add=DAC_OVERRIDE".to_string(), "--cap-add=NET_BIND_SERVICE".to_string(), ], + // Jellyfin: CoreCLR needs exec-enabled tmpfs for JIT compilation + "jellyfin" => vec![ + "--cap-add=CHOWN".to_string(), + "--cap-add=FOWNER".to_string(), + "--cap-add=SETUID".to_string(), + "--cap-add=SETGID".to_string(), + "--cap-add=DAC_OVERRIDE".to_string(), + ], // Nginx Proxy Manager needs to bind low ports "nginx-proxy-manager" => vec![ "--cap-add=CHOWN".to_string(), diff --git a/core/archipelago/src/api/rpc/package/install.rs b/core/archipelago/src/api/rpc/package/install.rs index 255b2aea..3fd8547a 100644 --- a/core/archipelago/src/api/rpc/package/install.rs +++ b/core/archipelago/src/api/rpc/package/install.rs @@ -158,11 +158,37 @@ impl RpcHandler { run_args.push("--cap-add=NET_RAW"); run_args.push("--device=/dev/net/tun"); } else if needs_archy_net(package_id) { - let _ = tokio::process::Command::new("podman") + // Create archy-net if it doesn't exist (idempotent — "already exists" is fine) + match tokio::process::Command::new("podman") .args(["network", "create", "archy-net"]) .output() + .await + { + Ok(output) if !output.status.success() => { + let stderr = String::from_utf8_lossy(&output.stderr); + if !stderr.contains("already exists") { + tracing::warn!("Failed to create archy-net: {}", stderr.trim()); + } + } + Err(e) => { + tracing::warn!("Failed to run podman network create: {}", e); + } + _ => {} + } + // Verify the network actually exists before using it + let net_check = tokio::process::Command::new("podman") + .args(["network", "exists", "archy-net"]) + .status() .await; - run_args.push("--network=archy-net"); + if net_check.map(|s| s.success()).unwrap_or(false) { + run_args.push("--network=archy-net"); + } else { + tracing::error!( + "archy-net network does not exist — {} will use default network. \ + Inter-container DNS will not work.", + package_id + ); + } } // Security hardening (skip for privileged containers) @@ -184,6 +210,11 @@ impl RpcHandler { run_args.push("--tmpfs=/tmp:rw,noexec,nosuid,size=256m"); run_args.push("--tmpfs=/run:rw,noexec,nosuid,size=64m"); } + + // Jellyfin: .NET CoreCLR needs exec-enabled /tmp for JIT compilation + if package_id == "jellyfin" { + run_args.push("--tmpfs=/tmp:rw,exec,size=256m"); + } } // Create data directories diff --git a/image-recipe/build-auto-installer-iso.sh b/image-recipe/build-auto-installer-iso.sh index 5390dc14..440b73e2 100755 --- a/image-recipe/build-auto-installer-iso.sh +++ b/image-recipe/build-auto-installer-iso.sh @@ -767,9 +767,9 @@ cp /usr/lib/ISOLINUX/isohdpfx.bin /output/isohdpfx.bin echo " [container] Generating GRUB fonts..." apt-get install -y -qq fonts-dejavu-core grub-common >/dev/null 2>&1 mkdir -p /output/grub-fonts -grub-mkfont -s 12 -o /output/grub-fonts/dejavu_12.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf -grub-mkfont -s 14 -o /output/grub-fonts/dejavu_14.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf -grub-mkfont -s 16 -o /output/grub-fonts/dejavu_16.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf +grub-mkfont -s 12 -o /output/grub-fonts/dejavu_12.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf +grub-mkfont -s 14 -o /output/grub-fonts/dejavu_14.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf +grub-mkfont -s 16 -o /output/grub-fonts/dejavu_16.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf grub-mkfont -s 24 -o /output/grub-fonts/dejavu_24.pf2 /usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf echo " [container] Done!" @@ -2817,13 +2817,13 @@ UI vesamenu.c32 PROMPT 0 TIMEOUT 0 -MENU TITLE bitcoin node os +MENU TITLE MENU BACKGROUND splash.png MENU RESOLUTION 1024 768 -MENU VSHIFT 18 -MENU HSHIFT 32 -MENU WIDTH 18 -MENU MARGIN 1 +MENU VSHIFT 20 +MENU HSHIFT 6 +MENU WIDTH 68 +MENU MARGIN 2 MENU ROWS 5 MENU TABMSG press tab to edit | archipelago.sh MENU COLOR screen 37;40 #00000000 #00000000 none diff --git a/neode-ui/src/components/BootScreen.vue b/neode-ui/src/components/BootScreen.vue index e2ac82e7..9187dc92 100644 --- a/neode-ui/src/components/BootScreen.vue +++ b/neode-ui/src/components/BootScreen.vue @@ -81,8 +81,6 @@ const iconSources = [ '/assets/icon/cloud-done.svg', '/assets/icon/github.svg', '/assets/icon/save.svg', - '/assets/icon/batteries.svg', - '/assets/icon/barbarian.svg', ] interface LogLine { prefix: string; text: string; type: string } diff --git a/neode-ui/src/views/OnboardingDone.vue b/neode-ui/src/views/OnboardingDone.vue index 0f7387c9..3a4eb5f1 100644 --- a/neode-ui/src/views/OnboardingDone.vue +++ b/neode-ui/src/views/OnboardingDone.vue @@ -1,9 +1,9 @@