docs(deploy): document user-owned session cutover

This commit is contained in:
User
2026-07-16 19:02:58 +02:00
parent c6a74c9ccb
commit cadc4c6947
12 changed files with 441 additions and 2 deletions
+43
View File
@@ -3,6 +3,11 @@ import path from "node:path";
export interface AppConfig {
host: string; port: number; harnessDir: string; thtBin: string; piBin: string;
authMode: "none" | "mock" | "upstream";
sessionStorage: {
mode: "local" | "postgres";
host?: string; port?: number; database?: string; runtimeUser?: string;
runtimePasswordFile?: string; sslmode?: "verify-ca" | "verify-full"; sslrootcert?: string;
};
defaults: { provider?: string; model?: string; thinking?: string };
maxPiProcesses: number;
settingsFile: string;
@@ -20,6 +25,43 @@ export function loadConfig(env: Record<string, string | undefined>): AppConfig {
if (env.THOTH_PUBLIC_EXPOSURE === "true" && authMode !== "upstream") {
throw new Error("public exposure requires AUTH_MODE=upstream behind a trusted proxy");
}
const sessionStorageMode = env.THT_SESSION_STORAGE ?? "local";
if (sessionStorageMode !== "local" && sessionStorageMode !== "postgres") {
throw new Error("session storage configuration is invalid");
}
if (sessionStorageMode === "local" && env.THOTH_PUBLIC_EXPOSURE === "true") {
throw new Error("local session storage requires loopback-only deployment");
}
const sessionStorage: AppConfig["sessionStorage"] = { mode: sessionStorageMode };
if (sessionStorageMode === "postgres") {
const host = env.THT_SESSION_DB_HOST;
const database = env.THT_SESSION_DB_NAME;
const runtimeUser = env.THT_SESSION_RUNTIME_USER;
const runtimePasswordFile = env.THT_SESSION_RUNTIME_PASSWORD_FILE;
const sslmode = env.THT_SESSION_DB_SSLMODE;
const sslrootcert = env.THT_SESSION_DB_SSLROOTCERT;
const port = Number(env.THT_SESSION_DB_PORT ?? 5432);
if (
authMode !== "upstream"
|| !host || !database || !runtimeUser
|| !runtimePasswordFile || !path.isAbsolute(runtimePasswordFile)
|| (sslmode !== "verify-ca" && sslmode !== "verify-full")
|| !sslrootcert || !path.isAbsolute(sslrootcert)
|| !Number.isInteger(port) || port < 1 || port > 65535
) {
if (authMode !== "upstream") {
throw new Error("server session storage requires AUTH_MODE=upstream");
}
throw new Error("server session storage configuration is invalid");
}
sessionStorage.host = host;
sessionStorage.port = port;
sessionStorage.database = database;
sessionStorage.runtimeUser = runtimeUser;
sessionStorage.runtimePasswordFile = runtimePasswordFile;
sessionStorage.sslmode = sslmode;
sessionStorage.sslrootcert = sslrootcert;
}
const modelApiKeyFile = env.THT_MODEL_API_KEY_FILE;
if (modelApiKeyFile !== undefined && (
modelApiKeyFile.trim() !== modelApiKeyFile
@@ -48,6 +90,7 @@ export function loadConfig(env: Record<string, string | undefined>): AppConfig {
thtBin: env.THT_BIN ?? "tht",
piBin: env.PI_BIN ?? "pi",
authMode: authMode as AppConfig["authMode"],
sessionStorage,
defaults: { provider: env.PI_PROVIDER, model: env.PI_MODEL, thinking: env.PI_THINKING },
maxPiProcesses: Number(env.MAX_PI_PROCESSES ?? 4),
settingsFile: env.SETTINGS_FILE ?? "data/settings.json",