返回 DeepSeek-Reasonix
permission_rule_notice.go
根目录 / internal / boot / permission_rule_notice.go
1 package boot
2
3 import (
4 "fmt"
5 "strings"
6
7 "reasonix/internal/event"
8 "reasonix/internal/permission"
9 )
10
11 // emitUnmatchableRuleNotice warns about permission rules that name a tool
12 // nothing answers to. A deny written as a bare shell command installs cleanly
13 // and never fires, so the author is told rather than left believing the rule
14 // guards them. The notice is a warning, not an error: the rest of the policy
15 // is still valid and startup continues.
16 func emitUnmatchableRuleNotice(sink event.Sink, allow, ask, deny []string) {
17 bad := permission.UnmatchableRules(allow, ask, deny)
18 if len(bad) == 0 || sink == nil {
19 return
20 }
21 var b strings.Builder
22 for i, r := range bad {
23 if i > 0 {
24 b.WriteString("\n")
25 }
26 fmt.Fprintf(&b, "permissions.%s: %q %s; write %s instead", r.List, r.Rule, unmatchableRuleCause(r.Defect), r.Suggestion)
27 }
28 sink.Emit(event.Event{
29 Kind: event.Notice,
30 Level: event.LevelWarn,
31 Text: fmt.Sprintf("%d permission rule(s) match nothing.", len(bad)),
32 Detail: b.String(),
33 })
34 }
35
36 // unmatchableRuleCause names what is wrong with the entry. A rule that only
37 // lacks its closing parenthesis is a typo, not a misunderstanding of the rule
38 // grammar, and saying so keeps the reader from rewriting a rule that was
39 // nearly right.
40 func unmatchableRuleCause(d permission.RuleDefect) string {
41 switch d {
42 case permission.DefectUnclosedSubject:
43 return "opens \"(\" without a closing \")\", so the whole entry is read as a tool name and never matches"
44 default:
45 return "names no tool and never matches"
46 }
47 }
48
48 lines GO