fix(restrict): redact sensitive param summary before it reaches audit/panel
This commit is contained in:
1 parent
5099c21520
commit
e0793debc3
2 files changed
+49
-2
No files matched your search
@@ -3,6 +3,8 @@ package restrict
|
||||
import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/trace"
|
||||
)
|
||||
|
||||
// SensitiveOp 是 design/11 §4「敏感清单」里的操作类别。它只用于审计与前端
|
||||
@@ -45,7 +47,8 @@ var SensitiveOps = []SensitiveOp{
|
||||
}
|
||||
|
||||
// sensitiveSummaryRunes 截断动作摘要:代审小字与审计只需一眼看出「想干什么」,
|
||||
// 同时限制进入前端/日志的文本块大小(也降低把长参数里的秘密整段搬进日志的机会)。
|
||||
// 同时限制进入前端/日志的文本块大小。它只管**长度** —— 秘密由 summarize 里的
|
||||
// trace.RedactText 负责打码,不靠截断「顺手甩掉」。
|
||||
const sensitiveSummaryRunes = 80
|
||||
|
||||
// SensitiveCall 判定一次工具调用是否属敏感操作(design/11 §4)。
|
||||
@@ -135,8 +138,14 @@ func httpCall(args map[string]any) (SensitiveOp, string, bool) {
|
||||
|
||||
// summarize 拼接「动作 + 目标」摘要并按 sensitiveSummaryRunes 截断(不切开
|
||||
// 多字节字符);目标为空时只返回动作。
|
||||
//
|
||||
// 目标先过 trace.RedactText 打码:这个摘要会进审计与前端小字两个读面,而
|
||||
// terminal 的 command / http 的 url 里常常就带着凭据(`curl -H 'api_key=…'`、
|
||||
// `?token=…`),截断并不能让它们变得安全。RedactText 自身已按同一档(80 rune)
|
||||
// 截断,后面的 clipRunes 保留是为了让长度上限继续由本包的
|
||||
// sensitiveSummaryRunes 掌握 —— 两处同档,叠加不改变结果。
|
||||
func summarize(action, target string) string {
|
||||
target = strings.TrimSpace(target)
|
||||
target = trace.RedactText(strings.TrimSpace(target))
|
||||
if target == "" {
|
||||
return action
|
||||
}
|
||||
|
||||
@@ -77,3 +77,41 @@ func TestSensitiveCall_SummaryIsClipped(t *testing.T) {
|
||||
t.Fatalf("被截断的摘要应以省略号结尾: %q", detail)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSensitiveCall_SummaryIsRedacted 锁定「参数摘要进审计与前端小字之前必须
|
||||
// 打码」:terminal 的 command、http 的 url 里常常就带着凭据,截断不是脱敏。
|
||||
func TestSensitiveCall_SummaryIsRedacted(t *testing.T) {
|
||||
t.Parallel()
|
||||
const secret = "sk-live-9f8e7d6c5b4a3210"
|
||||
cases := []struct {
|
||||
name string
|
||||
args map[string]any
|
||||
start string // 摘要应保留的开头(打码不能把摘要打没)
|
||||
}{
|
||||
{
|
||||
name: "terminal",
|
||||
args: map[string]any{"command": "curl -H 'api_key=" + secret + "' https://x"},
|
||||
start: "terminal ",
|
||||
},
|
||||
{
|
||||
name: "http",
|
||||
args: map[string]any{"method": "POST", "url": "https://x/hook?token=" + secret},
|
||||
start: "http POST ",
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
_, detail, sensitive := SensitiveCall(tc.name, tc.args)
|
||||
if !sensitive {
|
||||
t.Fatalf("%s 应判定为敏感", tc.name)
|
||||
}
|
||||
if strings.Contains(detail, secret) {
|
||||
t.Fatalf("%s 摘要泄露了凭据原文: %q", tc.name, detail)
|
||||
}
|
||||
if !strings.Contains(detail, "[redacted]") {
|
||||
t.Fatalf("%s 摘要应带打码标记: %q", tc.name, detail)
|
||||
}
|
||||
if !strings.HasPrefix(detail, tc.start) {
|
||||
t.Fatalf("%s 摘要应以 %q 开头(动作不能被一起打掉): %q", tc.name, tc.start, detail)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user