package permission // 规则应用管道 -- 将权限学习的建议转化为实际生效的 session 规则. // // 升华改进(ELEVATED): 不缓存决策结果,而是将重复决策升级为规则. // 规则比缓存更好:Bash(prefix:npm) 覆盖所有 npm 命令, // 而缓存只记住 "npm install" 这一条. // 更重要的是,规则可以有粒度控制(prefix vs 工具级), // 缓存无法区分同一命令在不同上下文中的安全含义. // 替代方案:命令指纹缓存(hash(tool_name + input) → 决策)-- // 更简单但有安全风险:同一个 rm -rf build/ 在不同 cwd 下含义不同. // // 设计决策(经用户和开发者讨论确认): // - 命令指纹缓存有安全风险:同一个 `rm -rf build/` 在不同 cwd 下含义不同 // - 规则是更高层次的抽象:`Bash(prefix:npm)` 覆盖所有 npm 命令,比缓存单条命令更有用 // - 原始设计故意不做指纹缓存,经过安全考量 import ( "sync" ) // 默认最大 session 规则数. // 防止无限膨胀--100 条 session 规则已经覆盖相当多的操作模式了. const defaultMaxSessionRules = 100 // RuleApplier 将权限学习的建议转化为实际生效的 session 规则. // // 升华改进(ELEVATED): 不缓存决策结果,而是将重复决策升级为规则. // 规则比缓存更好:Bash(prefix:npm) 覆盖所有 npm 命令, // 而缓存只记住 "npm install" 这一条. // 替代方案:命令指纹缓存(hash(tool_name + input) → 决策)-- // 更简单但有安全风险:同一个 rm -rf build/ 在不同 cwd 下含义不同. type RuleApplier struct { engine Checker // 权限引擎(用于 AddRule) learner *LearningTracker // 权限学习追踪器(获取建议) mu sync.Mutex // 已应用的建议(防止重复应用) appliedSuggestions map[string]bool // session 规则计数(限制最大条数防内存膨胀) sessionRuleCount int maxSessionRules int // 默认 100 } // NewRuleApplier 创建规则应用管道. // // maxRules 指定 session 规则的最大条数,传入 0 使用默认值(100 条). func NewRuleApplier(engine Checker, learner *LearningTracker, maxRules int) *RuleApplier { if maxRules <= 0 { maxRules = defaultMaxSessionRules } return &RuleApplier{ engine: engine, learner: learner, maxSessionRules: maxRules, appliedSuggestions: make(map[string]bool), } } // ApplySuggestions 检查学习追踪器的建议,自动应用为 session 规则. // // 返回本次新应用的规则列表.已经应用过的建议会被跳过. // 达到 maxSessionRules 上限后停止应用新规则. func (a *RuleApplier) ApplySuggestions() []Rule { suggestions := a.learner.SuggestPermanentRules() a.mu.Lock() defer a.mu.Unlock() var applied []Rule for _, s := range suggestions { key := s.RuleString if a.appliedSuggestions[key] { continue // 已应用过 } if a.sessionRuleCount >= a.maxSessionRules { break // 达到上限 } rule := ParseRule(s.RuleString, SourceSession, DecisionAllow) a.engine.AddRule(rule) a.appliedSuggestions[key] = true a.sessionRuleCount++ applied = append(applied, rule) } return applied } // ApplyRule 手动应用一条 session 规则. // // 如果规则已经应用过(按序列化字符串去重),则返回 false. // 如果达到 maxSessionRules 上限,也返回 false. func (a *RuleApplier) ApplyRule(rule Rule) bool { rule.Source = SourceSession key := SerializeRule(rule) a.mu.Lock() defer a.mu.Unlock() if a.appliedSuggestions[key] { return false // 已应用过 } if a.sessionRuleCount >= a.maxSessionRules { return false // 达到上限 } a.engine.AddRule(rule) a.appliedSuggestions[key] = true a.sessionRuleCount++ return true } // SessionRuleCount 返回当前 session 规则的数量. func (a *RuleApplier) SessionRuleCount() int { a.mu.Lock() defer a.mu.Unlock() return a.sessionRuleCount } // Reset 清除所有 session 规则的追踪状态. // 注意:已添加到引擎的规则不会被移除(引擎没有 RemoveRule 接口). // 通常在新会话开始时,引擎也会被重新创建,所以这不是问题. func (a *RuleApplier) Reset() { a.mu.Lock() defer a.mu.Unlock() a.appliedSuggestions = make(map[string]bool) a.sessionRuleCount = 0 }