#!/usr/bin/env bash set -euo pipefail root="$(cd "$(dirname "$0")/.." && pwd -P)" tmp_base="${TMPDIR:-/tmp}" tmp="$(mktemp -d "${tmp_base%/}/thoth-auth-runtime-compose.XXXXXX")" trap 'rm -rf "$tmp"' EXIT HUP INT TERM canonical="$tmp/canonical-auth" runtime="$tmp/runtime-auth" mkdir -p "$canonical" "$runtime" "$tmp/data" "$tmp/pi-state" "$tmp/workspace-registry" chmod 0700 "$canonical" "$runtime" printf '%s\n' '{}' >"$tmp/pi-auth.json" printf '%s\n' 'fixture-secret-sentinel' >"$tmp/thothii.secrets" chmod 0600 "$tmp/pi-auth.json" "$tmp/thothii.secrets" write_env() { local path="$1" { printf '%s\n' \ 'THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/platform/workspaces.git' \ "PI_AUTH_FILE=$tmp/pi-auth.json" \ "THT_SECRETS_FILE=$tmp/thothii.secrets" \ "THT_AUTH_CONFIG_ROOT=$canonical" \ "THT_DATA_ROOT=$tmp/data" \ "THT_PI_STATE_ROOT=$tmp/pi-state" \ "THT_WORKSPACE_REGISTRY_ROOT=$tmp/workspace-registry" } >"$path" } write_env "$tmp/nonprojected.env" cp "$tmp/nonprojected.env" "$tmp/projected.env" printf 'THT_AUTH_RUNTIME_ROOT=%s\n' "$runtime" >>"$tmp/projected.env" cat >"$tmp/operator.yaml" <<'YAML' services: core: environment: THT_AUTH_RUNTIME_PROJECTION_ROOT: operator-marker YAML cat >"$tmp/current-image.yaml" <<'YAML' services: core: environment: THT_AUTH_RUNTIME_PROJECTION_ROOT: current-marker YAML render() { local output="$1" local env_file="$2" shift 2 local -a files=(-f "$root/compose.yaml" -f "$root/deploy/compose.server.yaml") local file for file in "$@"; do files+=(-f "$file") done docker compose --project-directory "$root" --env-file "$env_file" "${files[@]}" \ config --format json >"$output" } render "$tmp/nonprojected.json" "$tmp/nonprojected.env" render "$tmp/projected.json" "$tmp/projected.env" \ "$tmp/operator.yaml" "$root/deploy/compose.auth-runtime-projection.yaml" render "$tmp/current.json" "$tmp/projected.env" \ "$tmp/operator.yaml" "$root/deploy/compose.auth-runtime-projection.yaml" \ "$tmp/current-image.yaml" for mode in nonprojected projected current; do node - "$tmp/$mode.json" "$mode" "$canonical" "$runtime" <<'NODE' const fs = require("fs"); const [path, mode, canonical, runtime] = process.argv.slice(2); const config = JSON.parse(fs.readFileSync(path, "utf8")); const core = config.services?.core; if (!core) throw new Error(`${mode}: missing core service`); const mounts = (core.volumes || []).filter((mount) => mount.target === "/run/thothii-auth"); if (mounts.length !== 1 || mounts[0].type !== "bind" || !mounts[0].read_only) { throw new Error(`${mode}: expected exactly one read-only auth bind`); } if (mode === "nonprojected") { if (mounts[0].source !== canonical) throw new Error("nonprojected: canonical auth source changed"); if (Object.hasOwn(core.environment || {}, "THT_AUTH_RUNTIME_PROJECTION_ROOT")) { throw new Error("nonprojected: projected environment unexpectedly present"); } } else { if (mounts[0].source !== runtime) throw new Error(`${mode}: runtime source did not replace canonical source`); if ((core.volumes || []).some((mount) => mount.source === canonical)) { throw new Error(`${mode}: canonical source is still mounted`); } const expected = mode === "projected" ? "/run/thothii-auth" : "current-marker"; if (core.environment?.THT_AUTH_RUNTIME_PROJECTION_ROOT !== expected) { throw new Error(`${mode}: override ordering failed`); } } for (const [name, service] of Object.entries(config.services || {})) { if (name !== "core" && Object.hasOwn(service.environment || {}, "THT_AUTH_RUNTIME_PROJECTION_ROOT")) { throw new Error(`${mode}: ${name} received projected auth environment`); } } const maintenance = config.services?.["workspace-maintenance"]; if ((maintenance?.volumes || []).some( (mount) => mount.target === "/run/thothii-auth" || mount.target === "/data/auth", )) { throw new Error(`${mode}: workspace-maintenance received auth mount`); } if (Object.keys(maintenance?.environment || {}).some((key) => key.startsWith("THT_AUTH_"))) { throw new Error(`${mode}: workspace-maintenance received auth environment`); } if (JSON.stringify(config).includes("fixture-secret-sentinel")) { throw new Error(`${mode}: rendered Compose leaked a secret sentinel`); } NODE done echo "runtime auth projection Compose contract passed."