187 lines
5.2 KiB
Bash
Executable File
187 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env sh
|
|
set -eu
|
|
|
|
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
PLATFORM_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/../.." && pwd)
|
|
INFRA_DIR="$PLATFORM_ROOT/infra"
|
|
ASSISTANT_DIR="$PLATFORM_ROOT/services/ai-workspace-assistant"
|
|
HUB_DIR="$PLATFORM_ROOT/services/ai-workspace-hub"
|
|
ONTOLOGY_DIR="$PLATFORM_ROOT/services/ontology-core"
|
|
|
|
COMPOSE_ENV="${COMPOSE_ENV:-$INFRA_DIR/.env}"
|
|
if [ ! -f "$COMPOSE_ENV" ]; then
|
|
COMPOSE_ENV="$INFRA_DIR/.env.example"
|
|
fi
|
|
|
|
REQUIRE_RUNTIME="${REQUIRE_RUNTIME:-0}"
|
|
REQUIRE_REMOTE_WORKER_RELAY="${REQUIRE_REMOTE_WORKER_RELAY:-0}"
|
|
|
|
passed=0
|
|
failed=0
|
|
skipped=0
|
|
|
|
section() {
|
|
printf '\n== %s ==\n' "$1"
|
|
}
|
|
|
|
pass() {
|
|
passed=$((passed + 1))
|
|
printf 'PASS %s\n' "$1"
|
|
}
|
|
|
|
fail() {
|
|
failed=$((failed + 1))
|
|
printf 'FAIL %s\n' "$1" >&2
|
|
}
|
|
|
|
skip() {
|
|
skipped=$((skipped + 1))
|
|
printf 'SKIP %s\n' "$1"
|
|
}
|
|
|
|
run_cmd() {
|
|
label="$1"
|
|
shift
|
|
printf '\n$ %s\n' "$label"
|
|
set +e
|
|
"$@"
|
|
status=$?
|
|
set -e
|
|
if [ "$status" -eq 0 ]; then
|
|
pass "$label"
|
|
else
|
|
fail "$label (exit $status)"
|
|
fi
|
|
}
|
|
|
|
run_sh() {
|
|
label="$1"
|
|
dir="$2"
|
|
command="$3"
|
|
printf '\n$ %s\n' "$label"
|
|
set +e
|
|
(cd "$dir" && sh -lc "$command")
|
|
status=$?
|
|
set -e
|
|
if [ "$status" -eq 0 ]; then
|
|
pass "$label"
|
|
else
|
|
fail "$label (exit $status)"
|
|
fi
|
|
}
|
|
|
|
run_sh_quiet() {
|
|
label="$1"
|
|
dir="$2"
|
|
command="$3"
|
|
output_file=$(mktemp "${TMPDIR:-/tmp}/nodedc-check.XXXXXX")
|
|
printf '\n$ %s\n' "$label"
|
|
set +e
|
|
(cd "$dir" && sh -lc "$command") > "$output_file" 2>&1
|
|
status=$?
|
|
set -e
|
|
if [ "$status" -eq 0 ]; then
|
|
pass "$label"
|
|
rm -f "$output_file"
|
|
else
|
|
cat "$output_file"
|
|
rm -f "$output_file"
|
|
fail "$label (exit $status)"
|
|
fi
|
|
}
|
|
|
|
section "Static syntax"
|
|
run_cmd "Hub server syntax" node --check "$HUB_DIR/src/server.mjs"
|
|
run_cmd "Assistant server syntax" node --check "$ASSISTANT_DIR/src/server.mjs"
|
|
run_cmd "Ontology MCP server syntax" node --check "$ONTOLOGY_DIR/src/mcp-server.mjs"
|
|
run_cmd "Local environment safety checker syntax" node --check "$INFRA_DIR/scripts/check-local-environment-safety.mjs"
|
|
run_sh "Shell scripts syntax" "$PLATFORM_ROOT" \
|
|
"sh -n infra/scripts/init-dev-env.sh infra/scripts/check-local-test-system.sh infra/scripts/check-ai-workspace-topology.sh infra/scripts/check-ai-workspace-config-contract.sh infra/scripts/check-ai-workspace-release-gates.sh"
|
|
if command -v bash >/dev/null 2>&1; then
|
|
run_sh "Synology hub-only deploy scripts syntax" "$PLATFORM_ROOT" \
|
|
"bash -n infra/synology/sync-ai-hub-relay.sh infra/synology/apply-ai-hub-relay.sh"
|
|
else
|
|
skip "Synology hub-only deploy scripts syntax (bash not installed)"
|
|
fi
|
|
|
|
section "Environment contracts"
|
|
run_cmd "Local environment safety" node "$INFRA_DIR/scripts/check-local-environment-safety.mjs"
|
|
run_cmd "AI Workspace config contract" "$INFRA_DIR/scripts/check-ai-workspace-config-contract.sh"
|
|
|
|
section "Compose boundary"
|
|
if command -v docker >/dev/null 2>&1; then
|
|
compose_tmp=$(mktemp "${TMPDIR:-/tmp}/nodedc-local-compose.XXXXXX")
|
|
if docker compose --env-file "$COMPOSE_ENV" -f "$INFRA_DIR/docker-compose.dev.yml" config > "$compose_tmp"; then
|
|
pass "Local compose config renders"
|
|
else
|
|
fail "Local compose config renders"
|
|
fi
|
|
rm -f "$compose_tmp"
|
|
|
|
if grep -Fq "env_file:" "$INFRA_DIR/docker-compose.dev.yml"; then
|
|
fail "Local compose must not inject the full .env into services"
|
|
else
|
|
pass "Local compose uses explicit service environment only"
|
|
fi
|
|
else
|
|
skip "Docker compose config render (docker not installed)"
|
|
fi
|
|
|
|
section "AI Workspace smokes"
|
|
run_sh_quiet "Assistant run-profile smoke" "$ASSISTANT_DIR" "npm run smoke:run-profile"
|
|
run_sh_quiet "AI Hub Ontology MCP proxy smoke" "$HUB_DIR" "npm run smoke:ontology-mcp-proxy"
|
|
if [ -d "$ONTOLOGY_DIR" ]; then
|
|
run_sh_quiet "Ontology assistant caller smoke" "$ONTOLOGY_DIR" "npm run smoke:assistant-caller"
|
|
run_sh_quiet "Ontology MCP smoke" "$ONTOLOGY_DIR" "npm run smoke:mcp"
|
|
else
|
|
skip "Ontology assistant caller smoke (missing $ONTOLOGY_DIR)"
|
|
fi
|
|
|
|
section "Runtime classification"
|
|
topology_tmp=$(mktemp "${TMPDIR:-/tmp}/nodedc-topology.XXXXXX")
|
|
set +e
|
|
(cd "$PLATFORM_ROOT" && infra/scripts/check-ai-workspace-topology.sh) > "$topology_tmp"
|
|
topology_status=$?
|
|
set -e
|
|
cat "$topology_tmp"
|
|
classification=$(awk -F= '/^classification=/{print $2; exit}' "$topology_tmp")
|
|
rm -f "$topology_tmp"
|
|
|
|
if [ "$topology_status" -eq 0 ]; then
|
|
pass "Runtime topology classified as ${classification:-unknown}"
|
|
else
|
|
fail "Runtime topology classification failed (exit $topology_status)"
|
|
fi
|
|
|
|
if [ "$REQUIRE_RUNTIME" = "1" ]; then
|
|
case "$classification" in
|
|
true-local-e2e|tunnel-local-e2e|local-remote-worker-relay)
|
|
pass "Runtime requirement satisfied"
|
|
;;
|
|
*)
|
|
fail "Runtime requirement not satisfied (classification=${classification:-unknown})"
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
if [ "$REQUIRE_REMOTE_WORKER_RELAY" = "1" ]; then
|
|
case "$classification" in
|
|
local-remote-worker-relay)
|
|
pass "Remote worker relay requirement satisfied"
|
|
;;
|
|
*)
|
|
fail "Remote worker relay requirement not satisfied (classification=${classification:-unknown})"
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
section "Git hygiene"
|
|
run_sh "Platform diff hygiene" "$PLATFORM_ROOT" "git diff --check"
|
|
|
|
section "Summary"
|
|
printf 'passed=%s failed=%s skipped=%s\n' "$passed" "$failed" "$skipped"
|
|
|
|
if [ "$failed" -ne 0 ]; then
|
|
exit 1
|
|
fi
|