#!/usr/bin/env bash # Covers the brain-home fleet-state check in `mosaic-doctor` (#1298 follow-up). # # The functions are extracted from the shipped script rather than copied here # (same discipline as test-fleet-transport-check.sh): a test that carries its # own copy of the logic keeps passing after the shipped copy changes. # Extraction is by exact function header and a closing brace in column one. set -euo pipefail SCRIPT_DIR=$(cd -- "$(dirname "$0")" && pwd) DOCTOR="$SCRIPT_DIR/mosaic-doctor" fail() { echo "FAIL: $*" >&2 exit 1 } [ -f "$DOCTOR" ] || fail "missing mosaic-doctor at $DOCTOR" extract_function() { local name="$1" local extracted extracted=$(sed -n "/^${name}() {/,/^}/p" "$DOCTOR") [ -n "$extracted" ] || fail "could not extract ${name}() from mosaic-doctor — script reshaped?" printf '%s\n' "$extracted" } for fn in resolve_brain_home check_brain_home; do extract_function "$fn" >/dev/null done warn_count=0 warn() { warn_count=$((warn_count + 1)); echo "[WARN] $*"; } pass() { echo "[OK] $*"; return 0; } eval "$(extract_function resolve_brain_home)" eval "$(extract_function check_brain_home)" ROOT=$(mktemp -d) trap 'rm -rf "$ROOT"' EXIT run_case() { # label, expect (ok|warn), then env assignments as arguments. # The check runs under `env` in a subshell, so its warn() also prints a # sentinel the parent counts — a subshell counter would never be visible. local label="$1" expect="$2" shift 2 local out warns out=$(env "$@" bash -c "warn() { echo \"[WARN] \$*\"; }; pass() { echo \"[OK] \$*\"; return 0; }; $(extract_function resolve_brain_home); $(extract_function check_brain_home); check_brain_home" 2>&1) warns=$(printf '%s\n' "$out" | grep -c '^\[WARN\]' || true) if [[ "$expect" == ok && "$warns" -eq 0 ]]; then echo "ok - $label" elif [[ "$expect" == warn && "$warns" -gt 0 ]]; then echo "ok - $label (warned)" else echo "output: $out" >&2 fail "$label: expected $expect (warns=$warns)" fi } # ── legacy: no brain, custom home never adopts ───────────────────────────── mkdir -p "$ROOT/legacy-mosaic/fleet/agents" run_case "custom home without brain stays legacy" ok \ MOSAIC_HOME="$ROOT/legacy-mosaic" HOME="$ROOT" # ── healthy brain at the default config home ─────────────────────────────── mkdir -p "$ROOT/home/.config/mosaic" "$ROOT/home/.mosaic/fleet/agents" chmod 700 "$ROOT/home/.mosaic/fleet/agents" run_case "default home adopts healthy brain" ok \ MOSAIC_HOME="$ROOT/home/.config/mosaic" HOME="$ROOT/home" # ── explicit MOSAIC_BRAIN_HOME to a brain without fleet/agents → warn ────── mkdir -p "$ROOT/brain-noagents/fleet" "$ROOT/config" run_case "explicit brain without agents warns" warn \ MOSAIC_HOME="$ROOT/config" HOME="$ROOT" MOSAIC_BRAIN_HOME="$ROOT/brain-noagents" # ── explicit MOSAIC_BRAIN_HOME to a healthy brain → ok ───────────────────── mkdir -p "$ROOT/brain-ok/fleet/agents" "$ROOT/config2" chmod 700 "$ROOT/brain-ok/fleet/agents" run_case "explicit healthy brain passes" ok \ MOSAIC_HOME="$ROOT/config2" HOME="$ROOT" MOSAIC_BRAIN_HOME="$ROOT/brain-ok" # ── group-readable agents dir → warn (0700 boundary) ─────────────────────── mkdir -p "$ROOT/brain-loose/fleet/agents" "$ROOT/config3" chmod 750 "$ROOT/brain-loose/fleet/agents" run_case "group-readable brain agents warns" warn \ MOSAIC_HOME="$ROOT/config3" HOME="$ROOT" MOSAIC_BRAIN_HOME="$ROOT/brain-loose" # ── symlinked agents dir → warn (managed-directory boundary) ─────────────── mkdir -p "$ROOT/brain-link/real-agents" "$ROOT/brain-link/fleet" "$ROOT/config4" ln -s "$ROOT/brain-link/real-agents" "$ROOT/brain-link/fleet/agents" run_case "symlinked brain agents warns" warn \ MOSAIC_HOME="$ROOT/config4" HOME="$ROOT" MOSAIC_BRAIN_HOME="$ROOT/brain-link" # ── split state: envs in BOTH trees → warn ───────────────────────────────── mkdir -p "$ROOT/brain-split/fleet/agents" "$ROOT/config5/fleet/agents" chmod 700 "$ROOT/brain-split/fleet/agents" "$ROOT/config5/fleet/agents" touch "$ROOT/config5/fleet/agents/coder0.env.generated" run_case "env files in both trees warns (split state)" warn \ MOSAIC_HOME="$ROOT/config5" HOME="$ROOT" MOSAIC_BRAIN_HOME="$ROOT/brain-split" # ── config-home agents dir WITHOUT env files alongside a brain → ok ──────── mkdir -p "$ROOT/brain-clean/fleet/agents" "$ROOT/config6/fleet/agents" chmod 700 "$ROOT/brain-clean/fleet/agents" "$ROOT/config6/fleet/agents" run_case "empty config-home agents dir alongside brain passes" ok \ MOSAIC_HOME="$ROOT/config6" HOME="$ROOT" MOSAIC_BRAIN_HOME="$ROOT/brain-clean" echo "ok - mosaic-doctor brain-home check"