返回 DeepSeek-Reasonix
permission_rule_save.go
根目录 / desktop / permission_rule_save.go
1 package main
2
3 import (
4 "fmt"
5 "strings"
6
7 "reasonix/internal/permission"
8 "reasonix/internal/plugin"
9 "reasonix/internal/tool"
10 )
11
12 func validateSavedPermissionRule(list, raw string, tools []tool.ContractEntry, servers []string) error {
13 rule, ok := permission.ParseRule(raw)
14 if !ok {
15 return nil // AddPermissionRule reports malformed rules.
16 }
17 for _, candidate := range tools {
18 if permission.RuleMatchesString(rule.Tool, candidate.Name, "") {
19 return nil
20 }
21 }
22 for _, server := range servers {
23 prefix := plugin.ToolPrefix(server)
24 suffix := strings.TrimPrefix(rule.Tool, prefix)
25 if (suffix != rule.Tool && validConfiguredMCPToolSuffix(suffix)) || rule.Tool == plugin.MCPConnectPermissionName(server) {
26 return nil
27 }
28 }
29 if strings.HasPrefix(rule.Tool, "mcp__") && strings.ContainsAny(rule.Tool, "*?") {
30 return fmt.Errorf("permission rule %q uses an MCP tool-name wildcard; MCP permission rules require an exact tool name", raw)
31 }
32 if rule.Subject == "" && !strings.ContainsAny(rule.Tool, "()") {
33 // Allow uses an exact reusable command; ask/deny use a command prefix
34 // so arguments to the same command remain covered.
35 if strings.EqualFold(strings.TrimSpace(list), "allow") {
36 return fmt.Errorf("permission rule %q names no registered tool; if this is a shell command, use Bash(%s)", raw, rule.Tool)
37 }
38 return fmt.Errorf("permission rule %q names no registered tool; if this is a shell command, use Bash(%s:*)", raw, rule.Tool)
39 }
40 return fmt.Errorf("permission rule %q names no registered tool", raw)
41 }
42
43 func validConfiguredMCPToolSuffix(suffix string) bool {
44 if suffix == "" {
45 return false
46 }
47 for _, c := range suffix {
48 if !('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_' || c == '-') {
49 return false
50 }
51 }
52 return true
53 }
54
54 lines GO