package comm import ( "os" "testing" "yunyan/lego/sys/log" ) // applyDBValues 在解密失败时会 log.Errorf;lego 的 log 子系统若未初始化会 nil 解引用。 func TestMain(m *testing.M) { _ = log.OnInit(nil) os.Exit(m.Run()) } // 事故回归:FIELD_ENCRYPT_KEY 与 console 不一致时,密钥字段解密失败。 // 此时**绝不能**把密文当明文写进 Sys 配置——历史上密文被当成微信商户私钥的文件路径去 open, // 触发 log.Fatal 让 home 退出,5-in-1 容器整体 crash loop,全站 502。 func TestApplyDBValues_DecryptFailure_DoesNotLeakCiphertext(t *testing.T) { const ciphertext = "HgIdj0m/9aV5CqoKQtj7Gi7yfnaCylNbGYztHF1fVKtwtfIM3UrD5jHP4khP6AI=" // 线上真实密文样本 sec := map[string]interface{}{ "PrivateKeyPath": "/app/certs/apiclient_key.pem", // yaml 默认值 } rows := []*AppModuleConfig{ {Module: "wechatpay", Key: "PrivateKeyPath", Value: ciphertext, Encrypted: true}, } applyDBValues(sec, rows, "wrong-key-not-matching-console") got, _ := sec["PrivateKeyPath"].(string) if got == ciphertext { t.Fatal("解密失败后密文被当明文写进配置——这正是导致全站 502 的 fail-open 行为") } if got != "/app/certs/apiclient_key.pem" { t.Errorf("解密失败应保留 yaml 默认值,实际=%q", got) } } // 解密成功时正常覆盖。 func TestApplyDBValues_DecryptSuccess_Overrides(t *testing.T) { const key = "test-key-consistent-with-console" ct, err := Encrypt(key, "real-secret-value") if err != nil { t.Fatalf("Encrypt err: %v", err) } sec := map[string]interface{}{"ApiKey": "yaml-default"} rows := []*AppModuleConfig{{Module: "sms", Key: "ApiKey", Value: ct, Encrypted: true}} applyDBValues(sec, rows, key) if got, _ := sec["ApiKey"].(string); got != "real-secret-value" { t.Errorf("解密成功应覆盖为明文,实际=%q", got) } } // 非加密字段照常覆盖,且按 yaml 原值类型还原。 func TestApplyDBValues_PlainField(t *testing.T) { sec := map[string]interface{}{"Enabled": false} rows := []*AppModuleConfig{{Module: "sms", Key: "Enabled", Value: "true", Encrypted: false}} applyDBValues(sec, rows, "") if got, _ := sec["Enabled"].(bool); !got { t.Errorf("非加密字段应按原值类型还原为 bool true,实际=%#v", sec["Enabled"]) } }