Files
ThothII/scripts/test-auth-runtime-projection-compose.sh

118 lines
4.3 KiB
Bash
Executable File

#!/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."