authentik: boot-persistent quadlet conversion with deploy handler
The compose-era authentik trio died at every boot (rootless podman does not auto-start bare containers). Convert the trio to Quadlet units installed by deploy-remote.sh into ~/.config/containers/systemd/, enabled + WantedBy= default.target: - 3 unit files under dankclaw/authentik/quadlet/ (postgres -> server -> worker ordering via Wants=/After=; secrets stay in the git-ignored host .env, expanded by systemd at start time exactly like the gitea units) - deploy_authentik() handler: install units, daemon-reload, retire stale compose-era containers only while units are inactive, enable once, then start in dependency order with podman-health gates between stages - compose.yaml: authentik service definitions retired to a comment pointing at the quadlet dir (same pattern as searxng/open-webui/gitea/caddy) - tests/authentik.bats rewritten from compose assertions to unit-file contract assertions (images, Exec roles, ordering, loopback-only publish, pg_isready probe, secret hygiene, dispatch routing)
This commit is contained in:
1 parent
5829a0bfe8
commit
914e251ebc
6 files changed
+211
-120
No files matched your search
+39
-57
@@ -19,86 +19,68 @@ COMPOSE="$REPO_ROOT/dankclaw/compose.yaml"
|
||||
CADDYFILE="$REPO_ROOT/dankclaw/Caddyfile"
|
||||
ENV_EXAMPLE="$REPO_ROOT/dankclaw/.env.example"
|
||||
|
||||
# --- Compose: the 3-service stack ---
|
||||
# --- Quadlet units: the 3-service stack ------------------------------------
|
||||
# The trio left compose: they are boot-persistent Quadlet units installed to
|
||||
# ~/.config/containers/systemd/ by deploy-remote.sh (deploy_authentik).
|
||||
|
||||
@test "compose defines authentik-postgres" {
|
||||
grep -qE '^ authentik-postgres:' "$COMPOSE"
|
||||
}
|
||||
UNIT_DIR="$REPO_ROOT/dankclaw/authentik/quadlet"
|
||||
|
||||
@test "compose defines authentik-server" {
|
||||
grep -qE '^ authentik-server:' "$COMPOSE"
|
||||
}
|
||||
|
||||
@test "compose defines authentik-worker" {
|
||||
grep -qE '^ authentik-worker:' "$COMPOSE"
|
||||
@test "the three authentik quadlet units exist" {
|
||||
for unit in authentik-postgres authentik-server authentik-worker; do
|
||||
[ -f "$UNIT_DIR/$unit.container" ]
|
||||
done
|
||||
}
|
||||
|
||||
@test "authentik-postgres uses the official postgres image" {
|
||||
grep -q 'image: docker.io/library/postgres:' "$COMPOSE"
|
||||
grep -q 'Image=docker.io/library/postgres:16-alpine' "$UNIT_DIR/authentik-postgres.container"
|
||||
}
|
||||
|
||||
@test "authentik-server uses the official goauthentik image" {
|
||||
grep -q 'image: ghcr.io/goauthentik/server:' "$COMPOSE"
|
||||
@test "server and worker use the official goauthentik image" {
|
||||
grep -q 'Image=ghcr.io/goauthentik/server:' "$UNIT_DIR/authentik-server.container"
|
||||
grep -q 'Image=ghcr.io/goauthentik/server:' "$UNIT_DIR/authentik-worker.container"
|
||||
}
|
||||
|
||||
@test "authentik-server runs the 'server' command" {
|
||||
# The same image runs both server and worker; the command selects the role.
|
||||
grep -qE '^\s+command:\s*server' "$COMPOSE"
|
||||
@test "the same image runs both roles; the Exec command selects the role" {
|
||||
grep -qE '^Exec=server$' "$UNIT_DIR/authentik-server.container"
|
||||
grep -qE '^Exec=worker$' "$UNIT_DIR/authentik-worker.container"
|
||||
}
|
||||
|
||||
@test "authentik-worker runs the 'worker' command" {
|
||||
grep -qE '^\s+command:\s*worker' "$COMPOSE"
|
||||
@test "startup order is postgres -> server -> worker via unit ordering" {
|
||||
grep -q 'After=network.target authentik-postgres.service' "$UNIT_DIR/authentik-server.container"
|
||||
grep -q 'Wants=authentik-postgres.service' "$UNIT_DIR/authentik-server.container"
|
||||
grep -q 'Wants=authentik-server.service' "$UNIT_DIR/authentik-worker.container"
|
||||
}
|
||||
|
||||
@test "authentik-server depends on a healthy authentik-postgres" {
|
||||
local block
|
||||
block=$(awk -v s="^ authentik-server:\$" '
|
||||
$0 ~ s { inblk = 1; next }
|
||||
inblk && /^ [a-z]/ { inblk = 0 }
|
||||
inblk' "$COMPOSE")
|
||||
echo "$block" | grep -q 'condition: service_healthy'
|
||||
}
|
||||
|
||||
@test "authentik-worker depends on a healthy authentik-postgres" {
|
||||
local block
|
||||
block=$(awk -v s="^ authentik-worker:\$" '
|
||||
$0 ~ s { inblk = 1; next }
|
||||
inblk && /^ [a-z]/ { inblk = 0 }
|
||||
inblk' "$COMPOSE")
|
||||
echo "$block" | grep -q 'condition: service_healthy'
|
||||
}
|
||||
|
||||
@test "authentik-server exposes port 9000" {
|
||||
local block
|
||||
block=$(awk -v s="^ authentik-server:\$" '
|
||||
$0 ~ s { inblk = 1; next }
|
||||
inblk && /^ [a-z]/ { inblk = 0 }
|
||||
inblk' "$COMPOSE")
|
||||
echo "$block" | grep -qE '"9000:9000"'
|
||||
@test "the server publishes 9000 on loopback only; LAN reaches it through Caddy" {
|
||||
grep -q 'PublishPort=127.0.0.1:9000:9000' "$UNIT_DIR/authentik-server.container"
|
||||
}
|
||||
|
||||
@test "authentik-postgres healthcheck uses pg_isready" {
|
||||
local block
|
||||
block=$(awk -v s="^ authentik-postgres:\$" '
|
||||
$0 ~ s { inblk = 1; next }
|
||||
inblk && /^ [a-z]/ { inblk = 0 }
|
||||
inblk' "$COMPOSE")
|
||||
echo "$block" | grep -q 'pg_isready'
|
||||
grep -q 'HealthCmd=.*pg_isready' "$UNIT_DIR/authentik-postgres.container"
|
||||
}
|
||||
|
||||
# --- Compose: environment (secrets from .env) ---
|
||||
# --- Units: environment (secrets stay in the host .env, expanded at start) --
|
||||
|
||||
@test "authentik services consume AUTHENTIK_PG_PASS from .env" {
|
||||
grep -q 'AUTHENTIK_PG_PASS' "$COMPOSE"
|
||||
@test "the units consume AUTHENTIK_PG_PASS via systemd expansion, not literals" {
|
||||
grep -q 'POSTGRES_PASSWORD=${AUTHENTIK_PG_PASS}' "$UNIT_DIR/authentik-postgres.container"
|
||||
grep -q 'PASSWORD=${AUTHENTIK_PG_PASS}' "$UNIT_DIR/authentik-server.container"
|
||||
grep -q 'PASSWORD=${AUTHENTIK_PG_PASS}' "$UNIT_DIR/authentik-worker.container"
|
||||
}
|
||||
|
||||
@test "authentik services consume AUTHENTIK_SECRET_KEY from .env" {
|
||||
grep -q 'AUTHENTIK_SECRET_KEY' "$COMPOSE"
|
||||
@test "the units consume AUTHENTIK_SECRET_KEY via systemd expansion, not literals" {
|
||||
for unit in authentik-server authentik-worker; do
|
||||
grep -q 'AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY}' "$UNIT_DIR/$unit.container"
|
||||
done
|
||||
}
|
||||
|
||||
@test "no real authentik secret is committed in compose" {
|
||||
# The compose must reference the secret via ${VAR}, never a literal.
|
||||
! grep -qE 'AUTHENTIK_SECRET_KEY:\s*["\x27]?\w{16,}' "$COMPOSE"
|
||||
@test "no secret material is committed in the quadlet units" {
|
||||
! grep -rqE 'SECRET_KEY=[^$]' "$UNIT_DIR"
|
||||
}
|
||||
|
||||
@test "deploy-remote.sh routes the authentik trio to the quadlet handler, not compose up" {
|
||||
grep -q 'authentik-postgres|authentik-server|authentik-worker)' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
grep -q 'deploy_authentik()' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
! grep -qE '^[[:space:]]+comfyui\|.*authentik' "$REPO_ROOT/scripts/deploy-remote.sh"
|
||||
}
|
||||
|
||||
# --- Caddyfile: the auth vhost ---
|
||||
|
||||
Reference in new issue
Block a user