import { URL } from "node:url"; interface DestructiveGuardOptions { commandName: string; allowedDatabaseNames?: string[]; requireConfirmation?: boolean; } const PROTECTED_DATABASE_NAMES = new Set(["capakraken"]); export function parseDatabaseUrl(rawUrl: string) { const parsed = new URL(rawUrl); const databaseName = parsed.pathname.replace(/^\/+/, ""); return { protocol: parsed.protocol, hostname: parsed.hostname, port: parsed.port, databaseName, username: decodeURIComponent(parsed.username), }; } export function formatTarget(target: ReturnType) { const port = target.port ? `:${target.port}` : ""; return `${target.protocol}//${target.username}@${target.hostname}${port}/${target.databaseName}`; } export function assertDestructiveDbAllowed({ commandName, allowedDatabaseNames = [], requireConfirmation = true, }: DestructiveGuardOptions) { const rawUrl = process.env.DATABASE_URL; if (!rawUrl) { throw new Error(`${commandName} aborted: DATABASE_URL is not configured.`); } const target = parseDatabaseUrl(rawUrl); const allowFlag = process.env.ALLOW_DESTRUCTIVE_DB_TOOLS === "true"; const confirmationDb = process.env.CONFIRM_DESTRUCTIVE_DB_NAME; const allowlisted = allowedDatabaseNames.includes(target.databaseName); if (PROTECTED_DATABASE_NAMES.has(target.databaseName)) { throw new Error( `${commandName} aborted: database '${target.databaseName}' is explicitly protected from destructive tooling. Target=${formatTarget(target)}`, ); } if (!allowlisted) { throw new Error( `${commandName} aborted: database '${target.databaseName}' is not in the destructive-tool allowlist (${allowedDatabaseNames.join(", ") || "none"}). Target=${formatTarget(target)}`, ); } if (!allowFlag) { throw new Error( `${commandName} aborted: set ALLOW_DESTRUCTIVE_DB_TOOLS=true to allow destructive database operations. Target=${formatTarget(target)}`, ); } if (requireConfirmation && confirmationDb !== target.databaseName) { throw new Error( `${commandName} aborted: set CONFIRM_DESTRUCTIVE_DB_NAME=${target.databaseName} to confirm the destructive target. Current value=${confirmationDb ?? ""}`, ); } return target; }