feat: profile-gated workspace-maintenance service and connector override generator (P2)
This commit is contained in:
@@ -55,6 +55,60 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- thothii
|
- thothii
|
||||||
|
|
||||||
|
workspace-maintenance:
|
||||||
|
image: thothii-core:local
|
||||||
|
profiles: [workspace-maintenance]
|
||||||
|
pull_policy: never
|
||||||
|
entrypoint: ["/usr/bin/tini", "--", "/app/docker/workspace-maintenance-entrypoint.sh"]
|
||||||
|
environment:
|
||||||
|
THT_HARNESS_DIR: /app/harness
|
||||||
|
THT_BIN: /opt/venv/bin/tht
|
||||||
|
THT_DATA_ROOT: /data
|
||||||
|
THT_WORKSPACE_REGISTRY_ROOT: /data/workspace-registry
|
||||||
|
THT_WORKSPACE_GIT_REMOTE: ${THT_WORKSPACE_GIT_REMOTE:?set THT_WORKSPACE_GIT_REMOTE}
|
||||||
|
THT_WORKSPACE_GIT_BRANCH: ${THT_WORKSPACE_GIT_BRANCH:-main}
|
||||||
|
THT_WORKSPACE_INSTALLATION_ID: ${THT_WORKSPACE_INSTALLATION_ID:-local}
|
||||||
|
THT_WORKSPACE_SECRET_ROOTS: /run/secrets
|
||||||
|
THT_SECRETS_FILE: /run/secrets/thothii.secrets
|
||||||
|
THT_DB_NAME: ${THT_DB_NAME:-}
|
||||||
|
THT_DWH_REST_URL: ${THT_DWH_REST_URL:-}
|
||||||
|
THT_LLM_URL: ${THT_LLM_URL:-}
|
||||||
|
THT_INTERNAL_QDRANT_URL: http://qdrant:6333
|
||||||
|
THT_INTERNAL_EMBEDDING_URL: http://embedding:11434
|
||||||
|
THT_INTERNAL_EMBEDDING_MODEL: qwen3-embedding:0.6b
|
||||||
|
THT_INTERNAL_EMBEDDING_DIMENSIONS: "1024"
|
||||||
|
HOME: /tmp/thoth
|
||||||
|
AWS_ACCESS_KEY_ID: ""
|
||||||
|
AWS_SECRET_ACCESS_KEY: ""
|
||||||
|
AWS_SESSION_TOKEN: ""
|
||||||
|
AWS_PROFILE: ""
|
||||||
|
AWS_DEFAULT_PROFILE: ""
|
||||||
|
AWS_CONFIG_FILE: /dev/null
|
||||||
|
AWS_SHARED_CREDENTIALS_FILE: /dev/null
|
||||||
|
volumes:
|
||||||
|
- type: volume
|
||||||
|
source: workspace-registry
|
||||||
|
target: /data/workspace-registry
|
||||||
|
read_only: true
|
||||||
|
- type: volume
|
||||||
|
source: sessions
|
||||||
|
target: /data/sessions
|
||||||
|
secrets:
|
||||||
|
- source: thothii_secrets
|
||||||
|
target: thothii.secrets
|
||||||
|
user: "10001:10001"
|
||||||
|
read_only: true
|
||||||
|
tmpfs:
|
||||||
|
- /tmp:rw,noexec,nosuid,nodev,size=64m,mode=1777
|
||||||
|
- /var/tmp:rw,noexec,nosuid,nodev,size=32m,mode=1777
|
||||||
|
cap_drop:
|
||||||
|
- ALL
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
|
restart: "no"
|
||||||
|
networks:
|
||||||
|
- thothii
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# Select this override only for an HTTPS Git remote. The separate CA mount keeps TLS validation
|
# Select this override only for an HTTPS Git remote. The separate CA mount keeps TLS validation
|
||||||
# explicit; neither host-only source file nor its contents belongs in the base Compose contract.
|
# explicit; neither host-only source file nor its contents belongs in the base Compose contract.
|
||||||
|
# Active-snapshot workspace-maintenance operations intentionally receive no Git credential mounts.
|
||||||
x-thoth-git-transport: https
|
x-thoth-git-transport: https
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# Select this override only for an SSH Git remote. The host-only source files must be absolute,
|
# Select this override only for an SSH Git remote. The host-only source files must be absolute,
|
||||||
# normalized paths; strict host-key checking is mandatory for registry pull and publish.
|
# normalized paths; strict host-key checking is mandatory for registry pull and publish.
|
||||||
|
# Active-snapshot workspace-maintenance operations intentionally receive no Git credential mounts.
|
||||||
x-thoth-git-transport: ssh
|
x-thoth-git-transport: ssh
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|||||||
@@ -11,3 +11,8 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:${THOTH_HTTP_PORT:-8080}:8080"
|
- "127.0.0.1:${THOTH_HTTP_PORT:-8080}:8080"
|
||||||
restart: "no"
|
restart: "no"
|
||||||
|
|
||||||
|
workspace-maintenance:
|
||||||
|
environment:
|
||||||
|
THT_WORKSPACE_INSTALLATION_ID: local
|
||||||
|
restart: "no"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# Retired for operator use: this profile remains only as a non-public engine-fixture path.
|
||||||
|
# It exercises the legacy preprocessing fixtures and must not become a second operator interface.
|
||||||
services:
|
services:
|
||||||
preprocess-evidence:
|
preprocess-evidence:
|
||||||
image: thothii-core:local
|
image: thothii-core:local
|
||||||
|
|||||||
@@ -35,3 +35,18 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "${THOTH_SERVER_BIND:-127.0.0.1}:${THOTH_HTTP_PORT:-8080}:8080"
|
- "${THOTH_SERVER_BIND:-127.0.0.1}:${THOTH_HTTP_PORT:-8080}:8080"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
|
|
||||||
|
workspace-maintenance:
|
||||||
|
environment:
|
||||||
|
THT_DATA_ROOT: /data
|
||||||
|
THT_WORKSPACE_INSTALLATION_ID: server
|
||||||
|
volumes: !override
|
||||||
|
- type: bind
|
||||||
|
source: ${THT_DATA_ROOT:?set THT_DATA_ROOT}/sessions
|
||||||
|
target: /data/sessions
|
||||||
|
- type: bind
|
||||||
|
source: ${THT_WORKSPACE_REGISTRY_ROOT:?set THT_WORKSPACE_REGISTRY_ROOT}
|
||||||
|
target: /data/workspace-registry
|
||||||
|
read_only: true
|
||||||
|
restart: "no"
|
||||||
|
|||||||
+12
-6
@@ -33,10 +33,16 @@ LABEL org.opencontainers.image.title="thothii-core" \
|
|||||||
io.thothii.pi.version="${PI_VERSION}"
|
io.thothii.pi.version="${PI_VERSION}"
|
||||||
|
|
||||||
# Runtime tools
|
# Runtime tools
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN set -eux; \
|
||||||
curl ca-certificates ripgrep fd-find tini git openssh-client \
|
runtime_packages="curl ca-certificates ripgrep fd-find tini git openssh-client"; \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
if ! command -v flock >/dev/null 2>&1; then \
|
||||||
&& ln -s /usr/bin/fdfind /usr/local/bin/fd
|
runtime_packages="$runtime_packages util-linux"; \
|
||||||
|
fi; \
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends $runtime_packages; \
|
||||||
|
rm -rf /var/lib/apt/lists/*; \
|
||||||
|
command -v flock >/dev/null 2>&1; \
|
||||||
|
ln -s /usr/bin/fdfind /usr/local/bin/fd
|
||||||
|
|
||||||
# Node 22 + npm copiati dall'immagine ufficiale (stesso Debian bookworm → binario compatibile)
|
# Node 22 + npm copiati dall'immagine ufficiale (stesso Debian bookworm → binario compatibile)
|
||||||
COPY --from=node-runtime /usr/local/bin/node /usr/local/bin/node
|
COPY --from=node-runtime /usr/local/bin/node /usr/local/bin/node
|
||||||
@@ -91,10 +97,10 @@ ENV PATH="/opt/venv/bin:/usr/local/bin:$PATH" \
|
|||||||
HOME=/home/thoth
|
HOME=/home/thoth
|
||||||
|
|
||||||
COPY scripts/verify-line-endings.sh /usr/local/bin/verify-line-endings
|
COPY scripts/verify-line-endings.sh /usr/local/bin/verify-line-endings
|
||||||
COPY docker/core-entrypoint.sh docker/session-migrate.sh docker/ensure-pi-trust.mjs docker/embedding-model-init.sh /app/docker/
|
COPY docker/core-entrypoint.sh docker/workspace-maintenance-entrypoint.sh docker/session-migrate.sh docker/ensure-pi-trust.mjs docker/embedding-model-init.sh /app/docker/
|
||||||
COPY docker/smoke/core-smoke.sh /app/docker/smoke/core-smoke.sh
|
COPY docker/smoke/core-smoke.sh /app/docker/smoke/core-smoke.sh
|
||||||
RUN /usr/local/bin/verify-line-endings /app/docker \
|
RUN /usr/local/bin/verify-line-endings /app/docker \
|
||||||
&& chmod +x /app/docker/core-entrypoint.sh /app/docker/session-migrate.sh /app/docker/embedding-model-init.sh /app/docker/smoke/core-smoke.sh
|
&& chmod +x /app/docker/core-entrypoint.sh /app/docker/workspace-maintenance-entrypoint.sh /app/docker/session-migrate.sh /app/docker/embedding-model-init.sh /app/docker/smoke/core-smoke.sh
|
||||||
|
|
||||||
WORKDIR /app/backend
|
WORKDIR /app/backend
|
||||||
USER thoth
|
USER thoth
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
exec node /app/backend/dist/workspace-maintenance.js "$@"
|
||||||
@@ -3,7 +3,10 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
echo "usage: $0 --bindings-env <workspace-bindings.env> --operator-env <operator.env> --output <override.yaml>" >&2
|
cat >&2 <<'EOF'
|
||||||
|
usage: $0 --bindings-env <workspace-bindings.env> --operator-env <operator.env> --output <override.yaml> \
|
||||||
|
[--service <core|workspace-maintenance>]... [--role <all|dwh|evidence>]...
|
||||||
|
EOF
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,20 +43,59 @@ read_env_value() {
|
|||||||
printf '%s' "$result"
|
printf '%s' "$result"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding_matches_roles() {
|
||||||
|
local name="$1" role
|
||||||
|
for role in "${roles[@]}"; do
|
||||||
|
case "$role" in
|
||||||
|
all) return 0 ;;
|
||||||
|
dwh)
|
||||||
|
[[ "$name" == *"_DWH_"* ]] && return 0
|
||||||
|
;;
|
||||||
|
evidence)
|
||||||
|
[[ "$name" == *"_EVIDENCE_"* ]] && return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "unsupported role filter: $role" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
bindings_env=""
|
bindings_env=""
|
||||||
operator_env=""
|
operator_env=""
|
||||||
output=""
|
output=""
|
||||||
|
services=()
|
||||||
|
roles=()
|
||||||
while (($#)); do
|
while (($#)); do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--bindings-env) bindings_env="${2:-}"; shift 2 ;;
|
--bindings-env) bindings_env="${2:-}"; shift 2 ;;
|
||||||
--operator-env) operator_env="${2:-}"; shift 2 ;;
|
--operator-env) operator_env="${2:-}"; shift 2 ;;
|
||||||
--output) output="${2:-}"; shift 2 ;;
|
--output) output="${2:-}"; shift 2 ;;
|
||||||
|
--service) services+=("${2:-}"); shift 2 ;;
|
||||||
|
--role)
|
||||||
|
roles+=("$(printf '%s' "${2:-}" | tr '[:upper:]' '[:lower:]')")
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
*) usage ;;
|
*) usage ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
[[ -f "$bindings_env" && -f "$operator_env" && -n "$output" ]] || usage
|
[[ -f "$bindings_env" && -f "$operator_env" && -n "$output" ]] || usage
|
||||||
[[ ! -e "$output" ]] || { echo "refusing to overwrite connector override: $output" >&2; exit 2; }
|
[[ ! -e "$output" ]] || { echo "refusing to overwrite connector override: $output" >&2; exit 2; }
|
||||||
|
((${#services[@]})) || services=(core)
|
||||||
|
((${#roles[@]})) || roles=(all)
|
||||||
|
|
||||||
|
for service in "${services[@]}"; do
|
||||||
|
case "$service" in
|
||||||
|
core|workspace-maintenance) ;;
|
||||||
|
*)
|
||||||
|
echo "unsupported service target: $service" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
names=()
|
names=()
|
||||||
targets=()
|
targets=()
|
||||||
@@ -64,6 +106,7 @@ while IFS=$'\t' read -r name target; do
|
|||||||
echo "retired semantic secret binding is not supported: ${name%_FILE}_SOURCE" >&2
|
echo "retired semantic secret binding is not supported: ${name%_FILE}_SOURCE" >&2
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
binding_matches_roles "$name" || continue
|
||||||
[[ "$target" =~ ^/run/secrets/[A-Za-z0-9][A-Za-z0-9_.-]*$ && "$target" != *..* ]] || {
|
[[ "$target" =~ ^/run/secrets/[A-Za-z0-9][A-Za-z0-9_.-]*$ && "$target" != *..* ]] || {
|
||||||
echo "invalid connector secret target for $name: $target" >&2
|
echo "invalid connector secret target for $name: $target" >&2
|
||||||
exit 2
|
exit 2
|
||||||
@@ -101,13 +144,17 @@ done < <(
|
|||||||
' "$bindings_env"
|
' "$bindings_env"
|
||||||
)
|
)
|
||||||
|
|
||||||
((${#names[@]})) || { echo "no THT_WS_*_FILE connector bindings found in $bindings_env" >&2; exit 2; }
|
((${#names[@]})) || {
|
||||||
|
echo "no THT_WS_*_FILE connector bindings matched the selected roles in $bindings_env" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
printf '%s\n' '# Generated by scripts/generate-connector-secrets-override.sh; keep this file untracked.'
|
printf '%s\n' '# Generated by scripts/generate-connector-secrets-override.sh; keep this file untracked.'
|
||||||
|
printf '%s\n' 'services:'
|
||||||
|
for service in "${services[@]}"; do
|
||||||
|
printf ' %s:\n' "$service"
|
||||||
printf '%s\n' \
|
printf '%s\n' \
|
||||||
'services:' \
|
|
||||||
' core:' \
|
|
||||||
' env_file:' \
|
' env_file:' \
|
||||||
' - path: ${THT_WORKSPACE_BINDINGS_ENV_FILE:?set THT_WORKSPACE_BINDINGS_ENV_FILE}' \
|
' - path: ${THT_WORKSPACE_BINDINGS_ENV_FILE:?set THT_WORKSPACE_BINDINGS_ENV_FILE}' \
|
||||||
' required: true' \
|
' required: true' \
|
||||||
@@ -116,6 +163,7 @@ done < <(
|
|||||||
printf ' - source: connector_secret_%d\n' "$((index + 1))"
|
printf ' - source: connector_secret_%d\n' "$((index + 1))"
|
||||||
printf ' target: %s\n' "${targets[index]}"
|
printf ' target: %s\n' "${targets[index]}"
|
||||||
done
|
done
|
||||||
|
done
|
||||||
printf '%s\n' '' 'secrets:'
|
printf '%s\n' '' 'secrets:'
|
||||||
for ((index = 0; index < ${#names[@]}; index += 1)); do
|
for ((index = 0; index < ${#names[@]}; index += 1)); do
|
||||||
printf ' connector_secret_%d:\n' "$((index + 1))"
|
printf ' connector_secret_%d:\n' "$((index + 1))"
|
||||||
@@ -123,4 +171,5 @@ done < <(
|
|||||||
done
|
done
|
||||||
} >"$output"
|
} >"$output"
|
||||||
|
|
||||||
printf 'generated %s connector secret mount(s) at %s\n' "${#names[@]}" "$output"
|
printf 'generated %s connector secret mount(s) for %s at %s\n' \
|
||||||
|
"${#names[@]}" "$(IFS=,; printf '%s' "${services[*]}")" "$output"
|
||||||
|
|||||||
Reference in New Issue
Block a user