diff --git a/backend/internal/handler/ticket.go b/backend/internal/handler/ticket.go index a2f9343..41f7f12 100644 --- a/backend/internal/handler/ticket.go +++ b/backend/internal/handler/ticket.go @@ -219,6 +219,16 @@ func CreateTicket(c *gin.Context) { return } + // Reject read-only SQL statements (SELECT/SHOW/DESC/EXPLAIN) + upperSQL := strings.ToUpper(strings.TrimSpace(input.SQLContent)) + readOnlyPrefixes := []string{"SELECT", "SHOW", "DESC", "DESCRIBE", "EXPLAIN"} + for _, prefix := range readOnlyPrefixes { + if strings.HasPrefix(upperSQL, prefix) { + c.JSON(http.StatusBadRequest, gin.H{"detail": "数据变更工单不支持 SELECT/SHOW/DESC 等只读语句,请使用查询数据功能"}) + return + } + } + // Auto-fill workflow_id from instance if not provided if input.WorkflowID == nil || *input.WorkflowID == 0 { var inst model.Instance diff --git a/frontend/src/pages/TicketCreatePage.tsx b/frontend/src/pages/TicketCreatePage.tsx index 9e8487a..0df818b 100644 --- a/frontend/src/pages/TicketCreatePage.tsx +++ b/frontend/src/pages/TicketCreatePage.tsx @@ -180,6 +180,15 @@ export default function TicketCreatePage() { if (!instanceId) { setError('请选择目标实例'); return; } if (!database) { setError('请选择数据库'); return; } + // 前端拦截只读语句 + const upperSQL = sqlContent.trim().toUpperCase(); + const readOnlyPrefixes = ['SELECT', 'SHOW', 'DESC', 'DESCRIBE', 'EXPLAIN']; + if (readOnlyPrefixes.some(p => upperSQL.startsWith(p))) { + setError('数据变更工单不支持 SELECT/SHOW/DESC 等只读语句,请使用查询数据功能'); + setValidated(false); + return; + } + setError(''); setAuditResult(null); setValidating(true); try { const result = await ticketApi.audit({ @@ -212,6 +221,14 @@ export default function TicketCreatePage() { if (!sqlContent.trim()) { setError('请填写 SQL 语句'); return; } if (!reason.trim()) { setError('请填写变更原因'); return; } + // 前端拦截只读语句 + const upperSQL = sqlContent.trim().toUpperCase(); + const readOnlyPrefixes = ['SELECT', 'SHOW', 'DESC', 'DESCRIBE', 'EXPLAIN']; + if (readOnlyPrefixes.some(p => upperSQL.startsWith(p))) { + setError('数据变更工单不支持 SELECT/SHOW/DESC 等只读语句,请使用查询数据功能'); + return; + } + setError(''); setSubmitting(true); try {