Files
stack/scripts/verify-dogfood-compose.sh
T
2026-08-30 16:07:25 -05:00

145 lines
4.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# Hermetic structural check for the explicit dogfood Compose overlay.
set -euo pipefail
repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
mkdir -p "$tmp/worktree" "$tmp/seat/secrets"
base_config_json=$(
cd "$repo_root"
BETTER_AUTH_SECRET=test-only-not-a-credential \
docker compose --profile stack config --format json
)
BASE_CONFIG_JSON="$base_config_json" python3 <<'PY'
import json
import os
config = json.loads(os.environ["BASE_CONFIG_JSON"])
gateway = config["services"]["gateway"]
env = gateway["environment"]
for key in (
"MOSAIC_AGENT_NAME",
"MOSAIC_GIT_IDENTITY",
"MOSAIC_BRAIN_HOME",
"AGENT_FILE_SANDBOX_DIR",
"AGENT_USER_TOOLS",
):
assert key not in env, f"base compose unexpectedly sets dogfood variable {key}"
targets = {mount["target"] for mount in gateway["volumes"]}
assert "/workspace/stack" not in targets
assert not any(target.startswith("/opt/mosaic/brain/") for target in targets)
PY
config_json=$(
cd "$repo_root"
BETTER_AUTH_SECRET=test-only-not-a-credential \
MOSAIC_DOGFOOD_WORKTREE="$tmp/worktree" \
MOSAIC_DOGFOOD_SEAT_HOME="$tmp/seat" \
docker compose \
-f docker-compose.yml \
-f docker-compose.dogfood.yml \
--profile stack \
config --format json
)
CONFIG_JSON="$config_json" EXPECT_WORKTREE="$tmp/worktree" EXPECT_SEAT="$tmp/seat" python3 <<'PY'
import json
import os
config = json.loads(os.environ["CONFIG_JSON"])
gateway = config["services"]["gateway"]
env = gateway["environment"]
expected_env = {
"MOSAIC_AGENT_NAME": "stack-dogfood",
"MOSAIC_GIT_IDENTITY": "stack-dogfood",
"MOSAIC_BRAIN_HOME": "/opt/mosaic/brain",
"AGENT_FILE_SANDBOX_DIR": "/workspace/stack",
}
for key, value in expected_env.items():
assert env.get(key) == value, f"{key}: expected {value!r}, got {env.get(key)!r}"
allowed = set(env["AGENT_USER_TOOLS"].split(","))
assert allowed == {
"fs_read_file",
"fs_write_file",
"fs_list_directory",
"fs_edit_file",
"git_status",
"git_log",
"git_diff",
"shell_exec",
}, f"unexpected dogfood tool set: {sorted(allowed)}"
mounts = {mount["target"]: mount for mount in gateway["volumes"]}
worktree = mounts["/workspace/stack"]
assert worktree["type"] == "bind"
assert worktree["source"] == os.environ["EXPECT_WORKTREE"]
assert not worktree.get("read_only", False), "dogfood worktree must be writable"
seat = mounts["/opt/mosaic/brain/fleet/agents/stack-dogfood"]
assert seat["type"] == "bind"
assert seat["source"] == os.environ["EXPECT_SEAT"]
assert seat.get("read_only") is True, "seat credential slot must be read-only"
other_seat_mounts = [
target
for target in mounts
if target.startswith("/opt/mosaic/brain/fleet/agents/")
and target != "/opt/mosaic/brain/fleet/agents/stack-dogfood"
]
assert other_seat_mounts == [], f"other seat mounts leaked: {other_seat_mounts}"
PY
# Each required path must fail closed rather than falling back to the current checkout.
expect_missing_path() {
local missing=$1 output rc
set +e
case "$missing" in
MOSAIC_DOGFOOD_WORKTREE)
output=$(
cd "$repo_root"
env -u MOSAIC_DOGFOOD_WORKTREE \
BETTER_AUTH_SECRET=test-only-not-a-credential \
MOSAIC_DOGFOOD_SEAT_HOME="$tmp/seat" \
docker compose -f docker-compose.yml -f docker-compose.dogfood.yml \
--profile stack config 2>&1
)
rc=$?
;;
MOSAIC_DOGFOOD_SEAT_HOME)
output=$(
cd "$repo_root"
env -u MOSAIC_DOGFOOD_SEAT_HOME \
BETTER_AUTH_SECRET=test-only-not-a-credential \
MOSAIC_DOGFOOD_WORKTREE="$tmp/worktree" \
docker compose -f docker-compose.yml -f docker-compose.dogfood.yml \
--profile stack config 2>&1
)
rc=$?
;;
*)
echo "FAIL: test requested unknown path variable $missing" >&2
exit 1
;;
esac
set -e
if [[ $rc -eq 0 ]]; then
echo "FAIL: dogfood compose accepted missing $missing" >&2
exit 1
fi
if [[ "$output" != *"$missing"* ]]; then
echo "FAIL: missing-path failure did not name $missing" >&2
exit 1
fi
}
expect_missing_path MOSAIC_DOGFOOD_WORKTREE
expect_missing_path MOSAIC_DOGFOOD_SEAT_HOME
printf 'dogfood compose verification passed\n'