fix: validate log matching rules before save

This commit is contained in:
zxr
2026-07-18 08:51:49 +08:00
parent 7efe430b9c
commit 601bfc58aa
2 changed files with 86 additions and 0 deletions

View File

@@ -35,6 +35,10 @@ func CreateSyslogRule(ctx *gin.Context) {
infra.Response.Error(ctx, err) infra.Response.Error(ctx, err)
return return
} }
if err := validateSyslogRule(&row); err != nil {
infra.Response.Error(ctx, err)
return
}
row.ID = 0 row.ID = 0
if err := impl.DBService.Create(&row).Error; err != nil { if err := impl.DBService.Create(&row).Error; err != nil {
infra.Response.Error(ctx, err) infra.Response.Error(ctx, err)
@@ -60,6 +64,10 @@ func UpdateSyslogRule(ctx *gin.Context) {
return return
} }
row.ID = id row.ID = id
if err := validateSyslogRule(&row); err != nil {
infra.Response.Error(ctx, err)
return
}
if err := impl.DBService.Save(&row).Error; err != nil { if err := impl.DBService.Save(&row).Error; err != nil {
infra.Response.Error(ctx, err) infra.Response.Error(ctx, err)
return return
@@ -98,6 +106,10 @@ func CreateTrapRule(ctx *gin.Context) {
infra.Response.Error(ctx, err) infra.Response.Error(ctx, err)
return return
} }
if err := validateTrapRule(&row); err != nil {
infra.Response.Error(ctx, err)
return
}
row.ID = 0 row.ID = 0
if err := impl.DBService.Create(&row).Error; err != nil { if err := impl.DBService.Create(&row).Error; err != nil {
infra.Response.Error(ctx, err) infra.Response.Error(ctx, err)
@@ -123,6 +135,10 @@ func UpdateTrapRule(ctx *gin.Context) {
return return
} }
row.ID = id row.ID = id
if err := validateTrapRule(&row); err != nil {
infra.Response.Error(ctx, err)
return
}
if err := impl.DBService.Save(&row).Error; err != nil { if err := impl.DBService.Save(&row).Error; err != nil {
infra.Response.Error(ctx, err) infra.Response.Error(ctx, err)
return return

View File

@@ -0,0 +1,70 @@
package controllers
import (
"encoding/json"
"fmt"
"regexp"
"strings"
"git.apinb.com/ops/logs/internal/models"
)
func validateSyslogRule(rule *models.SyslogRule) error {
regexFields := []struct {
name string
pattern string
}{
{name: "keyword_regex", pattern: rule.KeywordRegex},
{name: "message_regex", pattern: rule.MessageRegex},
{name: "resource_uid_extract_regex", pattern: rule.ResourceUIDExtractRegex},
}
for _, field := range regexFields {
if err := validateOptionalRegex(field.name, field.pattern); err != nil {
return err
}
}
if raw := strings.TrimSpace(rule.SeverityMappingJSON); raw != "" {
var mapping map[string]string
if err := json.Unmarshal([]byte(raw), &mapping); err != nil {
return fmt.Errorf("severity_mapping_json 必须是字符串到字符串的 JSON 对象:%v请修正 severity_mapping_json 后重试", err)
}
if mapping == nil {
return fmt.Errorf("severity_mapping_json 必须是字符串到字符串的 JSON 对象,不能是 null请改为 JSON 对象后重试")
}
for pattern := range mapping {
if _, err := regexp.Compile(pattern); err != nil {
return fmt.Errorf("severity_mapping_json 的映射键 %q 不是有效正则表达式:%v请修正该映射键后重试", pattern, err)
}
}
}
if strings.TrimSpace(rule.DeviceNameContains) == "" &&
strings.TrimSpace(rule.SourceMatch) == "" &&
strings.TrimSpace(rule.KeywordRegex) == "" &&
strings.TrimSpace(rule.MessageRegex) == "" {
return fmt.Errorf("Syslog 规则的匹配条件全部为空,运行时永远不会命中;请至少填写 device_name_contains、source_match、keyword_regex、message_regex 中的一项")
}
return nil
}
func validateTrapRule(rule *models.TrapRule) error {
if err := validateOptionalRegex("varbind_match_regex", rule.VarbindMatchRegex); err != nil {
return err
}
if strings.TrimSpace(rule.OIDPrefix) == "" && strings.TrimSpace(rule.VarbindMatchRegex) == "" {
return fmt.Errorf("Trap 规则的匹配条件全部为空,运行时永远不会命中;请至少填写 oid_prefix、varbind_match_regex 中的一项")
}
return nil
}
func validateOptionalRegex(field, pattern string) error {
pattern = strings.TrimSpace(pattern)
if pattern == "" {
return nil
}
if _, err := regexp.Compile(pattern); err != nil {
return fmt.Errorf("%s 不是有效正则表达式:%v请修正 %s 后重试", field, err, field)
}
return nil
}