Spaces:
Paused
Paused
| import type { PaperclipConfig } from "../config/schema.js"; | |
| import type { CheckResult } from "./index.js"; | |
| function isLoopbackHost(host: string) { | |
| const normalized = host.trim().toLowerCase(); | |
| return normalized === "127.0.0.1" || normalized === "localhost" || normalized === "::1"; | |
| } | |
| export function deploymentAuthCheck(config: PaperclipConfig): CheckResult { | |
| const mode = config.server.deploymentMode; | |
| const exposure = config.server.exposure; | |
| const auth = config.auth; | |
| if (mode === "local_trusted") { | |
| if (!isLoopbackHost(config.server.host)) { | |
| return { | |
| name: "Deployment/auth mode", | |
| status: "fail", | |
| message: `local_trusted requires loopback host binding (found ${config.server.host})`, | |
| canRepair: false, | |
| repairHint: "Run `paperclipai configure --section server` and set host to 127.0.0.1", | |
| }; | |
| } | |
| return { | |
| name: "Deployment/auth mode", | |
| status: "pass", | |
| message: "local_trusted mode is configured for loopback-only access", | |
| }; | |
| } | |
| const secret = | |
| process.env.BETTER_AUTH_SECRET?.trim() ?? | |
| process.env.PAPERCLIP_AGENT_JWT_SECRET?.trim(); | |
| if (!secret) { | |
| return { | |
| name: "Deployment/auth mode", | |
| status: "fail", | |
| message: "authenticated mode requires BETTER_AUTH_SECRET (or PAPERCLIP_AGENT_JWT_SECRET)", | |
| canRepair: false, | |
| repairHint: "Set BETTER_AUTH_SECRET before starting Paperclip", | |
| }; | |
| } | |
| if (auth.baseUrlMode === "explicit" && !auth.publicBaseUrl) { | |
| return { | |
| name: "Deployment/auth mode", | |
| status: "fail", | |
| message: "auth.baseUrlMode=explicit requires auth.publicBaseUrl", | |
| canRepair: false, | |
| repairHint: "Run `paperclipai configure --section server` and provide a base URL", | |
| }; | |
| } | |
| if (exposure === "public") { | |
| if (auth.baseUrlMode !== "explicit" || !auth.publicBaseUrl) { | |
| return { | |
| name: "Deployment/auth mode", | |
| status: "fail", | |
| message: "authenticated/public requires explicit auth.publicBaseUrl", | |
| canRepair: false, | |
| repairHint: "Run `paperclipai configure --section server` and select public exposure", | |
| }; | |
| } | |
| try { | |
| const url = new URL(auth.publicBaseUrl); | |
| if (url.protocol !== "https:") { | |
| return { | |
| name: "Deployment/auth mode", | |
| status: "warn", | |
| message: "Public exposure should use an https:// auth.publicBaseUrl", | |
| canRepair: false, | |
| repairHint: "Use HTTPS in production for secure session cookies", | |
| }; | |
| } | |
| } catch { | |
| return { | |
| name: "Deployment/auth mode", | |
| status: "fail", | |
| message: "auth.publicBaseUrl is not a valid URL", | |
| canRepair: false, | |
| repairHint: "Run `paperclipai configure --section server` and provide a valid URL", | |
| }; | |
| } | |
| } | |
| return { | |
| name: "Deployment/auth mode", | |
| status: "pass", | |
| message: `Mode ${mode}/${exposure} with auth URL mode ${auth.baseUrlMode}`, | |
| }; | |
| } | |