#!/bin/sh set -eu if [ -r /app/docker/secret-policy.sh ]; then . /app/docker/secret-policy.sh else . "$(CDPATH= cd -- "$(dirname -- "$0")/../deploy/vector" && pwd)/secret-policy.sh" fi if [ -n "${PI_PROVIDER_API_KEY:-}" ]; then echo "PI_PROVIDER_API_KEY is unsupported; configure THT_MODEL_API_KEY_FILE" >&2 exit 2 fi load_secret() { value_name=$1 file_name=$2 secret_file=$(printenv "$file_name" 2>/dev/null || true) if [ -n "$secret_file" ]; then if [ ! -r "$secret_file" ]; then echo "$file_name is not readable: $secret_file" >&2 exit 2 fi secret_value=$(cat "$secret_file") export "$value_name=$secret_value" fi } load_secret THT_DWH_API_KEY THT_DWH_API_KEY_FILE load_secret THT_VEC_API_KEY THT_VEC_API_KEY_FILE load_secret THT_VEC_WRITE_API_KEY THT_VEC_WRITE_API_KEY_FILE secret_tmp_dir= cleanup_secret_tmp() { if [ -n "${secret_tmp_dir:-}" ]; then rm -rf "$secret_tmp_dir"; fi } trap cleanup_secret_tmp EXIT HUP INT TERM run_child() { "$@" & child_pid=$! forward_signal() { kill -TERM "$child_pid" 2>/dev/null || true; } trap forward_signal HUP INT TERM wait "$child_pid" status=$? trap - HUP INT TERM return "$status" } bundle=${THT_SECRETS_FILE:-} if [ -n "$bundle" ]; then if ! validate_bundle "$bundle" >/dev/null 2>&1; then echo "THT_SECRETS_FILE points to an invalid secret bundle" >&2 exit 2 fi # REST adapters consume these values while the harness is running. They are # loaded here (before `tht` starts), not only in the backend/Pi process. load_bundle_env() { env_name=$1 key=$2 if value=$(read_bundle_secret "$bundle" "$key" 2>/dev/null); then export "$env_name=$value" else status=$? [ "$status" -eq 3 ] || { echo "secret bundle contains an invalid $key value" >&2; exit 2; } fi } load_bundle_env THT_DWH_API_KEY THT_DWH_API_KEY load_bundle_env THT_VEC_API_KEY THT_VEC_API_KEY load_bundle_env THT_VEC_WRITE_API_KEY THT_VEC_WRITE_API_KEY load_bundle_env THT_SSL_CA THT_SSL_CA if [ -z "${THT_SSL_CA:-}" ]; then load_bundle_env THT_SSL_CA THT_CA; fi # DatabaseConfig intentionally accepts password_file paths. Materialize # short-lived 0600 files so workspace interpolation never puts a password in # YAML, a URL, or the container's immutable Config.Env. umask 077 secret_tmp_dir=$(mktemp -d "${TMPDIR:-/tmp}/thothii-secrets.XXXXXX") materialize_password() { env_name=$1 key=$2 if value=$(read_bundle_secret "$bundle" "$key" 2>/dev/null); then file="$secret_tmp_dir/$key" printf '%s' "$value" >"$file" export "$env_name=$file" else status=$? [ "$status" -eq 3 ] || { echo "secret bundle contains an invalid $key value" >&2; exit 2; } fi } materialize_password THT_VECTOR_BOOTSTRAP_PASSWORD_FILE THT_VECTOR_BOOTSTRAP_PASSWORD materialize_password THT_VECTOR_MIGRATOR_PASSWORD_FILE THT_VECTOR_MIGRATOR_PASSWORD materialize_password THT_VECTOR_READER_PASSWORD_FILE THT_VECTOR_READER_PASSWORD materialize_password THT_VECTOR_WRITER_PASSWORD_FILE THT_VECTOR_WRITER_PASSWORD fi case "${1:-server}" in server) shift || true run_child node /app/backend/dist/server.js "$@" ;; doctor) shift run_child tht doctor "$@" ;; preprocess) shift run_child tht preprocess "$@" ;; tht) shift run_child tht "$@" ;; *) run_child tht "$@" ;; esac