fix(deploy): close container final review

This commit is contained in:
2026-07-12 00:44:39 +02:00
parent 0ca6346f75
commit a3a266fd81
30 changed files with 526 additions and 37 deletions
+6 -1
View File
@@ -42,7 +42,12 @@ export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstanc
const listModels = deps?.listModels ?? createPiModelLister(config);
const getSettings = deps?.getSettings ?? (() => effectiveSettings(config, loadSettings(config)));
app.addHook("preHandler", authPreHandler(config.authMode));
const authenticate = authPreHandler(config.authMode);
app.addHook("preHandler", async (req, reply) => {
// Process readiness is intentionally unauthenticated for local container/proxy probes.
if (req.url === "/health") return;
return authenticate(req, reply);
});
app.get("/health", async () => ({ status: "ok" }));
sessionRoutes(app, {
mgr, tht: tht as ThtRunner, hub, getSettings,
+6 -3
View File
@@ -1,6 +1,6 @@
import type { FastifyRequest, FastifyReply } from "fastify";
export function authPreHandler(mode: "none" | "mock" | "oidc") {
export function authPreHandler(mode: "none" | "mock" | "upstream") {
return async (req: FastifyRequest, reply: FastifyReply) => {
if (mode === "none") {
(req as any).user = { id: "dev@local" };
@@ -9,8 +9,11 @@ export function authPreHandler(mode: "none" | "mock" | "oidc") {
id: (req.headers["x-mock-user"] as string) ?? "mock",
};
} else {
reply.code(501);
throw new Error("OIDC non configurato (MVP: usa none/mock)");
const id = req.headers["x-authenticated-user"];
if (typeof id !== "string" || id.trim() === "") {
return reply.code(401).send({ error: "authenticated upstream identity required" });
}
(req as any).user = { id };
}
};
}
+9 -2
View File
@@ -1,6 +1,6 @@
export interface AppConfig {
host: string; port: number; harnessDir: string; thtBin: string; piBin: string;
authMode: "none" | "mock" | "oidc";
authMode: "none" | "mock" | "upstream";
defaults: { provider?: string; model?: string; thinking?: string };
maxPiProcesses: number;
settingsFile: string;
@@ -8,13 +8,20 @@ export interface AppConfig {
ollamaEnsureTimeoutMs: number;
}
export function loadConfig(env: Record<string, string | undefined>): AppConfig {
const authMode = env.AUTH_MODE ?? "none";
if (!(["none", "mock", "upstream"] as const).includes(authMode as AppConfig["authMode"])) {
throw new Error(`unsupported AUTH_MODE=${authMode}; use none, mock, or upstream`);
}
if (env.THOTH_PUBLIC_EXPOSURE === "true" && authMode !== "upstream") {
throw new Error("public exposure requires AUTH_MODE=upstream behind a trusted proxy");
}
return {
host: env.HOST ?? "127.0.0.1",
port: Number(env.PORT ?? 8787),
harnessDir: env.THT_HARNESS_DIR ?? "../harness",
thtBin: env.THT_BIN ?? "tht",
piBin: env.PI_BIN ?? "pi",
authMode: (env.AUTH_MODE as AppConfig["authMode"]) ?? "none",
authMode: authMode as AppConfig["authMode"],
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",