Files
ThothII/scripts/test-no-deployment-coupling.sh
2026-09-15 14:37:29 +02:00

161 lines
5.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Category-based guard for active build, runtime, install, and launch coupling.
set -euo pipefail
script_root="$(cd "$(dirname "$0")/.." && pwd -P)"
scan_root="$script_root"
if [[ "${1:-}" == --root ]]; then
[[ $# -eq 2 ]] || { echo "usage: $0 [--root PATH]" >&2; exit 2; }
scan_root="$2"
elif [[ $# -ne 0 ]]; then
echo "usage: $0 [--root PATH]" >&2
exit 2
fi
[[ -d "$scan_root" ]] || { echo "coupling scan root is not a directory: $scan_root" >&2; exit 2; }
cd "$scan_root"
runtime_files=()
install_files=()
operator_files=()
contract_test_files=()
add_file() {
local array_name="$1" file="$2"
[[ ! -f "$file" ]] || eval "$array_name+=(\"\$file\")"
}
for file in .dockerignore compose.yaml docker-compose.dev.yml frontend/vite.config.ts; do
add_file runtime_files "$file"
done
if [[ -d deploy ]]; then
while IFS= read -r -d '' file; do runtime_files+=("${file#./}"); done < <(
find deploy -type f -print0
)
fi
if [[ -d docker ]]; then
while IFS= read -r -d '' file; do
case "$file" in
docker/session-migrate.sh|docker/cutover-legacy-sessions.sh) continue ;;
esac
runtime_files+=("${file#./}")
done < <(find docker -type f -print0)
fi
for file in README.md .env.example docs/operations/compose-reference.md; do
add_file install_files "$file"
done
if [[ -d docs/install ]]; then
while IFS= read -r -d '' file; do install_files+=("${file#./}"); done < <(
find docs/install -type f -print0
)
fi
if [[ -d scripts ]]; then
while IFS= read -r -d '' file; do
case "${file#scripts/}" in
test-no-deployment-coupling.sh|test-no-deployment-coupling-scope.sh) continue ;;
test-*.sh)
contract_test_files+=("${file#./}")
continue
;;
compose-with-preflight.sh|generate-connector-secrets-override.sh|unified-deployment-smoke.sh|vector-rotate-bootstrap-password.sh)
continue
;;
verify-*.sh) continue ;;
esac
operator_files+=("${file#./}")
done < <(find scripts -maxdepth 1 -type f -print0)
fi
offenders=()
scan_category() {
local label="$1" pattern="$2"; shift 2
local output rg_status
(($#)) || return 0
set +e
output="$(rg -n -i --with-filename -- "$pattern" "$@" 2>&1)"
rg_status=$?
set -e
case "$rg_status" in
0)
while IFS= read -r match; do offenders+=("$label: $match"); done <<<"$output"
;;
1) ;;
*)
echo "coupling scan failed in $label (rg status $rg_status)" >&2
printf '%s\n' "$output" >&2
exit "$rg_status"
;;
esac
}
for forbidden_file in \
deploy/compose.local-vector.yaml \
deploy/compose.preprocess-local-vector.yaml \
deploy/compose.production.yaml \
deploy/compose.psd-local.yaml.example \
deploy/compose.psd-local.yaml \
deploy/sql/20-vector-roles.sql \
deploy/vector/reconcile-roles.sh \
deploy/vector/rotate-bootstrap-password.py \
deploy/vector/secret-policy.sh \
deploy/vector/vector-db-entrypoint.sh \
scripts/bootstrap-local-psd-docker-config.sh \
scripts/local-vector-smoke.sh \
scripts/test-qwen-network-config.sh \
scripts/test-local-vector-smoke-safety.sh \
scripts/test-local-vector-smoke-live-collision.sh \
scripts/test-vector-bootstrap-rotation.sh \
scripts/test-vector-migration-image.sh \
scripts/test-vector-secret-policy.sh \
harness/tests/test_psd_local_compose_contract.py; do
[[ ! -e "$forbidden_file" ]] \
|| offenders+=("active filename: $forbidden_file (superseded deployment contract)")
done
forbidden='omics_portal|chirone|localllm_default|datamart-builder|compose\.production\.yaml|compose\.psd-local\.yaml'
retired_semantic='local-vector|pgvector(_direct)?|pg_(dump|restore)|THT_VECTOR_([A-Z0-9_]+)|THT_OLLAMA_URL|THT_WS_[A-Z0-9_]*_(VECTOR|EMBEDDING)_[A-Z0-9_]+|VECTOR_API_KEY_(FILE|SOURCE)|EMBEDDING_API_KEY_(FILE|SOURCE)|vector-api-key|(^|[^A-Za-z0-9_])THT_VEC_(REST_URL|WRITE_REST_URL)|thoth_vector_http'
scan_category runtime "$forbidden" "${runtime_files[@]}"
scan_category install "$forbidden" "${install_files[@]}"
scan_category operator "$forbidden" "${operator_files[@]}"
scan_category runtime "$retired_semantic" "${runtime_files[@]}"
scan_category install "$retired_semantic" "${install_files[@]}"
scan_category operator "$retired_semantic" "${operator_files[@]}"
# Contract tests legitimately quote forbidden names in negative assertions. Scan their positive
# deployment wiring constructs instead, so a provider-owned network or retired overlay cannot be
# required under a different test filename.
positive_contract='networks(\?|\.)?\.?localllm_default|services(\?|\.)?\.?core(\?|\.)?\.?networks(\?|\.)?\.?localllm_default|docker compose[^\n]*(compose\.psd-local|compose\.production)|THT_PSD_[A-Z0-9_]*='
scan_category contract-test "$positive_contract" "${contract_test_files[@]}"
contract_scan_files=()
for file in "${contract_test_files[@]}"; do
case "${file#scripts/}" in
test-compose-secret-policy.sh) continue ;;
esac
contract_scan_files+=("$file")
done
retired_semantic_contract='docker compose[^\n]*(compose\.local-vector|compose\.preprocess-local-vector)|THT_VECTOR_([A-Z0-9_]+)=|THT_OLLAMA_URL=|THT_WS_[A-Z0-9_]*_(VECTOR|EMBEDDING)_[A-Z0-9_]+=|vector-api-key|pgvector|pg_(dump|restore)'
scan_category contract-test "$retired_semantic_contract" "${contract_scan_files[@]}"
if [[ -f scripts/run-stack.sh ]]; then
set +e
host_pi="$(rg -n 'command -v pi|PI_BIN="pi"|PI_BIN=pi' scripts/run-stack.sh 2>&1)"
host_pi_status=$?
set -e
case "$host_pi_status" in
0) offenders+=("operator: $host_pi") ;;
1) ;;
*)
echo "coupling scan failed in host-Pi contract (rg status $host_pi_status)" >&2
printf '%s\n' "$host_pi" >&2
exit "$host_pi_status"
;;
esac
fi
if ((${#offenders[@]})); then
printf '%s\n' "active deployment coupling found:" >&2
printf '%s\n' "${offenders[@]}" >&2
exit 1
fi
echo "no active retired deployment or external semantic coupling found."