account_mapper_redact_test.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package dto
  2. import (
  3. "encoding/json"
  4. "testing"
  5. "github.com/stretchr/testify/require"
  6. "github.com/Wei-Shaw/sub2api/internal/service"
  7. )
  8. func TestAccountFromServiceShallow_RedactsSensitiveCredentials(t *testing.T) {
  9. src := &service.Account{
  10. ID: 42,
  11. Name: "demo",
  12. Platform: "anthropic",
  13. Type: "oauth",
  14. Credentials: map[string]any{
  15. "access_token": "at-secret",
  16. "refresh_token": "rt-secret",
  17. "id_token": "id-secret",
  18. "api_key": "sk-secret",
  19. "base_url": "https://api.example.com",
  20. "model_mapping": map[string]any{"foo": "bar"},
  21. },
  22. }
  23. got := AccountFromServiceShallow(src)
  24. require.NotNil(t, got)
  25. // 敏感键不在 Credentials 里
  26. require.NotContains(t, got.Credentials, "access_token")
  27. require.NotContains(t, got.Credentials, "refresh_token")
  28. require.NotContains(t, got.Credentials, "id_token")
  29. require.NotContains(t, got.Credentials, "api_key")
  30. // 非敏感键保留
  31. require.Equal(t, "https://api.example.com", got.Credentials["base_url"])
  32. require.Equal(t, map[string]any{"foo": "bar"}, got.Credentials["model_mapping"])
  33. // 状态 map 标记敏感键存在
  34. require.True(t, got.CredentialsStatus["has_access_token"])
  35. require.True(t, got.CredentialsStatus["has_refresh_token"])
  36. require.True(t, got.CredentialsStatus["has_id_token"])
  37. require.True(t, got.CredentialsStatus["has_api_key"])
  38. // JSON 序列化校验:响应体里不会出现敏感子串
  39. raw, err := json.Marshal(got)
  40. require.NoError(t, err)
  41. require.NotContains(t, string(raw), "rt-secret")
  42. require.NotContains(t, string(raw), "at-secret")
  43. require.NotContains(t, string(raw), "sk-secret")
  44. require.NotContains(t, string(raw), "id-secret")
  45. // 状态标识应序列化进 JSON
  46. require.Contains(t, string(raw), "credentials_status")
  47. require.Contains(t, string(raw), "has_refresh_token")
  48. // 原始 service.Account 不应被改动
  49. require.Equal(t, "rt-secret", src.Credentials["refresh_token"])
  50. }
  51. func TestAccountFromServiceShallow_RedactsOllamaCloudManagedExtra(t *testing.T) {
  52. snapshot := map[string]any{
  53. "status": service.OllamaCloudUsageStatusOK,
  54. "last_attempt_at": "2026-07-22T12:00:00Z",
  55. "next_refresh_at": "2026-07-22T13:00:00Z",
  56. "data": map[string]any{"plan": "Pro"},
  57. }
  58. src := &service.Account{
  59. ID: 9, Platform: service.PlatformOpenAI, Type: service.AccountTypeAPIKey,
  60. Credentials: map[string]any{"base_url": "https://ollama.com", "api_key": "secret-key"},
  61. Extra: map[string]any{
  62. service.OllamaCloudUsageSessionExtraKey: "ciphertext-secret",
  63. service.OllamaCloudUsageAutoRefreshExtraKey: true,
  64. service.OllamaCloudUsageSnapshotExtraKey: snapshot,
  65. "ordinary": "kept",
  66. },
  67. }
  68. got := AccountFromServiceShallow(src)
  69. require.NotContains(t, got.Extra, service.OllamaCloudUsageSessionExtraKey)
  70. require.NotContains(t, got.Extra, service.OllamaCloudUsageAutoRefreshExtraKey)
  71. require.NotContains(t, got.Extra, service.OllamaCloudUsageSnapshotExtraKey)
  72. require.Equal(t, "kept", got.Extra["ordinary"])
  73. require.NotNil(t, got.OllamaCloudUsage)
  74. require.True(t, got.OllamaCloudUsage.Configured)
  75. require.True(t, got.OllamaCloudUsage.AutoRefreshEnabled)
  76. require.Equal(t, "Pro", got.OllamaCloudUsage.Snapshot.Data.Plan)
  77. raw, err := json.Marshal(got)
  78. require.NoError(t, err)
  79. require.NotContains(t, string(raw), "ciphertext-secret")
  80. require.NotContains(t, string(raw), "secret-key")
  81. require.Contains(t, src.Extra, service.OllamaCloudUsageSessionExtraKey)
  82. }
  83. func TestAccountFromServiceShallow_NilCredentialsOmitsStatus(t *testing.T) {
  84. src := &service.Account{ID: 1, Name: "n", Platform: "anthropic", Type: "oauth"}
  85. got := AccountFromServiceShallow(src)
  86. require.NotNil(t, got)
  87. require.Nil(t, got.Credentials)
  88. require.Nil(t, got.CredentialsStatus)
  89. }