#!/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 gluetun netns invariant (qBittorrent # publishes no port of its own; gluetun publishes both), 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 "qbittorrent joins gluetun's netns and publishes no port of its own" { local unit="$REPO_ROOT/frankbook-pro/qbittorrent/quadlet/qbittorrent.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 } @test "gluetun publishes qbittorrent's WebUI and torrent ports and needs NET_ADMIN+tun" { local unit="$REPO_ROOT/frankbook-pro/gluetun/quadlet/gluetun.container" grep -q '^PublishPort=8080:8080$' "$unit" || return 1 grep -q '^PublishPort=6881:6881$' "$unit" || return 1 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 "every arr serves its standard port and readarr keeps its pinned image" { grep -q '^PublishPort=9696:9696$' "$REPO_ROOT/frankbook-pro/prowlarr/quadlet/prowlarr.container" || return 1 grep -q '^PublishPort=8989:8989$' "$REPO_ROOT/frankbook-pro/sonarr/quadlet/sonarr.container" || return 1 grep -q '^PublishPort=7878:7878$' "$REPO_ROOT/frankbook-pro/radarr/quadlet/radarr.container" || return 1 grep -q '^PublishPort=8686:8686$' "$REPO_ROOT/frankbook-pro/lidarr/quadlet/lidarr.container" || return 1 grep -q '^PublishPort=8787:8787$' "$REPO_ROOT/frankbook-pro/readarr/quadlet/readarr.container" || return 1 grep -q '^Image=lscr.io/linuxserver/readarr:amd64-1.0.980$' \ "$REPO_ROOT/frankbook-pro/readarr/quadlet/readarr.container" || return 1 }