fix: harden compose Pi auth mounts

This commit is contained in:
2026-08-04 14:55:05 +02:00
parent 2e67568282
commit 2ce2e0089a
6 changed files with 32 additions and 0 deletions
+1
View File
@@ -13,3 +13,4 @@ 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
THT_LLM_URL=https://llm.example.invalid
+2
View File
@@ -25,10 +25,12 @@ services:
THT_VEC_REST_URL: ${THT_VEC_REST_URL:-}
THT_VEC_WRITE_REST_URL: ${THT_VEC_WRITE_REST_URL:-}
THT_OLLAMA_URL: ${THT_OLLAMA_URL:-}
THT_LLM_URL: ${THT_LLM_URL:-}
MAX_PI_PROCESSES: ${MAX_PI_PROCESSES:-4}
volumes:
- settings:/data/settings
- pi-state:/home/thoth/.pi
- ${PI_AUTH_FILE:?set PI_AUTH_FILE}:/home/thoth/.pi/agent/auth.json:ro
- workspace-registry:/data/workspace-registry
- sessions:/data/sessions
healthcheck:
+1
View File
@@ -8,6 +8,7 @@ services:
volumes: !override
- ${THT_DATA_ROOT:?set THT_DATA_ROOT}:/data
- ${THT_PI_STATE_ROOT:?set THT_PI_STATE_ROOT}:/home/thoth/.pi
- ${PI_AUTH_FILE:?set PI_AUTH_FILE}:/home/thoth/.pi/agent/auth.json:ro
- ${THT_WORKSPACE_REGISTRY_ROOT:?set THT_WORKSPACE_REGISTRY_ROOT}:/data/workspace-registry
restart: unless-stopped
+2
View File
@@ -3,6 +3,7 @@
THOTH_HTTP_PORT=8080
THOTH_CORE_HTTP_PORT=8787
MAX_PI_PROCESSES=4
PI_AUTH_FILE=/absolute/path/to/pi-auth.json
THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/platform/thoth-workspaces.git
THT_WORKSPACE_GIT_BRANCH=main
@@ -14,3 +15,4 @@ 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
THT_LLM_URL=https://llm.example.invalid
+2
View File
@@ -3,6 +3,7 @@
THOTH_SERVER_BIND=127.0.0.1
THOTH_HTTP_PORT=8080
MAX_PI_PROCESSES=4
PI_AUTH_FILE=/absolute/path/to/pi-auth.json
THT_DATA_ROOT=/srv/thothii/data
THT_PI_STATE_ROOT=/srv/thothii/pi-state
@@ -17,3 +18,4 @@ 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
THT_LLM_URL=https://llm.example.invalid
+24
View File
@@ -26,6 +26,18 @@ if (/omics_portal|chirone|localllm_default|\/home\/chirone/i.test(JSON.stringify
throw new Error("forbidden application coupling");
}
if (!config.networks || !config.networks.thothii) throw new Error("base stack must define the thothii network");
if (!Object.hasOwn(config.services.core.environment || {}, "THT_LLM_URL")) {
throw new Error("core must expose a generic THT_LLM_URL endpoint contract");
}
if (/docker\.sock|\/var\/run\/docker|docker[-_]?daemon/i.test(JSON.stringify(config.services))) {
throw new Error("Compose must not mount the Docker socket or daemon");
}
const piAuthMounts = (config.services.core.volumes || []).filter(
(mount) => mount.target === "/home/thoth/.pi/agent/auth.json",
);
if (piAuthMounts.length !== 1 || piAuthMounts[0].type !== "bind" || !piAuthMounts[0].read_only) {
throw new Error("Pi auth must be one read-only file bind");
}
const ports = Object.fromEntries(
Object.entries(config.services).map(([name, service]) => [name, service.ports || []]),
@@ -74,6 +86,18 @@ if (!config.networks || !config.networks.thothii) throw new Error("base stack mu
for (const volume of ["settings", "pi-state", "workspace-registry", "sessions"]) {
if (!config.volumes || !config.volumes[volume]) throw new Error(`missing required volume: ${volume}`);
}
if (!Object.hasOwn(config.services.core.environment || {}, "THT_LLM_URL")) {
throw new Error("core must expose a generic THT_LLM_URL endpoint contract");
}
if (/docker\.sock|\/var\/run\/docker|docker[-_]?daemon/i.test(JSON.stringify(config.services))) {
throw new Error("Compose must not mount the Docker socket or daemon");
}
const piAuthMounts = (config.services.core.volumes || []).filter(
(mount) => mount.target === "/home/thoth/.pi/agent/auth.json",
);
if (piAuthMounts.length !== 1 || piAuthMounts[0].type !== "bind" || !piAuthMounts[0].read_only) {
throw new Error("Pi auth must be one read-only file bind");
}
NODE
render_profile local deploy/env/local.env.example deploy/compose.local.yaml