81 lines
2.7 KiB
Go
81 lines
2.7 KiB
Go
// 织忆 MemoryWeave — 凭证脱敏单元测试
|
||
// 2026-09-10 新增(mc P0 事故):锁死「密钥不得进记忆/图谱/Obsidian 镜像」这个回归。
|
||
package redact
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
// 测试用假密钥(非真实凭证,按各平台形状构造)
|
||
const (
|
||
fakeTailscale = "tskey-auth-kTESTONLY0000000000000000000000000000000000000000000000000" // 61 位
|
||
fakeOpenAI = "sk-TESTONLY000000000000000000000000000" // 48 位
|
||
fakeGithubPAT = "github_pat_11TESTONLY0000000000000000000000000000000000000000000000000000000000000000"
|
||
fakeNvapi = "nvapi-TESTONLY0000000000000000000000000000"
|
||
)
|
||
|
||
func TestRedactSecrets_KnownShapes(t *testing.T) {
|
||
cases := []struct {
|
||
name string
|
||
in string
|
||
}{
|
||
{"tailscale", "配置 tailscale up --authkey " + fakeTailscale + " 完成"},
|
||
{"openai", "OPENAI_API_KEY=" + fakeOpenAI},
|
||
{"github_pat", "GITHUB_PERSONAL_ACCESS_TOKEN: " + fakeGithubPAT},
|
||
{"nvapi", "key=" + fakeNvapi},
|
||
{"aws", "AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE"},
|
||
}
|
||
for _, tc := range cases {
|
||
got := RedactSecrets(tc.in)
|
||
if strings.Contains(got, "<REDACTED-secret>") != true {
|
||
t.Errorf("%s: 未脱敏: %q", tc.name, got)
|
||
}
|
||
}
|
||
// 脱敏后不得再残留任何形状
|
||
for _, tc := range cases {
|
||
if ContainsSecret(RedactSecrets(tc.in)) {
|
||
t.Errorf("%s: 脱敏后仍能匹配到凭证形状", tc.name)
|
||
}
|
||
}
|
||
}
|
||
|
||
// URL / 普通连字符词里的 "sk-" 片段不得误伤(事故里 false positive 的来源)
|
||
func TestRedactSecrets_NoFalsePositiveOnURL(t *testing.T) {
|
||
in := "参考 https://yoheinakajima.com/task-driven-autonomous-agents 与 babybeeagi-task-xxx 的说明"
|
||
if got := RedactSecrets(in); got != in {
|
||
t.Errorf("URL 片段被误脱敏:\n got=%q\nwant=%q", got, in)
|
||
}
|
||
if ContainsSecret(in) {
|
||
t.Error("ContainsSecret 对 URL 片段误报")
|
||
}
|
||
}
|
||
|
||
// 嵌在更长标识符里的假命中不替换(前一位是单词字符)
|
||
func TestRedactSecrets_EmbeddedTokenIgnored(t *testing.T) {
|
||
in := "字段名 xxxkey_sk-TESTONLY0000000000000000000000000001234 不是凭证"
|
||
if got := RedactSecrets(in); got != in {
|
||
t.Errorf("嵌在标识符里的 token 被误脱敏: %q", got)
|
||
}
|
||
}
|
||
|
||
func TestRedactSecrets_IdempotentAndPlainTextUntouched(t *testing.T) {
|
||
plain := "牧尘喜欢结论先行,不要废话科普。"
|
||
if got := RedactSecrets(plain); got != plain {
|
||
t.Errorf("纯文本被改动: %q", got)
|
||
}
|
||
once := RedactSecrets("key=" + fakeOpenAI)
|
||
if twice := RedactSecrets(once); twice != once {
|
||
t.Errorf("脱敏不幂等: %q → %q", once, twice)
|
||
}
|
||
}
|
||
|
||
func TestContainsSecret(t *testing.T) {
|
||
if !ContainsSecret("authkey " + fakeTailscale) {
|
||
t.Error("真实形状应被判为含凭证")
|
||
}
|
||
if ContainsSecret("普通的记忆内容,没有凭证") {
|
||
t.Error("普通内容误报")
|
||
}
|
||
}
|