Files
HomeAgent/internal/config/backup_diag_test.go
JianFeeeee 4e70b8d5d8 refactor(module): 核心仓 Go module 路径改为 github.com/JianFeeeee/HologramAgent
批 1,不含 SDK 仓与目录改名。

- go.mod 第 1 行 module 路径
- 366 个 .go 文件的完整前缀 github.com/JianFeeeee/HomeAgent 机械替换
  (857 处,仅完整前缀;展示名/注释里的 HomeAgent 字样留给批 5)
- 未改:third_party 目录名、SDK 自身 go.mod module、go.mod replace 目标、
  homed/waiter 可执行名、.hmap 后缀
2026-10-21 12:17:19 +08:00

94 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package config
import (
"path/filepath"
"testing"
"github.com/JianFeeeee/HologramAgent/internal/security"
)
// ★★ E-2:备份来自**另一台机器**(密钥不同)时,审计必须报出“不可解”,
// 而不是静默当明文/空值,也不是等到某个功能坏了才发现。
//
// 这是备份恢复场景的核心判据:db 能打开、表能读、但密文解不开 ——
// 那种状态最容易被误判成“配置丢了”。
func TestAuditSecretsDetectsForeignKeyBackup(t *testing.T) {
// 本包的 codec 是**进程级全局**,测试必须还原现场,
// 否则会把密钥泄漏给同包其它判据(实测:导致 GetInt 读到密文)。
t.Cleanup(security.ClearConfigCodec)
dir := t.TempDir()
keyA := []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
keyB := []byte("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
// 机器 A:写入一条加密配置
security.ClearConfigCodec()
if _, err := security.InitConfigCodec(keyA); err != nil {
t.Fatal(err)
}
regA := NewConfigRegistry(filepath.Join(dir, "config.db"))
regA.RegisterDef(cfgDef("core.llm.api_key"))
if err := regA.Set("core.llm.api_key", "sk-machine-a"); err != nil {
t.Fatal(err)
}
ok, bad, err := regA.AuditSecrets()
if err != nil || ok != 1 || bad != 0 {
t.Fatalf("machine A 自审应为 ok=1 bad=0,实际 ok=%d bad=%d err=%v", ok, bad, err)
}
regA.Close()
// 机器 B:同一份 db,但密钥不同
security.ClearConfigCodec()
if _, err := security.InitConfigCodec(keyB); err != nil {
t.Fatal(err)
}
regB := NewConfigRegistry(filepath.Join(dir, "config.db"))
defer regB.Close()
ok2, bad2, err := regB.AuditSecrets()
if err != nil {
t.Fatal(err)
}
if bad2 == 0 {
t.Fatal("★ 外来密钥的备份未被识别 —— 会被误判为「配置丢了」而非「密钥不匹配」")
}
if ok2 != 0 {
t.Errorf("外来密钥下可解条数应为 0,实际 %d", ok2)
}
// 读取该键必须**响亮报错**,不能把密文当明文交出去
if v, err := regB.Get("core.llm.api_key"); err == nil {
t.Fatalf("★ 密文解不开却返回了值: %v", v)
}
}
// ★ 同一密钥下重启(正常恢复)必须全部可解 —— 不能把正常备份误报成坏。
func TestAuditSecretsCleanOnSameKey(t *testing.T) {
t.Cleanup(security.ClearConfigCodec)
dir := t.TempDir()
key := []byte("cccccccccccccccccccccccccccccccc")
security.ClearConfigCodec()
if _, err := security.InitConfigCodec(key); err != nil {
t.Fatal(err)
}
db := filepath.Join(dir, "config.db")
reg := NewConfigRegistry(db)
reg.RegisterDef(cfgDef("core.llm.api_key"))
if err := reg.Set("core.llm.api_key", "sk-1"); err != nil {
t.Fatal(err)
}
reg.Close()
if _, err := security.InitConfigCodec(key); err != nil {
t.Fatal(err)
}
reg2 := NewConfigRegistry(db)
defer reg2.Close()
ok, bad, err := reg2.AuditSecrets()
if err != nil || bad != 0 || ok != 1 {
t.Fatalf("同密钥重启应为 ok=1 bad=0,实际 ok=%d bad=%d err=%v", ok, bad, err)
}
}
// cfgDef 造一个最小 secret 键定义。
func cfgDef(key string) ConfigDef {
return ConfigDef{Key: key, Type: "string", Secret: true}
}