deploy: unify local and server compose stack
This commit is contained in:
+11
-38
@@ -1,42 +1,15 @@
|
|||||||
# ThothII Compose defaults. Copy this file to .env in the repository root.
|
# Common non-secret Compose values. Select local.env or server.env with --env-file.
|
||||||
# The root .env is loaded automatically by Docker Compose; do not put secrets here.
|
# Run Compose with both files explicitly, for example:
|
||||||
|
# docker compose -f compose.yaml -f deploy/compose.local.yaml up -d --build
|
||||||
|
|
||||||
COMPOSE_FILE=compose.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
|
MAX_PI_PROCESSES=4
|
||||||
PI_PROVIDER=
|
THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/platform/thoth-workspaces.git
|
||||||
PI_MODEL=
|
|
||||||
PI_THINKING=
|
|
||||||
PI_AUTH_FILE=${HOME}/.pi/agent/auth.json
|
|
||||||
|
|
||||||
# Git-backed workspace registry. Set the remote only in the installation environment;
|
|
||||||
# credentials and SSH/CA files remain outside this repository and are bind-mounted read-only.
|
|
||||||
THT_WORKSPACE_REGISTRY_ROOT=/data/workspace-registry
|
|
||||||
THT_WORKSPACE_GIT_BRANCH=main
|
THT_WORKSPACE_GIT_BRANCH=main
|
||||||
THT_WORKSPACE_INSTALLATION_ID=local
|
THT_WORKSPACE_GIT_AUTHOR_NAME="Thoth Workspace Registry"
|
||||||
# THT_WORKSPACE_GIT_REMOTE=ssh://git@your-git-host/your-org/thoth-workspaces.git
|
THT_WORKSPACE_GIT_AUTHOR_EMAIL=thoth-workspace-registry@example.invalid
|
||||||
# THT_WORKSPACE_GIT_CREDENTIALS_FILE=/absolute/path/to/git-credentials
|
|
||||||
# THT_WORKSPACE_GIT_CA_FILE=/absolute/path/to/git-ca.pem
|
|
||||||
# THT_WORKSPACE_GIT_SSH_KEY_FILE=/absolute/path/to/git-ssh-key
|
|
||||||
# THT_WORKSPACE_GIT_KNOWN_HOSTS_FILE=/absolute/path/to/git-known-hosts
|
|
||||||
|
|
||||||
# Set these for the selected DWH/vector/embedding adapters.
|
THT_DB_NAME=warehouse
|
||||||
THT_DB_NAME=
|
THT_DWH_REST_URL=https://dwh.example.invalid
|
||||||
THT_DWH_REST_URL=
|
THT_VEC_REST_URL=https://vector.example.invalid
|
||||||
THT_VEC_REST_URL=
|
THT_VEC_WRITE_REST_URL=https://vector-write.example.invalid
|
||||||
THT_VEC_WRITE_REST_URL=
|
THT_OLLAMA_URL=https://embeddings.example.invalid
|
||||||
THT_OLLAMA_URL=
|
|
||||||
THT_DOCS_ROOT=/data/workspaces/example/evidence-source
|
|
||||||
THT_PROFILE=server
|
|
||||||
|
|
||||||
# Local-vector defaults (used by the optional local-vector overlay).
|
|
||||||
THT_VECTOR_DATABASE=thoth
|
|
||||||
THT_VECTOR_BOOTSTRAP_USER=postgres
|
|
||||||
THT_VECTOR_MIGRATOR_USER=thoth_vector_migrator
|
|
||||||
THT_VECTOR_READER_USER=thoth_vector_reader
|
|
||||||
THT_VECTOR_WRITER_USER=thoth_vector_writer
|
|
||||||
|
|||||||
+33
-47
@@ -1,14 +1,3 @@
|
|||||||
# ThothII — deploy embedded nel portale omics_portal (PRODUZIONE).
|
|
||||||
# core + frontend sulla rete esterna del portale (omics_portal_omics_network,
|
|
||||||
# creata da Compose col prefisso project). Alias thothii-core/thothii-frontend
|
|
||||||
# per il DNS usato dagli upstream nginx del portale.
|
|
||||||
# NESSUNA porta host esposta: il backend è invisibile dall'esterno.
|
|
||||||
#
|
|
||||||
# Prereq: devono esistere entrambe le reti esterne: il portale crea
|
|
||||||
# omics_portal_omics_network e lo stack vLLM crea localllm_default.
|
|
||||||
# Avvia il portale con:
|
|
||||||
# cd /home/chirone/omics_portal && docker compose up -d
|
|
||||||
# Poi: docker compose up -d --build
|
|
||||||
name: thothii
|
name: thothii
|
||||||
|
|
||||||
services:
|
services:
|
||||||
@@ -17,68 +6,65 @@ services:
|
|||||||
context: .
|
context: .
|
||||||
dockerfile: docker/core.Dockerfile
|
dockerfile: docker/core.Dockerfile
|
||||||
image: thothii-core:local
|
image: thothii-core:local
|
||||||
env_file:
|
|
||||||
- path: deploy/thothii.env
|
|
||||||
required: false
|
|
||||||
environment:
|
environment:
|
||||||
HOST: 0.0.0.0
|
HOST: 0.0.0.0
|
||||||
PORT: "8787"
|
PORT: "8787"
|
||||||
THT_HARNESS_DIR: /app/harness
|
THT_HARNESS_DIR: /app/harness
|
||||||
THT_BIN: /opt/venv/bin/tht
|
THT_BIN: /opt/venv/bin/tht
|
||||||
|
THT_DATA_ROOT: /data
|
||||||
SETTINGS_FILE: /data/settings/settings.json
|
SETTINGS_FILE: /data/settings/settings.json
|
||||||
THT_CONFIG: /app/harness/workspaces/local.yaml # configPath di default per i route tht senza workspace esplicito
|
|
||||||
THT_MODEL_API_KEY_FILE: /data/secrets/model_api_key # provider key per buildPiChildEnv (codex)
|
|
||||||
THT_WORKSPACE_REGISTRY_ROOT: /data/workspace-registry
|
THT_WORKSPACE_REGISTRY_ROOT: /data/workspace-registry
|
||||||
THT_WORKSPACE_GIT_REMOTE: ${THT_WORKSPACE_GIT_REMOTE:?set THT_WORKSPACE_GIT_REMOTE}
|
THT_WORKSPACE_GIT_REMOTE: ${THT_WORKSPACE_GIT_REMOTE:?set THT_WORKSPACE_GIT_REMOTE}
|
||||||
THT_WORKSPACE_GIT_BRANCH: ${THT_WORKSPACE_GIT_BRANCH:-main}
|
THT_WORKSPACE_GIT_BRANCH: ${THT_WORKSPACE_GIT_BRANCH:-main}
|
||||||
THT_WORKSPACE_INSTALLATION_ID: ${THT_WORKSPACE_INSTALLATION_ID:-server}
|
THT_WORKSPACE_INSTALLATION_ID: ${THT_WORKSPACE_INSTALLATION_ID:-local}
|
||||||
THT_WORKSPACE_GIT_AUTHOR_NAME: ${THT_WORKSPACE_GIT_AUTHOR_NAME:-Thoth Workspace Registry}
|
THT_WORKSPACE_GIT_AUTHOR_NAME: ${THT_WORKSPACE_GIT_AUTHOR_NAME:-Thoth Workspace Registry}
|
||||||
THT_WORKSPACE_GIT_AUTHOR_EMAIL: ${THT_WORKSPACE_GIT_AUTHOR_EMAIL:-thoth-workspace-registry@localhost}
|
THT_WORKSPACE_GIT_AUTHOR_EMAIL: ${THT_WORKSPACE_GIT_AUTHOR_EMAIL:-thoth-workspace-registry@localhost}
|
||||||
THT_WORKSPACE_SECRET_ROOTS: /run/secrets
|
THT_WORKSPACE_SECRET_ROOTS: /run/secrets
|
||||||
GIT_CONFIG_COUNT: "2"
|
THT_DB_NAME: ${THT_DB_NAME:-}
|
||||||
GIT_CONFIG_KEY_0: credential.helper
|
THT_DWH_REST_URL: ${THT_DWH_REST_URL:-}
|
||||||
GIT_CONFIG_VALUE_0: store --file=/run/secrets/workspace-registry-git-credentials
|
THT_VEC_REST_URL: ${THT_VEC_REST_URL:-}
|
||||||
GIT_CONFIG_KEY_1: http.sslCAInfo
|
THT_VEC_WRITE_REST_URL: ${THT_VEC_WRITE_REST_URL:-}
|
||||||
GIT_CONFIG_VALUE_1: /run/secrets/workspace-registry-git-ca
|
THT_OLLAMA_URL: ${THT_OLLAMA_URL:-}
|
||||||
GIT_SSH_COMMAND: ssh -i /run/secrets/workspace-registry-git-ssh-key -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=/run/secrets/workspace-registry-git-known-hosts
|
|
||||||
AUTH_MODE: ${AUTH_MODE:-none}
|
|
||||||
MAX_PI_PROCESSES: ${MAX_PI_PROCESSES:-4}
|
MAX_PI_PROCESSES: ${MAX_PI_PROCESSES:-4}
|
||||||
extra_hosts:
|
|
||||||
- "host.docker.internal:host-gateway" # Supabase :5438 + Ollama :11434 sull'host
|
|
||||||
volumes:
|
volumes:
|
||||||
- /home/chirone/thothii-data:/data
|
- settings:/data/settings
|
||||||
|
- pi-state:/home/thoth/.pi
|
||||||
- workspace-registry:/data/workspace-registry
|
- workspace-registry:/data/workspace-registry
|
||||||
- /home/chirone/thothii-data/pi-config:/home/thoth/.pi
|
- sessions:/data/sessions
|
||||||
- ${PI_AUTH_FILE:?set PI_AUTH_FILE}:/home/thoth/.pi/agent/auth.json:ro
|
healthcheck:
|
||||||
- /home/chirone/chirone/etl/docs/evidence:/data/evidence:ro
|
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8787/health"]
|
||||||
- ${THT_WORKSPACE_GIT_CREDENTIALS_FILE:-/dev/null}:/run/secrets/workspace-registry-git-credentials:ro
|
interval: 15s
|
||||||
- ${THT_WORKSPACE_GIT_CA_FILE:-/etc/ssl/certs/ca-certificates.crt}:/run/secrets/workspace-registry-git-ca:ro
|
timeout: 3s
|
||||||
- ${THT_WORKSPACE_GIT_SSH_KEY_FILE:-/dev/null}:/run/secrets/workspace-registry-git-ssh-key:ro
|
retries: 5
|
||||||
- ${THT_WORKSPACE_GIT_KNOWN_HOSTS_FILE:-/dev/null}:/run/secrets/workspace-registry-git-known-hosts:ro
|
start_period: 30s
|
||||||
restart: unless-stopped
|
|
||||||
networks:
|
networks:
|
||||||
omics_portal_omics_network:
|
- thothii
|
||||||
aliases: ["thothii-core"]
|
|
||||||
localllm_default: {}
|
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: docker/frontend.Dockerfile
|
dockerfile: docker/frontend.Dockerfile
|
||||||
args:
|
args:
|
||||||
VITE_BASE: /datamart-builder/assets/
|
VITE_BASE: /
|
||||||
VITE_BACKEND_URL: /datamart-builder/api
|
VITE_BACKEND_URL: /api
|
||||||
image: thothii-frontend:local
|
image: thothii-frontend:local
|
||||||
restart: unless-stopped
|
depends_on:
|
||||||
|
core:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:8080/ || exit 1"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
networks:
|
networks:
|
||||||
omics_portal_omics_network:
|
- thothii
|
||||||
aliases: ["thothii-frontend"]
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
omics_portal_omics_network:
|
thothii:
|
||||||
external: true
|
|
||||||
localllm_default:
|
|
||||||
external: true
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
|
settings:
|
||||||
|
pi-state:
|
||||||
workspace-registry:
|
workspace-registry:
|
||||||
|
sessions:
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
services:
|
services:
|
||||||
core:
|
core:
|
||||||
environment:
|
environment:
|
||||||
# Non-secret settings come from the root .env interpolation file.
|
AUTH_MODE: none
|
||||||
AUTH_MODE: "${AUTH_MODE:-none}"
|
THT_WORKSPACE_INSTALLATION_ID: local
|
||||||
THT_SECRETS_FILE: /run/secrets/thothii.secrets
|
ports:
|
||||||
|
- "127.0.0.1:${THOTH_CORE_HTTP_PORT:-8787}:8787"
|
||||||
|
restart: "no"
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:${THOTH_HTTP_PORT:-8080}:8080"
|
||||||
|
restart: "no"
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
services:
|
||||||
|
core:
|
||||||
|
environment:
|
||||||
|
AUTH_MODE: upstream
|
||||||
|
THOTH_PUBLIC_EXPOSURE: "true"
|
||||||
|
THT_DATA_ROOT: /data
|
||||||
|
THT_WORKSPACE_INSTALLATION_ID: server
|
||||||
|
volumes: !override
|
||||||
|
- ${THT_DATA_ROOT:?set THT_DATA_ROOT}:/data
|
||||||
|
- ${THT_PI_STATE_ROOT:?set THT_PI_STATE_ROOT}:/home/thoth/.pi
|
||||||
|
- ${THT_WORKSPACE_REGISTRY_ROOT:?set THT_WORKSPACE_REGISTRY_ROOT}:/data/workspace-registry
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
ports:
|
||||||
|
- "${THOTH_SERVER_BIND:-127.0.0.1}:${THOTH_HTTP_PORT:-8080}:8080"
|
||||||
|
restart: unless-stopped
|
||||||
Vendored
+16
@@ -0,0 +1,16 @@
|
|||||||
|
# Local profile defaults. Copy this file to an untracked local.env and pass it with --env-file.
|
||||||
|
# Values are non-secret documentation values only.
|
||||||
|
THOTH_HTTP_PORT=8080
|
||||||
|
THOTH_CORE_HTTP_PORT=8787
|
||||||
|
MAX_PI_PROCESSES=4
|
||||||
|
|
||||||
|
THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/platform/thoth-workspaces.git
|
||||||
|
THT_WORKSPACE_GIT_BRANCH=main
|
||||||
|
THT_WORKSPACE_GIT_AUTHOR_NAME="Thoth Workspace Registry"
|
||||||
|
THT_WORKSPACE_GIT_AUTHOR_EMAIL=thoth-workspace-registry@example.invalid
|
||||||
|
|
||||||
|
THT_DB_NAME=warehouse
|
||||||
|
THT_DWH_REST_URL=https://dwh.example.invalid
|
||||||
|
THT_VEC_REST_URL=https://vector.example.invalid
|
||||||
|
THT_VEC_WRITE_REST_URL=https://vector-write.example.invalid
|
||||||
|
THT_OLLAMA_URL=https://embeddings.example.invalid
|
||||||
Vendored
+19
@@ -0,0 +1,19 @@
|
|||||||
|
# Server profile defaults. Copy this file to a reviewed, untracked server.env and pass it with --env-file.
|
||||||
|
# Values are non-secret documentation values only.
|
||||||
|
THOTH_SERVER_BIND=127.0.0.1
|
||||||
|
THOTH_HTTP_PORT=8080
|
||||||
|
MAX_PI_PROCESSES=4
|
||||||
|
|
||||||
|
THT_DATA_ROOT=/srv/thothii/data
|
||||||
|
THT_PI_STATE_ROOT=/srv/thothii/pi-state
|
||||||
|
THT_WORKSPACE_REGISTRY_ROOT=/srv/thothii/workspace-registry
|
||||||
|
THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/platform/thoth-workspaces.git
|
||||||
|
THT_WORKSPACE_GIT_BRANCH=main
|
||||||
|
THT_WORKSPACE_GIT_AUTHOR_NAME="Thoth Workspace Registry"
|
||||||
|
THT_WORKSPACE_GIT_AUTHOR_EMAIL=thoth-workspace-registry@example.invalid
|
||||||
|
|
||||||
|
THT_DB_NAME=warehouse
|
||||||
|
THT_DWH_REST_URL=https://dwh.example.invalid
|
||||||
|
THT_VEC_REST_URL=https://vector.example.invalid
|
||||||
|
THT_VEC_WRITE_REST_URL=https://vector-write.example.invalid
|
||||||
|
THT_OLLAMA_URL=https://embeddings.example.invalid
|
||||||
@@ -1,43 +1,26 @@
|
|||||||
#!/bin/sh
|
#!/usr/bin/env bash
|
||||||
set -eu
|
set -euo pipefail
|
||||||
|
|
||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
test -f .env.example
|
test -f .env.example
|
||||||
test -f deploy/secrets/thothii.secrets.example
|
test -f deploy/env/local.env.example
|
||||||
grep -q '^docker compose up --build -d$' docs/installazione-docker-4-contesti.md
|
test -f deploy/env/server.env.example
|
||||||
if grep -q 'cp deploy/env.example deploy/.env\|THT_[A-Z0-9_]*_SECRET_FILE=' docs/installazione-docker-4-contesti.md; then
|
|
||||||
echo "installation guide still presents the legacy per-file secret setup" >&2
|
rendered=$(mktemp)
|
||||||
|
trap 'rm -f "$rendered"' EXIT HUP INT TERM
|
||||||
|
|
||||||
|
docker compose --env-file deploy/env/local.env.example \
|
||||||
|
-f compose.yaml -f deploy/compose.local.yaml config >"$rendered"
|
||||||
|
|
||||||
|
grep -q '^ core:' "$rendered"
|
||||||
|
grep -q '^ frontend:' "$rendered"
|
||||||
|
grep -q 'host_ip: 127.0.0.1' "$rendered"
|
||||||
|
grep -q 'AUTH_MODE: none' "$rendered"
|
||||||
|
grep -q 'THT_WORKSPACE_INSTALLATION_ID: local' "$rendered"
|
||||||
|
if grep -Eqi 'omics_portal|chirone|localllm_default|/home/chirone' "$rendered"; then
|
||||||
|
echo "default Compose contains application-specific coupling" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tmp=$(mktemp -d)
|
|
||||||
trap 'rm -rf "$tmp"' EXIT HUP INT TERM
|
|
||||||
|
|
||||||
mkdir -p "$tmp/deploy/secrets" "$tmp/deploy/workspaces"
|
|
||||||
cp compose.yaml "$tmp/compose.yaml"
|
|
||||||
cp .env.example "$tmp/.env"
|
|
||||||
cp deploy/secrets/thothii.secrets.example "$tmp/deploy/secrets/thothii.secrets"
|
|
||||||
printf '%s\n' 'THT_MODEL_API_KEY=example-secret' >>"$tmp/deploy/secrets/thothii.secrets"
|
|
||||||
chmod 0600 "$tmp/deploy/secrets/thothii.secrets"
|
|
||||||
|
|
||||||
services=$(docker compose --project-directory "$tmp" config --services)
|
|
||||||
[ "$services" = "core
|
|
||||||
frontend" ] || {
|
|
||||||
echo "default Compose services must be core and frontend (got: $services)" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
rendered=$(docker compose --project-directory "$tmp" config)
|
|
||||||
printf '%s\n' "$rendered" | grep -q 'target: thothii.secrets'
|
|
||||||
if printf '%s\n' "$rendered" | grep -Eq 'dwh_api_key|vector_reader_api_key|vector_writer_api_key|model_api_key|thoth_ca'; then
|
|
||||||
echo "default Compose must not declare legacy per-secret mounts" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if printf '%s\n' "$rendered" | grep -Eq 'THT_[A-Z0-9_]+_SECRET_FILE:'; then
|
|
||||||
echo "default Compose must not require legacy secret-file variables" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
printf '%s\n' "$rendered" | grep -q 'THT_SECRETS_FILE: /run/secrets/thothii.secrets'
|
|
||||||
|
|
||||||
echo "default Compose contract passed."
|
echo "default Compose contract passed."
|
||||||
|
|||||||
Executable
+84
@@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
tmp=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$tmp"' EXIT HUP INT TERM
|
||||||
|
|
||||||
|
render_profile() {
|
||||||
|
local profile=$1
|
||||||
|
local env_file=$2
|
||||||
|
local compose_file=$3
|
||||||
|
local rendered="$tmp/$profile.json"
|
||||||
|
|
||||||
|
docker compose --env-file "$env_file" -f compose.yaml -f "$compose_file" \
|
||||||
|
config --format json >"$rendered"
|
||||||
|
|
||||||
|
node - "$rendered" "$profile" <<'NODE'
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
const [configPath, profile] = process.argv.slice(2);
|
||||||
|
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
||||||
|
const services = Object.keys(config.services).sort();
|
||||||
|
if (services.join(",") !== "core,frontend") throw new Error("mandatory stack must be core,frontend");
|
||||||
|
if (/omics_portal|chirone|localllm_default|\/home\/chirone/i.test(JSON.stringify(config))) {
|
||||||
|
throw new Error("forbidden application coupling");
|
||||||
|
}
|
||||||
|
if (!config.networks || !config.networks.thothii) throw new Error("base stack must define the thothii network");
|
||||||
|
|
||||||
|
const ports = Object.fromEntries(
|
||||||
|
Object.entries(config.services).map(([name, service]) => [name, service.ports || []]),
|
||||||
|
);
|
||||||
|
if (profile === "local") {
|
||||||
|
if (!ports.frontend.some((port) => port.host_ip === "127.0.0.1")) {
|
||||||
|
throw new Error("local frontend must publish a loopback port");
|
||||||
|
}
|
||||||
|
if (ports.core.length !== 0 && !ports.core.every((port) => port.host_ip === "127.0.0.1")) {
|
||||||
|
throw new Error("local core may publish only loopback ports");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ports.core.length !== 0) throw new Error("server core must not publish a host port");
|
||||||
|
if (ports.frontend.length === 0) throw new Error("server frontend must publish a host port");
|
||||||
|
}
|
||||||
|
NODE
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_remote_required() {
|
||||||
|
local env_file=$1
|
||||||
|
local compose_file=$2
|
||||||
|
local without_remote="$tmp/without-remote.env"
|
||||||
|
grep -v '^THT_WORKSPACE_GIT_REMOTE=' "$env_file" >"$without_remote"
|
||||||
|
|
||||||
|
if env -u THT_WORKSPACE_GIT_REMOTE docker compose --env-file "$without_remote" -f compose.yaml -f "$compose_file" \
|
||||||
|
config --format json >"$tmp/missing-remote.out" 2>"$tmp/missing-remote.err"; then
|
||||||
|
echo "Compose must require THT_WORKSPACE_GIT_REMOTE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
grep -q 'THT_WORKSPACE_GIT_REMOTE' "$tmp/missing-remote.err"
|
||||||
|
}
|
||||||
|
|
||||||
|
THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/platform/thoth-workspaces.git \
|
||||||
|
PI_AUTH_FILE=/dev/null \
|
||||||
|
docker compose -f compose.yaml config --format json >"$tmp/base.json"
|
||||||
|
node - "$tmp/base.json" <<'NODE'
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
const config = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
|
||||||
|
const services = Object.keys(config.services).sort();
|
||||||
|
if (services.join(",") !== "core,frontend") throw new Error("mandatory stack must be core,frontend");
|
||||||
|
if (/omics_portal|chirone|localllm_default|\/home\/chirone/i.test(JSON.stringify(config))) {
|
||||||
|
throw new Error("forbidden application coupling");
|
||||||
|
}
|
||||||
|
if (!config.networks || !config.networks.thothii) throw new Error("base stack must define the thothii network");
|
||||||
|
for (const volume of ["settings", "pi-state", "workspace-registry", "sessions"]) {
|
||||||
|
if (!config.volumes || !config.volumes[volume]) throw new Error(`missing required volume: ${volume}`);
|
||||||
|
}
|
||||||
|
NODE
|
||||||
|
|
||||||
|
render_profile local deploy/env/local.env.example deploy/compose.local.yaml
|
||||||
|
render_profile server deploy/env/server.env.example deploy/compose.server.yaml
|
||||||
|
assert_remote_required deploy/env/local.env.example deploy/compose.local.yaml
|
||||||
|
assert_remote_required deploy/env/server.env.example deploy/compose.server.yaml
|
||||||
|
|
||||||
|
echo "unified Compose contract passed."
|
||||||
Reference in New Issue
Block a user