Files
EvoBGP/internal/maintenance/safety.go
T
DenozordecandCursor 6510a9ca22 feat(maintenance): add policy executor and config provider
ConfigProvider, PolicyExecutor, DBStatsProvider, scheduler и safety; зависимость robfig/cron/v3.

Co-authored-by: Cursor <[email protected]>
2026-06-12 13:21:32 +07:00

73 lines
1.7 KiB
Go

package maintenance
import (
"fmt"
"regexp"
"strings"
)
const (
DefaultBatchRows = 10000
MaxBatchRows = 100000
DefaultStatementTimeoutSec = 30
)
var (
blockedTableNames = map[string]struct{}{
"schema_migrations": {},
"tenant": {},
"maintenance_policy": {},
"maintenance_policy_config_audit": {},
}
sqlForbidden = regexp.MustCompile(`(?i)(;|--|/\*|\b(drop|truncate|insert|update|alter|create|grant|revoke|copy)\b)`)
)
// ValidateTableName ensures table is a safe identifier and not blocked.
func ValidateTableName(name string) error {
name = strings.TrimSpace(name)
if name == "" || !isSafeIdent(name) {
return fmt.Errorf("maintenance: invalid table name")
}
if _, blocked := blockedTableNames[strings.ToLower(name)]; blocked {
return fmt.Errorf("maintenance: table %q is not allowed", name)
}
return nil
}
// ValidateCondition ensures the WHERE fragment is safe for parameterized cleanup.
func ValidateCondition(condition string) error {
c := strings.TrimSpace(condition)
if c == "" {
return nil
}
if sqlForbidden.MatchString(c) {
return fmt.Errorf("maintenance: unsafe condition")
}
return nil
}
// NormalizeBatchLimit clamps delete batch size.
func NormalizeBatchLimit(maxRows *int) int {
if maxRows == nil || *maxRows <= 0 {
return DefaultBatchRows
}
if *maxRows > MaxBatchRows {
return MaxBatchRows
}
return *maxRows
}
func isSafeIdent(name string) bool {
if name == "" {
return false
}
for _, r := range name {
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '_' {
continue
}
return false
}
return true
}