NODEDC_PLATFORM/infra/scripts/check-ai-workspace-config-c...

147 lines
7.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)
OPS_GATEWAY_REPO="${OPS_GATEWAY_REPO:-$PLATFORM_ROOT/../../data/NODEDC_TASKMANAGER_CODEXAPI}"
ENGINE_REPO="${ENGINE_REPO:-$PLATFORM_ROOT/../NODEDC_ENGINE_INFRA}"
PLATFORM_ENV="${PLATFORM_ENV:-$PLATFORM_ROOT/infra/.env}"
passed=0
failed=0
warnings=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
}
warn() {
warnings=$((warnings + 1))
printf 'WARN %s\n' "$1" >&2
}
require_file() {
file="$1"
label="$2"
if [ -f "$file" ]; then
pass "$label"
else
fail "$label (missing file: $file)"
fi
}
require_contains() {
file="$1"
needle="$2"
label="$3"
if [ ! -f "$file" ]; then
fail "$label (missing file: $file)"
return 0
fi
if grep -Fq "$needle" "$file"; then
pass "$label"
else
fail "$label (missing: $needle)"
fi
}
read_env() {
file="$1"
key="$2"
if [ ! -f "$file" ]; then
return 0
fi
awk -F= -v key="$key" '
$0 ~ "^[[:space:]]*#" { next }
$1 == key {
value = substr($0, index($0, "=") + 1)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
gsub(/^"|"$/, "", value)
print value
exit
}
' "$file"
}
require_env_value() {
file="$1"
key="$2"
expected="$3"
label="$4"
actual=$(read_env "$file" "$key" || true)
if [ "$actual" = "$expected" ]; then
pass "$label"
else
fail "$label (expected $key=$expected, got ${actual:-<missing>})"
fi
}
section "Required files"
require_file "$PLATFORM_ROOT/infra/.env.example" "Platform local env example exists"
require_file "$PLATFORM_ROOT/infra/synology/.env.synology.example" "Platform Synology env example exists"
require_file "$PLATFORM_ROOT/infra/docker-compose.dev.yml" "Platform local compose exists"
require_file "$PLATFORM_ROOT/infra/synology/docker-compose.platform-http.yml" "Platform Synology compose exists"
require_file "$OPS_GATEWAY_REPO/.env.example" "Ops Gateway local env example exists"
require_file "$OPS_GATEWAY_REPO/.env.synology.example" "Ops Gateway Synology env example exists"
require_file "$OPS_GATEWAY_REPO/docker-compose.local.yml" "Ops Gateway local compose exists"
require_file "$OPS_GATEWAY_REPO/docker-compose.synology.yml" "Ops Gateway Synology compose exists"
require_file "$ENGINE_REPO/docker-compose.yml" "Engine compose exists"
section "Platform local contract"
require_env_value "$PLATFORM_ROOT/infra/.env.example" "AI_WORKSPACE_OPS_ENTITLEMENT_URL" "http://host.docker.internal:4100/api/internal/v1/ai-workspace/entitlements" "Local Platform example points Ops entitlement to local Gateway"
require_env_value "$PLATFORM_ROOT/infra/.env.example" "AI_WORKSPACE_HUB_PUBLIC_URL" "wss://ai-hub.nodedc.ru/api/ai-workspace/hub" "Local Platform example keeps deployed Hub as hybrid worker relay by default"
require_env_value "$PLATFORM_ROOT/infra/.env.example" "AI_WORKSPACE_HUB_INTERNAL_URL" "https://ai-hub.nodedc.ru" "Local Platform example has explicit Hub internal URL"
require_contains "$PLATFORM_ROOT/infra/scripts/init-dev-env.sh" "AI_WORKSPACE_OPS_ENTITLEMENT_URL=http://host.docker.internal:4100/api/internal/v1/ai-workspace/entitlements" "Local env generator emits local Ops entitlement URL"
require_contains "$PLATFORM_ROOT/infra/scripts/init-dev-env.sh" "AI_WORKSPACE_HUB_INTERNAL_URL=https://ai-hub.nodedc.ru" "Local env generator emits explicit Hub internal URL"
section "Platform Synology contract"
require_env_value "$PLATFORM_ROOT/infra/synology/.env.synology.example" "NODEDC_AI_WORKSPACE_ASSISTANT_URL" "http://ai-workspace-assistant:18082" "Synology Platform exposes Assistant to app services on compose network"
require_env_value "$PLATFORM_ROOT/infra/synology/.env.synology.example" "AI_WORKSPACE_OPS_ENTITLEMENT_URL" "http://172.22.0.222:18190/api/internal/v1/ai-workspace/entitlements" "Synology Platform points Ops entitlement to Synology Gateway"
require_env_value "$PLATFORM_ROOT/infra/synology/.env.synology.example" "AI_WORKSPACE_HUB_PUBLIC_URL" "wss://ai-hub.nodedc.ru/api/ai-workspace/hub" "Synology Platform worker-facing Hub URL is public relay"
require_env_value "$PLATFORM_ROOT/infra/synology/.env.synology.example" "AI_WORKSPACE_HUB_INTERNAL_URL" "https://ai-hub.nodedc.ru" "Synology Platform backend Hub URL is explicit"
require_contains "$PLATFORM_ROOT/infra/synology/verify-current-runtime.sh" 'AI_WORKSPACE_OPS_ENTITLEMENT_URL" = "http://172.22.0.222:18190/api/internal/v1/ai-workspace/entitlements"' "Synology verify checks Ops entitlement URL"
section "Ops Gateway contract"
require_env_value "$OPS_GATEWAY_REPO/.env.example" "NODEDC_AGENT_GATEWAY_PUBLIC_URL" "https://ops-agents.nodedc.ru" "Ops Gateway local example keeps worker-facing MCP URL explicit"
require_env_value "$OPS_GATEWAY_REPO/.env.example" "NODEDC_TASKER_INTERNAL_URL" "http://task.local.nodedc" "Ops Gateway local example points downstream to local Tasker"
require_env_value "$OPS_GATEWAY_REPO/.env.synology.example" "NODEDC_AGENT_GATEWAY_PUBLIC_URL" "https://ops-agents.nodedc.ru" "Ops Gateway Synology public MCP URL is public relay"
require_env_value "$OPS_GATEWAY_REPO/.env.synology.example" "NODEDC_TASKER_INTERNAL_URL" "http://172.22.0.222:18090" "Ops Gateway Synology downstream points to Synology Tasker"
require_contains "$OPS_GATEWAY_REPO/docker-compose.synology.yml" '${HOST_BIND:-172.22.0.222}:${HOST_PORT:-18190}:${PORT:-4100}' "Ops Gateway Synology compose binds expected internal port"
require_contains "$OPS_GATEWAY_REPO/README.md" "The response uses the AI Workspace adapter contract" "Ops Gateway README documents AI Workspace adapter contract"
section "Engine contract"
require_contains "$ENGINE_REPO/docker-compose.yml" 'NODEDC_AI_WORKSPACE_ASSISTANT_URL: ${NODEDC_AI_WORKSPACE_ASSISTANT_URL:-http://ai-workspace-assistant:18082}' "Engine compose accepts configurable Assistant URL"
require_contains "$ENGINE_REPO/docker-compose.yml" 'NDC_AI_WORKSPACE_HUB_URL: ${NDC_AI_WORKSPACE_HUB_URL:-wss://ai-hub.nodedc.ru/api/ai-workspace/hub}' "Engine compose accepts configurable worker-facing Hub URL"
require_contains "$ENGINE_REPO/docker-compose.yml" 'NDC_AI_WORKSPACE_HUB_HTTP_URL: ${NDC_AI_WORKSPACE_HUB_HTTP_URL:-https://ai-hub.nodedc.ru}' "Engine compose accepts configurable Hub HTTP URL"
require_contains "$ENGINE_REPO/nodedc-source/server/aiWorkspace/assistantRegistryClient.js" "'X-NODEDC-User-Role': role" "Engine forwards user role to Assistant"
require_contains "$ENGINE_REPO/nodedc-source/server/aiWorkspace/assistantRegistryClient.js" "'X-NODEDC-User-Groups': groups.join(',')" "Engine forwards user groups to Assistant"
section "Current local env warnings"
if [ -f "$PLATFORM_ENV" ]; then
local_ops_entitlement=$(read_env "$PLATFORM_ENV" AI_WORKSPACE_OPS_ENTITLEMENT_URL || true)
if [ -z "$local_ops_entitlement" ]; then
warn "Current Platform env has no AI_WORKSPACE_OPS_ENTITLEMENT_URL; current Mac remains hybrid/contract-only until env is deliberately updated."
else
pass "Current Platform env has AI_WORKSPACE_OPS_ENTITLEMENT_URL"
fi
else
warn "Current Platform env not found: $PLATFORM_ENV"
fi
section "Summary"
printf 'passed=%s failed=%s warnings=%s\n' "$passed" "$failed" "$warnings"
if [ "$failed" -ne 0 ]; then
exit 1
fi