feat(safety): add production environment safeguards

This commit is contained in:
wuxiemian authored and GitHub committed 2026-07-12 10:02:27 +08:00
1 parent be66d6f46b
commit 1be66fb115
80 files changed
+4220 -234

No files matched your search

@@ -10,6 +10,7 @@ import { useConnectionStore } from "@/stores/connectionStore";
import { useToast } from "@/composables/useToast";
import type { ConnectionConfig } from "@/types/database";
import * as api from "@/lib/backend/api";
import { executeWithProductionSqlGuard } from "@/lib/database/productionExecutionGuard";
import {
DAMENG_JOB_ENVIRONMENT_SQL,
damengClearJobHistoriesSql,
@@ -169,10 +170,18 @@ async function applyPendingSql() {
applying.value = true;
try {
await ensureConnection();
await api.executeMulti(props.connection.id, executionDatabase.value, pendingSql.value, undefined, undefined, {
maxRows: 1000,
useTransaction: pendingUseTransaction.value,
const result = await executeWithProductionSqlGuard({
connection: props.connection,
database: executionDatabase.value,
sql: pendingSql.value,
source: t("production.sourceAdmin"),
execute: () =>
api.executeMulti(props.connection.id, executionDatabase.value, pendingSql.value, undefined, undefined, {
maxRows: 1000,
useTransaction: pendingUseTransaction.value,
}),
});
if (!result) return;
toast(t("damengJobAdmin.applySuccess"), 2500);
previewDialogOpen.value = false;
await (pendingAfterApply.value?.() ?? Promise.resolve());
@@ -13,6 +13,7 @@ import { useToast } from "@/composables/useToast";
import { useSqlHighlighter } from "@/composables/useSqlHighlighter";
import type { ConnectionConfig } from "@/types/database";
import * as api from "@/lib/backend/api";
import { executeWithProductionSqlGuard } from "@/lib/database/productionExecutionGuard";
import { grantsFromQueryResult, getDatabaseUserAdminProvider, supportsDatabaseUserAdmin, type DatabaseUserIdentity, type PrivilegeScope } from "@/lib/database/databaseUserAdmin";
const props = defineProps<{
@@ -165,7 +166,14 @@ async function applyPendingSql() {
if (!pendingSql.value.trim()) return;
applying.value = true;
try {
await api.executeMulti(props.connection.id, "", pendingSql.value, undefined, undefined, { maxRows: 1000 });
const result = await executeWithProductionSqlGuard({
connection: props.connection,
database: "",
sql: pendingSql.value,
source: t("production.sourceAdmin"),
execute: () => api.executeMulti(props.connection.id, "", pendingSql.value, undefined, undefined, { maxRows: 1000 }),
});
if (!result) return;
toast(t("userAdmin.applySuccess"), 2500);
sqlDialogOpen.value = false;
await (pendingAfterApply.value?.() ?? Promise.resolve());