refactor: remove portal deployment coupling
This commit is contained in:
@@ -1,70 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
source_env=${1:-"$root/../../harness/.env"}
|
||||
workspace=${2:-"$root/../../../tht-workspace-psd"}
|
||||
auth_file=${3:-"$HOME/.pi/agent/auth.json"}
|
||||
|
||||
value() {
|
||||
awk -F= -v key="$1" '$1 == key { sub(/^[^=]*=/, ""); sub(/[[:space:]].*$/, ""); print; exit }' "$source_env"
|
||||
}
|
||||
required() {
|
||||
result=$(value "$1")
|
||||
[ -n "$result" ] || { echo "missing $1 in local source configuration" >&2; exit 2; }
|
||||
printf '%s' "$result"
|
||||
}
|
||||
|
||||
test -f "$source_env"
|
||||
test -d "$workspace"
|
||||
test -f "$auth_file"
|
||||
ca=$(value THT_SSL_CA)
|
||||
[ -z "$ca" ] || test -f "$ca"
|
||||
model_key=$(jq -er '.zai.key' "$auth_file")
|
||||
test -n "$model_key"
|
||||
|
||||
umask 077
|
||||
mkdir -p "$root/deploy/secrets" "$root/deploy/workspaces"
|
||||
: >"$root/deploy/thothii.env"
|
||||
cp "$root/deploy/compose.psd-local.yaml.example" "$root/deploy/compose.psd-local.yaml"
|
||||
cp "$root/deploy/workspaces/psd.yaml.example" "$root/deploy/workspaces/psd.yaml"
|
||||
cat >"$root/.env" <<EOF
|
||||
COMPOSE_FILE=compose.yaml:deploy/compose.psd-local.yaml
|
||||
COMPOSE_PROFILES=
|
||||
THT_SECRETS_FILE=./deploy/secrets/thothii.secrets
|
||||
THOTH_HTTP_PORT=8080
|
||||
AUTH_MODE=none
|
||||
THOTH_PUBLIC_EXPOSURE=false
|
||||
MAX_PI_PROCESSES=4
|
||||
PI_PROVIDER=zai
|
||||
PI_MODEL=glm-5.2
|
||||
PI_THINKING=medium
|
||||
PI_AUTH_FILE=$auth_file
|
||||
THT_PROFILE=workstation
|
||||
THT_DB_NAME=$(required THT_DB_NAME)
|
||||
THT_DWH_REST_URL=$(required THT_DWH_REST_URL)
|
||||
THT_VEC_REST_URL=$(required THT_VEC_REST_URL)
|
||||
THT_VEC_WRITE_REST_URL=$(required THT_VEC_WRITE_REST_URL)
|
||||
THT_OLLAMA_URL=http://host.docker.internal:11434
|
||||
THT_DOCS_ROOT=/data/workspaces/psd
|
||||
THT_PSD_WORKSPACE_HOST_PATH=$workspace
|
||||
EOF
|
||||
cat >"$root/deploy/secrets/thothii.secrets" <<EOF
|
||||
THT_MODEL_API_KEY=$model_key
|
||||
THT_DWH_API_KEY=$(required THT_DWH_API_KEY)
|
||||
THT_VEC_API_KEY=$(required THT_VEC_API_KEY)
|
||||
THT_VEC_WRITE_API_KEY=$(required THT_VEC_WRITE_API_KEY)
|
||||
EOF
|
||||
if [ -n "$ca" ]; then
|
||||
cat >>"$root/deploy/compose.psd-local.yaml" <<EOF
|
||||
- type: bind
|
||||
source: $ca
|
||||
target: /run/secrets/ca-chain.pem
|
||||
read_only: true
|
||||
EOF
|
||||
printf '%s\n' 'THT_CA=/run/secrets/ca-chain.pem' >>"$root/deploy/secrets/thothii.secrets"
|
||||
else
|
||||
printf '%s\n' 'THT_CA=/etc/ssl/certs/ca-certificates.crt' >>"$root/deploy/secrets/thothii.secrets"
|
||||
fi
|
||||
chmod 600 "$root/.env" "$root/deploy/thothii.env" "$root/deploy/secrets/thothii.secrets"
|
||||
echo "Local PSD Docker configuration materialized without printing secret values."
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# Smoke test del deploy standalone ThothII (core + frontend).
|
||||
# Usa docker-compose.dev.yml (rete propria, porte host). Non tocca il portale.
|
||||
# Prereq: deploy/thothii.env popolato + ruoli DB creati + pi-config + settings.json.
|
||||
# Usa docker-compose.dev.yml (rete propria, porte host).
|
||||
# Prereq: deploy/thothii.env popolato, endpoint esterni configurati e profilo Pi locale.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
|
||||
+12
-60
@@ -1,68 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
# run-stack.sh — avvia i 3 layer reali di ThothII per la validazione end-to-end.
|
||||
# run-stack.sh — avvia lo stack Compose locale di ThothII in primo piano.
|
||||
#
|
||||
# frontend (browser) → backend (Fastify :8787) → pi --mode rpc (GLM 5.2) → tht/harness → DWH
|
||||
# Il core include Pi; DWH, vector DB, embedding e LLM sono endpoint esterni configurati
|
||||
# in deploy/env/local.env. Non richiede un eseguibile Pi sull'host.
|
||||
#
|
||||
# Prerequisiti: VPN attiva, `pi` su PATH (GLM 5.2 configurato), harness/.env popolato,
|
||||
# harness/config/tht.yaml -> workspace cliente, deps installate nei 3 progetti.
|
||||
#
|
||||
# Uso: ./scripts/run-stack.sh
|
||||
# Stop: Ctrl-C (termina backend + frontend; i processi pi figli del backend muoiono con esso).
|
||||
# Preparazione: cp deploy/env/local.env.example deploy/env/local.env e compilare i valori.
|
||||
# Uso: ./scripts/run-stack.sh [argomenti aggiuntivi per docker compose up]
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
||||
HARNESS="$ROOT/harness"
|
||||
BACKEND="$ROOT/backend"
|
||||
FRONTEND="$ROOT/frontend"
|
||||
THT_BIN="$HARNESS/.venv/bin/tht"
|
||||
BACKEND_PORT="${BACKEND_PORT:-8787}"
|
||||
FRONTEND_PORT="${FRONTEND_PORT:-5173}"
|
||||
LOCAL_ENV_FILE="${THT_LOCAL_ENV_FILE:-$ROOT/deploy/env/local.env}"
|
||||
|
||||
# --- preflight ---------------------------------------------------------------
|
||||
[ -f "$HARNESS/.env" ] || { echo "ERRORE: $HARNESS/.env mancante (credenziali DWH/vector)"; exit 1; }
|
||||
[ -x "$THT_BIN" ] || { echo "ERRORE: $THT_BIN non trovato (esegui: cd harness && python -m venv .venv && pip install -e .)"; exit 1; }
|
||||
command -v pi >/dev/null || { echo "ERRORE: 'pi' non sul PATH (configura @earendil-works/pi-coding-agent con GLM 5.2)"; exit 1; }
|
||||
[ -e "$HARNESS/config/tht.yaml" ] || { echo "ERRORE: $HARNESS/config/tht.yaml mancante (symlink al workspace)"; exit 1; }
|
||||
[[ -f "$LOCAL_ENV_FILE" ]] || {
|
||||
echo "ERRORE: $LOCAL_ENV_FILE mancante. Copia deploy/env/local.env.example e configura gli endpoint." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Carica le variabili del DWH/vector nell'ambiente: il backend le passa a pi e a tht.
|
||||
set -a; . "$HARNESS/.env"; set +a
|
||||
|
||||
# tht deve essere raggiungibile dal processo pi che il backend spawna.
|
||||
export PATH="$HARNESS/.venv/bin:$PATH"
|
||||
|
||||
echo "== ThothII stack =="
|
||||
echo " harness : $HARNESS (tht: $THT_BIN)"
|
||||
echo " backend : http://localhost:$BACKEND_PORT"
|
||||
echo " frontend: http://localhost:$FRONTEND_PORT"
|
||||
echo " pi : $(command -v pi)"
|
||||
echo
|
||||
|
||||
# --- avvio -------------------------------------------------------------------
|
||||
pids=()
|
||||
cleanup() { echo; echo "Arresto stack..."; for p in "${pids[@]}"; do kill "$p" 2>/dev/null || true; done; }
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Backend: usa il pi reale + il tht del venv, cwd harness per lo spawn di pi.
|
||||
(
|
||||
cd "$BACKEND"
|
||||
PORT="$BACKEND_PORT" \
|
||||
THT_HARNESS_DIR="$HARNESS" \
|
||||
THT_BIN="$THT_BIN" \
|
||||
PI_BIN="pi" \
|
||||
AUTH_MODE="none" \
|
||||
THT_DWH_PRECHECK="1" \
|
||||
npm run dev
|
||||
) &
|
||||
pids+=($!)
|
||||
|
||||
# Frontend: il browser usa sempre /api; Vite lo inoltra al backend locale.
|
||||
(
|
||||
cd "$FRONTEND"
|
||||
THT_FRONTEND_API_UPSTREAM="http://localhost:$BACKEND_PORT" \
|
||||
npm run dev -- --port "$FRONTEND_PORT"
|
||||
) &
|
||||
pids+=($!)
|
||||
|
||||
echo "Stack avviato. Apri http://localhost:$FRONTEND_PORT e crea una nuova domanda."
|
||||
echo "Ctrl-C per fermare."
|
||||
wait
|
||||
exec docker compose --env-file "$LOCAL_ENV_FILE" \
|
||||
-f "$ROOT/compose.yaml" -f "$ROOT/deploy/compose.local.yaml" up --build "$@"
|
||||
|
||||
@@ -6,6 +6,9 @@ project="thothii-external-lifecycle-$$"
|
||||
cleanup() { docker compose --project-name "$project" --profile external down --volumes >/dev/null 2>&1 || true; }
|
||||
trap cleanup EXIT HUP INT TERM
|
||||
|
||||
export THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/platform/thoth-workspaces.git
|
||||
export PI_AUTH_FILE=/dev/null
|
||||
|
||||
unset THT_VECTOR_BOOTSTRAP_PASSWORD_SECRET_FILE THT_VECTOR_MIGRATOR_PASSWORD_SECRET_FILE
|
||||
unset THT_VECTOR_READER_PASSWORD_SECRET_FILE THT_VECTOR_WRITER_PASSWORD_SECRET_FILE
|
||||
rendered=$(docker compose --project-name "$project" --profile external config)
|
||||
@@ -13,6 +16,10 @@ if printf '%s' "$rendered" | grep -q 'THT_VECTOR_.*PASSWORD_FILE\|vector_.*passw
|
||||
echo "external config contains local vector secret references" >&2
|
||||
exit 1
|
||||
fi
|
||||
if printf '%s' "$rendered" | grep -Eqi 'omics_portal|chirone|localllm_default|/home/chirone|datamart-builder'; then
|
||||
echo "external config contains deployment-specific coupling" >&2
|
||||
exit 1
|
||||
fi
|
||||
docker compose --project-name "$project" --profile external up --build --wait core
|
||||
core=$(docker compose --project-name "$project" --profile external ps -q core)
|
||||
inspect=$(docker inspect "$core")
|
||||
@@ -20,4 +27,8 @@ if printf '%s' "$inspect" | grep -q 'THT_VECTOR_.*PASSWORD_FILE\|/run/secrets/ve
|
||||
echo "external core inspect contains local vector secret references" >&2
|
||||
exit 1
|
||||
fi
|
||||
if printf '%s' "$inspect" | grep -Eqi 'omics_portal|chirone|localllm_default|/home/chirone|datamart-builder'; then
|
||||
echo "external core inspect contains deployment-specific coupling" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "external core lifecycle without local vector secrets passed."
|
||||
|
||||
@@ -54,13 +54,13 @@ if [ "$response" != '{"backend":"fastify","path":"/health"}' ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! rg -Fq 'THT_FRONTEND_API_UPSTREAM="http://localhost:$BACKEND_PORT"' "$ROOT/scripts/run-stack.sh"; then
|
||||
echo "run-stack.sh must configure the Vite internal upstream from BACKEND_PORT" >&2
|
||||
if ! rg -Fq -- '-f "$ROOT/compose.yaml" -f "$ROOT/deploy/compose.local.yaml" up --build "$@"' "$ROOT/scripts/run-stack.sh"; then
|
||||
echo "run-stack.sh must start the base+local Compose stack" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if rg -q 'VITE_BACKEND_URL' "$ROOT/scripts/run-stack.sh"; then
|
||||
echo "run-stack.sh must keep the browser base on /api" >&2
|
||||
if rg -q 'command -v pi|PI_BIN="pi"|PI_BIN=pi' "$ROOT/scripts/run-stack.sh"; then
|
||||
echo "run-stack.sh must not require a host Pi binary" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
content_targets=(
|
||||
.dockerignore
|
||||
compose.yaml
|
||||
docker-compose.dev.yml
|
||||
deploy
|
||||
docker
|
||||
frontend/vite.config.ts
|
||||
README.md
|
||||
docs/install
|
||||
docs/installazione-docker-4-contesti.md
|
||||
.env.example
|
||||
scripts/run-stack.sh
|
||||
scripts/docker-smoke.sh
|
||||
)
|
||||
|
||||
matches=$(
|
||||
rg -n -i \
|
||||
-g '!deploy/workspaces/**' \
|
||||
-g '!docker/session-migrate.sh' \
|
||||
-g '!docker/cutover-legacy-sessions.sh' \
|
||||
-g '!docker/smoke/**' \
|
||||
'omics_portal|chirone|localllm_default|datamart-builder|compose\.production\.yaml|compose\.psd-local\.yaml' \
|
||||
"${content_targets[@]}" || true
|
||||
)
|
||||
|
||||
runtime_psd_matches=$(
|
||||
rg -n -i \
|
||||
-g '!deploy/workspaces/**' \
|
||||
-g '!docker/session-migrate.sh' \
|
||||
-g '!docker/cutover-legacy-sessions.sh' \
|
||||
-g '!docker/smoke/**' \
|
||||
'\bpsd\b' \
|
||||
.dockerignore compose.yaml docker-compose.dev.yml deploy docker frontend/vite.config.ts \
|
||||
.env.example scripts/run-stack.sh scripts/docker-smoke.sh || true
|
||||
)
|
||||
|
||||
offenders=()
|
||||
for superseded_file in \
|
||||
deploy/compose.production.yaml \
|
||||
deploy/compose.psd-local.yaml.example \
|
||||
deploy/compose.psd-local.yaml \
|
||||
scripts/bootstrap-local-psd-docker-config.sh \
|
||||
harness/tests/test_psd_local_compose_contract.py
|
||||
do
|
||||
[[ ! -e "$superseded_file" ]] || offenders+=("$superseded_file (forbidden active deployment filename)")
|
||||
done
|
||||
|
||||
if [[ -n "$matches" ]]; then
|
||||
while IFS= read -r match; do
|
||||
offenders+=("$match")
|
||||
done <<<"$matches"
|
||||
fi
|
||||
|
||||
if [[ -n "$runtime_psd_matches" ]]; then
|
||||
while IFS= read -r match; do
|
||||
offenders+=("$match")
|
||||
done <<<"$runtime_psd_matches"
|
||||
fi
|
||||
|
||||
if rg -n 'command -v pi|PI_BIN="pi"|PI_BIN=pi' scripts/run-stack.sh >/dev/null; then
|
||||
offenders+=("scripts/run-stack.sh (requires a host Pi binary)")
|
||||
fi
|
||||
|
||||
if ((${#offenders[@]})); then
|
||||
printf '%s\n' "active deployment coupling found:" >&2
|
||||
printf '%s\n' "${offenders[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "no active PSD, Chirone, or portal deployment coupling found."
|
||||
@@ -9,7 +9,8 @@ auth_file="$tmp/auth.json"
|
||||
printf '%s\n' '{}' >"$auth_file"
|
||||
chmod 0600 "$auth_file"
|
||||
|
||||
rendered=$(PI_AUTH_FILE="$auth_file" docker compose config)
|
||||
rendered=$(THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/platform/thoth-workspaces.git \
|
||||
PI_AUTH_FILE="$auth_file" docker compose config)
|
||||
printf '%s\n' "$rendered" | grep -q "source: $auth_file"
|
||||
printf '%s\n' "$rendered" | grep -q 'target: /home/thoth/.pi/agent/auth.json'
|
||||
printf '%s\n' "$rendered" | grep -A4 'target: /home/thoth/.pi/agent/auth.json' \
|
||||
@@ -29,6 +30,7 @@ assert settings["enabledModels"] == [
|
||||
PY
|
||||
|
||||
grep -q '^ARG PI_VERSION=0.80.3$' docker/core.Dockerfile
|
||||
grep -q '^PI_AUTH_FILE=$auth_file$' scripts/bootstrap-local-psd-docker-config.sh
|
||||
grep -q '^PI_AUTH_FILE=/absolute/path/to/pi-auth.json$' deploy/env/local.env.example
|
||||
grep -q '^PI_AUTH_FILE=/absolute/path/to/pi-auth.json$' deploy/env/server.env.example
|
||||
|
||||
echo "Pi user-auth Compose contract passed."
|
||||
|
||||
@@ -44,4 +44,17 @@ printf 'FROM scratch\n' > "$fixture_root/Dockerfile"
|
||||
|
||||
"$repo_root/scripts/verify-line-endings.sh" "$fixture_root"
|
||||
|
||||
git_fixture="$fixture_root/git-worktree"
|
||||
mkdir -p "$git_fixture"
|
||||
git -C "$git_fixture" init -q
|
||||
printf 'tracked then deleted\n' >"$git_fixture/deleted.md"
|
||||
git -C "$git_fixture" add deleted.md
|
||||
rm "$git_fixture/deleted.md"
|
||||
|
||||
git_output="$(cd "$git_fixture" && "$repo_root/scripts/verify-line-endings.sh" 2>&1)"
|
||||
if grep -Fq 'No such file or directory' <<<"$git_output"; then
|
||||
echo "line-ending verifier tried to read a tracked deletion" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "line-ending verifier tests passed"
|
||||
|
||||
@@ -23,6 +23,7 @@ root="$(cd "$root" && pwd)"
|
||||
offenders=()
|
||||
|
||||
while IFS= read -r -d '' file; do
|
||||
[[ -f "$file" ]] || continue
|
||||
case "$file" in
|
||||
*.ps1) continue ;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user