#!/usr/bin/env bats # Seam: the FrankBook-Pro quadlet units (gluetun, qbittorrent, five *arrs). # These units are installed INSIDE the Mac's podman machine VM by the # frankbook-pro handler in deploy-remote.sh. The contract pinned here: # boot persistence, self-healing, the VPN egress invariant (the whole # *arr fleet + qBittorrent share gluetun's netns and publish no ports of # their own, so ALL egress exits through the WireGuard tunnel — # AllowedIPs=0.0.0.0/0 — by construction; gluetun publishes every fleet # port), the verbatim plan-locked data-root mounts, and zero literal # secrets in tracked files. load helpers FRANKBOOK_UNITS=( gluetun/quadlet/gluetun qbittorrent/quadlet/qbittorrent prowlarr/quadlet/prowlarr sonarr/quadlet/sonarr radarr/quadlet/radarr lidarr/quadlet/lidarr readarr/quadlet/readarr ) @test "all seven frankbook-pro units exist under frankbook-pro//quadlet/" { for unit in "${FRANKBOOK_UNITS[@]}"; do [ -f "$REPO_ROOT/frankbook-pro/$unit.container" ] || return 1 done } @test "every frankbook-pro unit is boot-persistent and self-healing" { for unit in "${FRANKBOOK_UNITS[@]}"; do grep -q '^WantedBy=default.target$' "$REPO_ROOT/frankbook-pro/$unit.container" || return 1 grep -q '^Restart=always$' "$REPO_ROOT/frankbook-pro/$unit.container" || return 1 done } @test "every arr and qbittorrent joins gluetun's netns and publishes no port" { local svc unit for svc in qbittorrent prowlarr sonarr radarr lidarr readarr; do unit="$REPO_ROOT/frankbook-pro/$svc/quadlet/$svc.container" grep -q '^Network=gluetun.container$' "$unit" || return 1 grep -q '^Wants=gluetun.service$' "$unit" || return 1 grep -q '^After=gluetun.service$' "$unit" || return 1 ! grep -q '^PublishPort=' "$unit" || return 1 done } @test "gluetun publishes the whole fleet's ports and needs NET_ADMIN+tun" { local unit="$REPO_ROOT/frankbook-pro/gluetun/quadlet/gluetun.container" for port in 8080 6881 9696 8989 7878 8686 8787; do grep -q "^PublishPort=$port:$port\$" "$unit" || return 1 done grep -q '^PublishPort=6881:6881/udp$' "$unit" || return 1 grep -q '^AddCapability=NET_ADMIN$' "$unit" || return 1 grep -q '^AddDevice=/dev/net/tun:/dev/net/tun$' "$unit" || return 1 } @test "gluetun credentials come from a machine-local env file, never literals" { local unit="$REPO_ROOT/frankbook-pro/gluetun/quadlet/gluetun.container" grep -q '^EnvironmentFile=/home/core/Containers/gluetun/env$' "$unit" || return 1 # Only ${VAR} expansions may carry the WireGuard material. if grep -qE '^Environment=WIREGUARD_PRIVATE_KEY=[^$]' "$unit"; then return 1 fi } @test "data roots follow the plan-locked virtiofs layout" { for svc in qbittorrent prowlarr sonarr radarr lidarr readarr; do grep -q "^Volume=/Volumes/COMPLETE/$svc-data:/config$" \ "$REPO_ROOT/frankbook-pro/$svc/quadlet/$svc.container" || return 1 done # qBittorrent additionally mounts both external disks verbatim: the # seeded conf references the literal /Volumes paths. local unit="$REPO_ROOT/frankbook-pro/qbittorrent/quadlet/qbittorrent.container" grep -q '^Volume=/Volumes/COMPLETE:/Volumes/COMPLETE$' "$unit" || return 1 grep -q '^Volume=/Volumes/INCOMPLETE:/Volumes/INCOMPLETE$' "$unit" || return 1 } @test "readarr keeps its pinned image" { grep -q '^Image=lscr.io/linuxserver/readarr:amd64-1.0.980$' \ "$REPO_ROOT/frankbook-pro/readarr/quadlet/readarr.container" || return 1 }