mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-02 15:27:33 +00:00
记忆层: - MemoryBlock 承载 FrameTS/PageSeq/PageKind/BlockRole/CallID - coldcontext 归档与回填按完整页传递,工具调用参数和配对键不丢失 - 召回先估算总 token,超预算时按全局页相似度标记 inactive - inactive 仅是 context 渲染期状态,不落盘、不进入 coldcontext,Prune 后重置 - Peek/确认/Remove 两阶段召回,失败保留冷上下文副本 - stablemem 记录 last_recalled_at,删块连带清理边 命名: - internal/memory/document → internal/memory/coldcontext - Doc/DocEvent/DocHit → ColdDoc/ColdEvent/ColdHit - ContextToColdContext/RecentColdContexts/FindColdContexts - 保留既有 JSON 标签、doc_ 文件前缀与 doc_count 状态键,兼容存量数据 安全治理: - 工具策略门禁、安全配置、事件总线发布者身份与入站脱敏 - 声明式 SecurityAPI 与 QQ owner/guest profile - 日志保留策略与相关 e2e/回归判据 验证:go build ./...、go vet ./...、go test ./...(62 包); 生产副本 e2e:7013 块迁移后 ID/向量/指纹 0 变化、0 缺失。
122 lines
4.1 KiB
Go
122 lines
4.1 KiB
Go
package security
|
||
|
||
// EventPolicy 作为**总线闸门**的实现(events.Guard)。
|
||
//
|
||
// ## 为什么这一层必须存在(用户 2026-10-28 的指正)
|
||
//
|
||
// 「eventbus 上所有事件都要接受安全模块的监控。」
|
||
//
|
||
// 在此之前,EventPolicy 只被 internal/sdk/events.go 调用 —— 而那是**四条**
|
||
// 事件路径中的**一条**。其余三条(s.Publish / s.Subscribe / s.EventBus())
|
||
// 拿的是裸 *events.Bus,策略完全不参与。于是「安全监控」只对合规者生效。
|
||
//
|
||
// 现在闸门挂在总线本体上(见 internal/events/bus.go 的 publishAs/subscribeAs),
|
||
// 本文件把 security 的策略与脱敏接上去。
|
||
//
|
||
// ## 分工(与既有设计一致)
|
||
//
|
||
// internal/security 策略 + 载荷过闸(**本文件**)
|
||
// internal/events 总线:每次发布/订阅都问一遍 Guard
|
||
// internal/sdk 适配:把「谁在调用」翻译成 events.Publisher
|
||
// sdk(公开) 只给接口与事件名
|
||
|
||
import (
|
||
"github.com/JianFeeeee/HologramAgent/internal/events"
|
||
)
|
||
|
||
// eventGuard 把 Runtime 的策略适配成 events.Guard。
|
||
type eventGuard struct {
|
||
rt *Runtime
|
||
}
|
||
|
||
// AsEventGuard 返回总线闸门实现。
|
||
//
|
||
// rt 为 nil 时返回 nil(调用方据此不装闸门)。**不**返回一个
|
||
// "永远放行"的假实现 —— 那会让"安全未装配"看起来像"安全已通过"。
|
||
func AsEventGuard(rt *Runtime) events.Guard {
|
||
if rt == nil {
|
||
return nil
|
||
}
|
||
return &eventGuard{rt: rt}
|
||
}
|
||
|
||
// AllowPublish 判定能否发布。
|
||
//
|
||
// ★ 内核身份(空 Name)一律放行:内核模块发布系统事件不需要授权,
|
||
// 它们本身就是可信执行体。但**载荷脱敏仍然执行**(见 ScrubPayload)——
|
||
// 内核也可能把敏感值拼进事件。
|
||
func (g *eventGuard) AllowPublish(p events.Publisher, eventType events.EventType) (bool, string) {
|
||
if p.IsKernel() {
|
||
return true, ""
|
||
}
|
||
d := g.rt.CheckEventPublish(p.Name, string(eventType))
|
||
return d.Allowed, d.Reason
|
||
}
|
||
|
||
// AllowSubscribe 判定能否订阅。
|
||
func (g *eventGuard) AllowSubscribe(p events.Publisher, eventType events.EventType) (bool, string) {
|
||
if p.IsKernel() {
|
||
return true, ""
|
||
}
|
||
d := g.rt.CheckEventSubscribe(p.Name, string(eventType))
|
||
return d.Allowed, d.Reason
|
||
}
|
||
|
||
// ScrubPayload 对出向载荷逐字段脱敏。
|
||
//
|
||
// ★ 对**所有**发布者生效(含内核):凭据闸门与身份无关。
|
||
// 内核模块把 api_key 拼进事件,和插件拼进去一样危险。
|
||
func (g *eventGuard) ScrubPayload(eventType events.EventType, payload map[string]interface{}) map[string]interface{} {
|
||
if g.rt == nil || payload == nil {
|
||
return payload
|
||
}
|
||
out := make(map[string]interface{}, len(payload))
|
||
for k, v := range payload {
|
||
if s, ok := v.(string); ok && s != "" {
|
||
clean, n := g.rt.PrepareOutbound(Inspection{
|
||
Direction: DirectionOutbound,
|
||
Stage: "event:" + string(eventType),
|
||
}, s)
|
||
if n > 0 {
|
||
out[k] = clean
|
||
continue
|
||
}
|
||
}
|
||
out[k] = v
|
||
}
|
||
return out
|
||
}
|
||
|
||
// ScrubInbound 对**入向**载荷逐字段清洗(投递给订阅者之前)。
|
||
//
|
||
// 与 ScrubPayload 对称,但用的是 Inbound 方向:
|
||
// 外部模块写进载荷的明文凭据在这里被换回别名。
|
||
//
|
||
// 为何必须在总线上做(而不是订阅方的适配层):
|
||
// 总线是**唯一的投递点**,而订阅入口有四五条。在适配层做就只好每条
|
||
// 各自实现一遍(实际就是这么发生的:sdk 侧曾有一份 scrubIn),
|
||
// 漏一条就是漏一条路径。安全模块持有总线 ⇒ 在这里做一次就覆盖全部。
|
||
func (g *eventGuard) ScrubInbound(eventType events.EventType, payload map[string]interface{}) map[string]interface{} {
|
||
if g.rt == nil || payload == nil {
|
||
return payload
|
||
}
|
||
out := make(map[string]interface{}, len(payload))
|
||
for k, v := range payload {
|
||
if s, ok := v.(string); ok && s != "" {
|
||
clean, n := g.rt.ScrubInbound(Inspection{
|
||
Direction: DirectionInbound,
|
||
Stage: "event:" + string(eventType),
|
||
}, s)
|
||
if n > 0 {
|
||
out[k] = clean
|
||
continue
|
||
}
|
||
}
|
||
out[k] = v
|
||
}
|
||
return out
|
||
}
|
||
|
||
// 编译期确认实现了 events.Guard。
|
||
var _ events.Guard = (*eventGuard)(nil)
|