import { useProductionSafetyStore } from "@/stores/productionSafetyStore"; import { assessProductionSql, productionContextForDatabase } from "@/lib/database/productionSafety"; import { ensureReadOnlyWriteAccess } from "@/lib/database/readOnlyWriteAccess"; import type { ConnectionConfig } from "@/types/database"; export interface ProductionSqlExecutionGuardOptions { connection?: ConnectionConfig; database?: string | null; sql: string; source?: string; execute: () => Promise; } export async function executeWithProductionSqlGuard(options: ProductionSqlExecutionGuardOptions): Promise { if (!(await ensureReadOnlyWriteAccess({ connection: options.connection, sql: options.sql, source: options.source }))) { return undefined; } const assessment = assessProductionSql(options.sql, options.connection, options.database); if (assessment.active && assessment.isMutation) { // Centralize production write confirmation so secondary tool surfaces cannot // bypass the same explicit review step used by the SQL editor. const confirmed = await useProductionSafetyStore().requestConfirmation({ sql: options.sql, connectionName: options.connection?.name, database: options.database ?? undefined, productionDatabases: assessment.databases, source: options.source, }); if (!confirmed) return undefined; } return options.execute(); } export interface ProductionContextExecutionGuardOptions { connection?: ConnectionConfig; database?: string | null; /** Review text shown in the production confirmation dialog (SQL or shell preview). */ reviewText: string; source?: string; execute: () => Promise; } /** * Gate non-SQL mutations (Mongo shell commands, structured editors, etc.) using * connection/database production scope rather than SQL risk classification. */ export async function executeWithProductionContextGuard(options: ProductionContextExecutionGuardOptions): Promise { if (!(await ensureReadOnlyWriteAccess({ connection: options.connection, sql: options.reviewText, source: options.source, treatAsMutation: true }))) { return undefined; } const productionContext = productionContextForDatabase(options.connection, options.database); if (productionContext.active) { const confirmed = await useProductionSafetyStore().requestConfirmation({ sql: options.reviewText, connectionName: options.connection?.name, database: options.database ?? undefined, productionDatabases: productionContext.databases, source: options.source, }); if (!confirmed) return undefined; } return options.execute(); }