feat(orchestrator): complete container migration and release hardening

This commit is contained in:
archipelago
2026-04-28 15:00:58 -04:00
parent 4d05705315
commit 8f83b37d51
94 changed files with 5034 additions and 1003 deletions

View File

@@ -46,7 +46,7 @@ set -e
# Source pinned image versions (single source of truth)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
[ -f "$SCRIPT_DIR/../scripts/image-versions.sh" ] && . "$SCRIPT_DIR/../scripts/image-versions.sh"
[ -f "$SCRIPT_DIR/../../scripts/image-versions.sh" ] && . "$SCRIPT_DIR/../../scripts/image-versions.sh"
# Configuration
DEV_SERVER="${DEV_SERVER:-archipelago@192.168.1.228}"
@@ -267,7 +267,7 @@ WORKDIR /src/fips
# `rustables`). Without the feature, cargo doesn't build it, and
# cargo deb --no-build panics hunting for target/release/fips-gateway.
# Inspected upstream Cargo.toml 2026-04-19 — features.gateway = ["dep:rustables"].
RUN cargo build --release --features gateway
RUN cargo build --release
RUN cargo deb --no-build
RUN cp target/debian/fips_*_amd64.deb /tmp/fips.deb
@@ -498,9 +498,9 @@ RUN apt-get clean && \
DOCKERFILE
# Copy nginx snippets for HTTPS (PWA, app proxies)
if [ -d "$SCRIPT_DIR/configs/snippets" ]; then
if [ -d "$SCRIPT_DIR/../configs/snippets" ]; then
mkdir -p "$WORK_DIR/snippets"
cp "$SCRIPT_DIR/configs/snippets/"*.conf "$WORK_DIR/snippets/" 2>/dev/null || true
cp "$SCRIPT_DIR/../configs/snippets/"*.conf "$WORK_DIR/snippets/" 2>/dev/null || true
echo " Using nginx snippets from configs/snippets/"
else
mkdir -p "$WORK_DIR/snippets"
@@ -508,8 +508,8 @@ DOCKERFILE
fi
# Use nginx config from configs/ (includes app proxies for Nextcloud, Vaultwarden, etc.)
if [ -f "$SCRIPT_DIR/configs/nginx-archipelago.conf" ]; then
cp "$SCRIPT_DIR/configs/nginx-archipelago.conf" "$WORK_DIR/nginx-archipelago.conf"
if [ -f "$SCRIPT_DIR/../configs/nginx-archipelago.conf" ]; then
cp "$SCRIPT_DIR/../configs/nginx-archipelago.conf" "$WORK_DIR/nginx-archipelago.conf"
echo " Using nginx config from configs/nginx-archipelago.conf"
else
echo " ⚠ configs/nginx-archipelago.conf not found, using minimal config"
@@ -528,15 +528,15 @@ NGINXCONF
fi
# Copy udev rule for mesh radio stable naming
if [ -f "$SCRIPT_DIR/configs/99-mesh-radio.rules" ]; then
cp "$SCRIPT_DIR/configs/99-mesh-radio.rules" "$WORK_DIR/99-mesh-radio.rules"
if [ -f "$SCRIPT_DIR/../configs/99-mesh-radio.rules" ]; then
cp "$SCRIPT_DIR/../configs/99-mesh-radio.rules" "$WORK_DIR/99-mesh-radio.rules"
echo " Using 99-mesh-radio.rules from configs/"
fi
# Copy update service and timer
if [ -f "$SCRIPT_DIR/configs/archipelago-update.service" ]; then
cp "$SCRIPT_DIR/configs/archipelago-update.service" "$WORK_DIR/archipelago-update.service"
cp "$SCRIPT_DIR/configs/archipelago-update.timer" "$WORK_DIR/archipelago-update.timer"
if [ -f "$SCRIPT_DIR/../configs/archipelago-update.service" ]; then
cp "$SCRIPT_DIR/../configs/archipelago-update.service" "$WORK_DIR/archipelago-update.service"
cp "$SCRIPT_DIR/../configs/archipelago-update.timer" "$WORK_DIR/archipelago-update.timer"
echo " Using archipelago-update.service + timer from configs/"
fi
@@ -544,68 +544,68 @@ NGINXCONF
# timer is gone as of Step 8a — BootReconciler replaces it — but the
# reconcile-containers.sh script stays, invoked by the OTA update RPC
# until Step 8b/c ports all manifests to the Rust orchestrator).
if [ -f "$SCRIPT_DIR/configs/archipelago-doctor.service" ]; then
cp "$SCRIPT_DIR/configs/archipelago-doctor.service" "$WORK_DIR/archipelago-doctor.service"
cp "$SCRIPT_DIR/configs/archipelago-doctor.timer" "$WORK_DIR/archipelago-doctor.timer"
if [ -f "$SCRIPT_DIR/../configs/archipelago-doctor.service" ]; then
cp "$SCRIPT_DIR/../configs/archipelago-doctor.service" "$WORK_DIR/archipelago-doctor.service"
cp "$SCRIPT_DIR/../configs/archipelago-doctor.timer" "$WORK_DIR/archipelago-doctor.timer"
# Copy the actual scripts the services / update RPC reference
for s in container-doctor.sh reconcile-containers.sh container-specs.sh tor-helper.sh; do
if [ -f "$SCRIPT_DIR/../scripts/$s" ]; then
cp "$SCRIPT_DIR/../scripts/$s" "$WORK_DIR/$s"
if [ -f "$SCRIPT_DIR/../../scripts/$s" ]; then
cp "$SCRIPT_DIR/../../scripts/$s" "$WORK_DIR/$s"
fi
done
# Copy shared script library (mem_limit etc.)
if [ -d "$SCRIPT_DIR/../scripts/lib" ]; then
if [ -d "$SCRIPT_DIR/../../scripts/lib" ]; then
mkdir -p "$WORK_DIR/lib"
cp "$SCRIPT_DIR/../scripts/lib/"*.sh "$WORK_DIR/lib/" 2>/dev/null || true
cp "$SCRIPT_DIR/../../scripts/lib/"*.sh "$WORK_DIR/lib/" 2>/dev/null || true
fi
echo " Using container doctor timer from configs/"
fi
# Copy Tor helper path-activated service (allows backend to manage Tor as non-root)
if [ -f "$SCRIPT_DIR/configs/archipelago-tor-helper.service" ]; then
cp "$SCRIPT_DIR/configs/archipelago-tor-helper.service" "$WORK_DIR/archipelago-tor-helper.service"
cp "$SCRIPT_DIR/configs/archipelago-tor-helper.path" "$WORK_DIR/archipelago-tor-helper.path"
if [ -f "$SCRIPT_DIR/../configs/archipelago-tor-helper.service" ]; then
cp "$SCRIPT_DIR/../configs/archipelago-tor-helper.service" "$WORK_DIR/archipelago-tor-helper.service"
cp "$SCRIPT_DIR/../configs/archipelago-tor-helper.path" "$WORK_DIR/archipelago-tor-helper.path"
echo " Using tor-helper path unit from configs/"
fi
# Copy NostrVPN system service (native mesh VPN, not a container)
if [ -f "$SCRIPT_DIR/configs/nostr-vpn.service" ]; then
cp "$SCRIPT_DIR/configs/nostr-vpn.service" "$WORK_DIR/nostr-vpn.service"
if [ -f "$SCRIPT_DIR/../configs/nostr-vpn.service" ]; then
cp "$SCRIPT_DIR/../configs/nostr-vpn.service" "$WORK_DIR/nostr-vpn.service"
echo " Using nostr-vpn.service from configs/"
fi
if [ -f "$SCRIPT_DIR/configs/archipelago-wg.service" ]; then
cp "$SCRIPT_DIR/configs/archipelago-wg.service" "$WORK_DIR/archipelago-wg.service"
if [ -f "$SCRIPT_DIR/../configs/archipelago-wg.service" ]; then
cp "$SCRIPT_DIR/../configs/archipelago-wg.service" "$WORK_DIR/archipelago-wg.service"
echo " Using archipelago-wg.service from configs/"
fi
if [ -f "$SCRIPT_DIR/configs/archipelago-wg-address.service" ]; then
cp "$SCRIPT_DIR/configs/archipelago-wg-address.service" "$WORK_DIR/archipelago-wg-address.service"
if [ -f "$SCRIPT_DIR/../configs/archipelago-wg-address.service" ]; then
cp "$SCRIPT_DIR/../configs/archipelago-wg-address.service" "$WORK_DIR/archipelago-wg-address.service"
echo " Using archipelago-wg-address.service from configs/"
fi
if [ -f "$SCRIPT_DIR/configs/archipelago-fips.service" ]; then
cp "$SCRIPT_DIR/configs/archipelago-fips.service" "$WORK_DIR/archipelago-fips.service"
if [ -f "$SCRIPT_DIR/../configs/archipelago-fips.service" ]; then
cp "$SCRIPT_DIR/../configs/archipelago-fips.service" "$WORK_DIR/archipelago-fips.service"
echo " Using archipelago-fips.service from configs/"
fi
# Copy private Nostr relay service (native, for NostrVPN signaling)
if [ -f "$SCRIPT_DIR/configs/nostr-relay.service" ]; then
cp "$SCRIPT_DIR/configs/nostr-relay.service" "$WORK_DIR/nostr-relay.service"
if [ -f "$SCRIPT_DIR/../configs/nostr-relay.service" ]; then
cp "$SCRIPT_DIR/../configs/nostr-relay.service" "$WORK_DIR/nostr-relay.service"
echo " Using nostr-relay.service from configs/"
fi
if [ -f "$SCRIPT_DIR/configs/nostr-relay-config.toml" ]; then
cp "$SCRIPT_DIR/configs/nostr-relay-config.toml" "$WORK_DIR/nostr-relay-config.toml"
if [ -f "$SCRIPT_DIR/../configs/nostr-relay-config.toml" ]; then
cp "$SCRIPT_DIR/../configs/nostr-relay-config.toml" "$WORK_DIR/nostr-relay-config.toml"
echo " Using nostr-relay-config.toml from configs/"
fi
# Copy WireGuard helper script (privileged peer management)
if [ -f "$SCRIPT_DIR/../scripts/archipelago-wg" ]; then
cp "$SCRIPT_DIR/../scripts/archipelago-wg" "$WORK_DIR/archipelago-wg"
if [ -f "$SCRIPT_DIR/../../scripts/archipelago-wg" ]; then
cp "$SCRIPT_DIR/../../scripts/archipelago-wg" "$WORK_DIR/archipelago-wg"
echo " Using archipelago-wg helper from scripts/"
fi
# Use archipelago.service from configs/ (User=root for Podman container access)
if [ -f "$SCRIPT_DIR/configs/archipelago.service" ]; then
cp "$SCRIPT_DIR/configs/archipelago.service" "$WORK_DIR/archipelago.service"
if [ -f "$SCRIPT_DIR/../configs/archipelago.service" ]; then
cp "$SCRIPT_DIR/../configs/archipelago.service" "$WORK_DIR/archipelago.service"
echo " Using archipelago.service from configs/"
else
cat > "$WORK_DIR/archipelago.service" <<'SYSTEMDSERVICE'
@@ -1440,8 +1440,8 @@ cp "$WORK_DIR/archipelago-load-images.service" "$ARCH_DIR/scripts/"
# Tor setup: copy torrc and create first-boot setup script
mkdir -p "$ARCH_DIR/scripts/tor"
if [ -f "$SCRIPT_DIR/../scripts/tor/torrc.template" ]; then
cp "$SCRIPT_DIR/../scripts/tor/torrc.template" "$ARCH_DIR/scripts/tor/torrc"
if [ -f "$SCRIPT_DIR/../../scripts/tor/torrc.template" ]; then
cp "$SCRIPT_DIR/../../scripts/tor/torrc.template" "$ARCH_DIR/scripts/tor/torrc"
fi
echo " Creating first-boot Tor setup service..."
@@ -1676,9 +1676,9 @@ FBUNBUNDLED
cp "$WORK_DIR/first-boot-containers-unbundled.sh" "$ARCH_DIR/scripts/first-boot-containers.sh"
# Copy shared script library (TUI animations for installer, shared utils)
if [ -d "$SCRIPT_DIR/../scripts/lib" ]; then
if [ -d "$SCRIPT_DIR/../../scripts/lib" ]; then
mkdir -p "$ARCH_DIR/scripts/lib"
cp "$SCRIPT_DIR/../scripts/lib/"*.sh "$ARCH_DIR/scripts/lib/" 2>/dev/null || true
cp "$SCRIPT_DIR/../../scripts/lib/"*.sh "$ARCH_DIR/scripts/lib/" 2>/dev/null || true
echo " Copied scripts/lib/ ($(ls "$ARCH_DIR/scripts/lib/" 2>/dev/null | wc -l) files)"
fi
@@ -1704,12 +1704,12 @@ FBCSERVICE
else
echo " Creating first-boot container creation service..."
# Copy shared script library
if [ -d "$SCRIPT_DIR/../scripts/lib" ]; then
if [ -d "$SCRIPT_DIR/../../scripts/lib" ]; then
mkdir -p "$ARCH_DIR/scripts/lib"
cp "$SCRIPT_DIR/../scripts/lib/"*.sh "$ARCH_DIR/scripts/lib/" 2>/dev/null || true
cp "$SCRIPT_DIR/../../scripts/lib/"*.sh "$ARCH_DIR/scripts/lib/" 2>/dev/null || true
fi
if [ -f "$SCRIPT_DIR/../scripts/first-boot-containers.sh" ]; then
cp "$SCRIPT_DIR/../scripts/first-boot-containers.sh" "$ARCH_DIR/scripts/"
if [ -f "$SCRIPT_DIR/../../scripts/first-boot-containers.sh" ]; then
cp "$SCRIPT_DIR/../../scripts/first-boot-containers.sh" "$ARCH_DIR/scripts/"
chmod +x "$ARCH_DIR/scripts/first-boot-containers.sh"
cat > "$WORK_DIR/archipelago-first-boot-containers.service" <<'FBCSERVICE'
[Unit]
@@ -1762,32 +1762,32 @@ else
fi
# Bundle bootstrap switchover script + systemd timer
if [ -f "$SCRIPT_DIR/../scripts/bootstrap-switchover.sh" ]; then
cp "$SCRIPT_DIR/../scripts/bootstrap-switchover.sh" "$ARCH_DIR/scripts/"
if [ -f "$SCRIPT_DIR/../../scripts/bootstrap-switchover.sh" ]; then
cp "$SCRIPT_DIR/../../scripts/bootstrap-switchover.sh" "$ARCH_DIR/scripts/"
chmod +x "$ARCH_DIR/scripts/bootstrap-switchover.sh"
echo " ✅ Bundled bootstrap switchover script"
fi
# Bundle E2E test script for post-install validation
if [ -f "$SCRIPT_DIR/../scripts/run-e2e-tests.sh" ]; then
cp "$SCRIPT_DIR/../scripts/run-e2e-tests.sh" "$ARCH_DIR/scripts/"
if [ -f "$SCRIPT_DIR/../../scripts/run-e2e-tests.sh" ]; then
cp "$SCRIPT_DIR/../../scripts/run-e2e-tests.sh" "$ARCH_DIR/scripts/"
chmod +x "$ARCH_DIR/scripts/run-e2e-tests.sh"
echo " ✅ Bundled E2E test script for post-install validation"
fi
if [ -f "$SCRIPT_DIR/../scripts/run-post-install-tests.sh" ]; then
cp "$SCRIPT_DIR/../scripts/run-post-install-tests.sh" "$ARCH_DIR/scripts/"
if [ -f "$SCRIPT_DIR/../../scripts/run-post-install-tests.sh" ]; then
cp "$SCRIPT_DIR/../../scripts/run-post-install-tests.sh" "$ARCH_DIR/scripts/"
chmod +x "$ARCH_DIR/scripts/run-post-install-tests.sh"
echo " ✅ Bundled post-install test suite"
fi
# Bundle self-update script and image-versions for update system
if [ -f "$SCRIPT_DIR/../scripts/self-update.sh" ]; then
cp "$SCRIPT_DIR/../scripts/self-update.sh" "$ARCH_DIR/scripts/"
if [ -f "$SCRIPT_DIR/../../scripts/self-update.sh" ]; then
cp "$SCRIPT_DIR/../../scripts/self-update.sh" "$ARCH_DIR/scripts/"
chmod +x "$ARCH_DIR/scripts/self-update.sh"
echo " ✅ Bundled self-update script"
fi
if [ -f "$SCRIPT_DIR/../scripts/image-versions.sh" ]; then
cp "$SCRIPT_DIR/../scripts/image-versions.sh" "$ARCH_DIR/scripts/"
if [ -f "$SCRIPT_DIR/../../scripts/image-versions.sh" ]; then
cp "$SCRIPT_DIR/../../scripts/image-versions.sh" "$ARCH_DIR/scripts/"
echo " ✅ Bundled image-versions.sh"
fi
@@ -1907,7 +1907,7 @@ spinner() {
for _tui_path in \
"$BOOT_MEDIA/archipelago/scripts/lib/install-tui.sh" \
"/opt/archipelago/scripts/lib/install-tui.sh" \
"$(dirname "$0")/../scripts/lib/install-tui.sh"; do
"$(dirname "$0")/../../scripts/lib/install-tui.sh"; do
[ -f "$_tui_path" ] && { source "$_tui_path" 2>/dev/null; break; }
done
@@ -2494,7 +2494,7 @@ fi
# Do NOT overwrite — the rootfs already has the correct User=archipelago, no DEV_MODE version
if [ ! -f /mnt/target/etc/systemd/system/archipelago.service ]; then
echo " WARNING: archipelago.service missing from rootfs — copying from ISO"
cp "$BOOT_MEDIA/archipelago/configs/archipelago.service" /mnt/target/etc/systemd/system/archipelago.service 2>/dev/null || true
cp "$BOOT_MEDIA/archipelago/../configs/archipelago.service" /mnt/target/etc/systemd/system/archipelago.service 2>/dev/null || true
fi
# Claude API proxy — middleware that injects max_tokens, strips invalid fields
@@ -2887,7 +2887,7 @@ fi
# Install udev rule for mesh radio stable naming (/dev/mesh-radio)
MESH_RULES=""
for p in "$BOOT_MEDIA/99-mesh-radio.rules" /cdrom/99-mesh-radio.rules "$BOOT_MEDIA/archipelago/configs/99-mesh-radio.rules"; do
for p in "$BOOT_MEDIA/99-mesh-radio.rules" /cdrom/99-mesh-radio.rules "$BOOT_MEDIA/archipelago/../configs/99-mesh-radio.rules"; do
[ -f "$p" ] && MESH_RULES="$p" && break
done
if [ -n "$MESH_RULES" ]; then