mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-04-28 11:30:15 +00:00
Adds TestOIDCEnvVarsWithNilConfig to catch the case where OIDC_* env vars were silently ignored when no oidc.enc file existed. This documents the proper pattern of initializing OIDCConfig before calling MergeFromEnv.
636 lines
17 KiB
Go
636 lines
17 KiB
Go
package config
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestNormaliseList(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
values []string
|
|
want []string
|
|
}{
|
|
{
|
|
name: "empty slice",
|
|
values: []string{},
|
|
want: []string{},
|
|
},
|
|
{
|
|
name: "nil slice",
|
|
values: nil,
|
|
want: []string{},
|
|
},
|
|
{
|
|
name: "single value",
|
|
values: []string{"foo"},
|
|
want: []string{"foo"},
|
|
},
|
|
{
|
|
name: "trims whitespace",
|
|
values: []string{" foo ", " bar "},
|
|
want: []string{"foo", "bar"},
|
|
},
|
|
{
|
|
name: "removes empty strings",
|
|
values: []string{"foo", "", "bar", " "},
|
|
want: []string{"foo", "bar"},
|
|
},
|
|
{
|
|
name: "removes duplicates case insensitive",
|
|
values: []string{"foo", "Foo", "FOO", "bar"},
|
|
want: []string{"foo", "bar"},
|
|
},
|
|
{
|
|
name: "preserves first occurrence",
|
|
values: []string{"Foo", "foo", "bar", "Bar"},
|
|
want: []string{"Foo", "bar"},
|
|
},
|
|
{
|
|
name: "complex example",
|
|
values: []string{" openid ", "profile", "", " email ", "OPENID", "Profile"},
|
|
want: []string{"openid", "profile", "email"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := normaliseList(tt.values)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("normaliseList(%v) = %v, want %v", tt.values, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseDelimited(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
want []string
|
|
}{
|
|
{
|
|
name: "empty string",
|
|
input: "",
|
|
want: nil,
|
|
},
|
|
{
|
|
name: "whitespace only",
|
|
input: " ",
|
|
want: nil,
|
|
},
|
|
{
|
|
name: "comma separated",
|
|
input: "foo,bar,baz",
|
|
want: []string{"foo", "bar", "baz"},
|
|
},
|
|
{
|
|
name: "space separated",
|
|
input: "foo bar baz",
|
|
want: []string{"foo", "bar", "baz"},
|
|
},
|
|
{
|
|
name: "mixed separators",
|
|
input: "foo, bar baz,qux",
|
|
want: []string{"foo", "bar", "baz", "qux"},
|
|
},
|
|
{
|
|
name: "removes duplicates",
|
|
input: "foo,bar,foo,BAR",
|
|
want: []string{"foo", "bar"},
|
|
},
|
|
{
|
|
name: "trims surrounding whitespace",
|
|
input: " foo , bar ",
|
|
want: []string{"foo", "bar"},
|
|
},
|
|
{
|
|
name: "single value",
|
|
input: "foo",
|
|
want: []string{"foo"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := parseDelimited(tt.input)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("parseDelimited(%q) = %v, want %v", tt.input, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDefaultRedirectURL(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
publicURL string
|
|
want string
|
|
}{
|
|
{
|
|
name: "empty string",
|
|
publicURL: "",
|
|
want: "",
|
|
},
|
|
{
|
|
name: "whitespace only",
|
|
publicURL: " ",
|
|
want: "",
|
|
},
|
|
{
|
|
name: "simple URL",
|
|
publicURL: "https://pulse.example.com",
|
|
want: "https://pulse.example.com/api/oidc/callback",
|
|
},
|
|
{
|
|
name: "URL with trailing slash",
|
|
publicURL: "https://pulse.example.com/",
|
|
want: "https://pulse.example.com/api/oidc/callback",
|
|
},
|
|
{
|
|
name: "URL with path",
|
|
publicURL: "https://example.com/pulse",
|
|
want: "https://example.com/pulse/api/oidc/callback",
|
|
},
|
|
{
|
|
name: "URL with path and trailing slash",
|
|
publicURL: "https://example.com/pulse/",
|
|
want: "https://example.com/pulse/api/oidc/callback",
|
|
},
|
|
{
|
|
name: "URL with port",
|
|
publicURL: "https://pulse.example.com:8443",
|
|
want: "https://pulse.example.com:8443/api/oidc/callback",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := DefaultRedirectURL(tt.publicURL)
|
|
if got != tt.want {
|
|
t.Errorf("DefaultRedirectURL(%q) = %q, want %q", tt.publicURL, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOIDCConfigClone(t *testing.T) {
|
|
t.Run("nil config", func(t *testing.T) {
|
|
var cfg *OIDCConfig
|
|
clone := cfg.Clone()
|
|
if clone != nil {
|
|
t.Error("Clone() of nil should return nil")
|
|
}
|
|
})
|
|
|
|
t.Run("deep copy", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
Enabled: true,
|
|
IssuerURL: "https://issuer.example.com",
|
|
ClientID: "client-123",
|
|
ClientSecret: "secret",
|
|
RedirectURL: "https://pulse.example.com/callback",
|
|
Scopes: []string{"openid", "profile"},
|
|
AllowedGroups: []string{"admin", "users"},
|
|
AllowedDomains: []string{"example.com"},
|
|
AllowedEmails: []string{"user@example.com"},
|
|
EnvOverrides: map[string]bool{"enabled": true},
|
|
}
|
|
|
|
clone := cfg.Clone()
|
|
|
|
// Should be equal
|
|
if clone.Enabled != cfg.Enabled {
|
|
t.Error("Enabled should be equal")
|
|
}
|
|
if clone.IssuerURL != cfg.IssuerURL {
|
|
t.Error("IssuerURL should be equal")
|
|
}
|
|
|
|
// Modify clone slices - originals should be unchanged
|
|
clone.Scopes[0] = "modified"
|
|
if cfg.Scopes[0] == "modified" {
|
|
t.Error("Clone should have independent Scopes slice")
|
|
}
|
|
|
|
clone.AllowedGroups[0] = "modified"
|
|
if cfg.AllowedGroups[0] == "modified" {
|
|
t.Error("Clone should have independent AllowedGroups slice")
|
|
}
|
|
|
|
clone.AllowedDomains[0] = "modified.com"
|
|
if cfg.AllowedDomains[0] == "modified.com" {
|
|
t.Error("Clone should have independent AllowedDomains slice")
|
|
}
|
|
|
|
clone.AllowedEmails[0] = "modified@example.com"
|
|
if cfg.AllowedEmails[0] == "modified@example.com" {
|
|
t.Error("Clone should have independent AllowedEmails slice")
|
|
}
|
|
|
|
// Modify clone EnvOverrides - originals should be unchanged
|
|
clone.EnvOverrides["issuerUrl"] = true
|
|
if cfg.EnvOverrides["issuerUrl"] {
|
|
t.Error("Clone should have independent EnvOverrides map")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestOIDCConfigApplyDefaults(t *testing.T) {
|
|
t.Run("nil config", func(t *testing.T) {
|
|
var cfg *OIDCConfig
|
|
cfg.ApplyDefaults("") // Should not panic
|
|
})
|
|
|
|
t.Run("default scopes", func(t *testing.T) {
|
|
cfg := &OIDCConfig{}
|
|
cfg.ApplyDefaults("")
|
|
|
|
expectedScopes := []string{"openid", "profile", "email"}
|
|
if !reflect.DeepEqual(cfg.Scopes, expectedScopes) {
|
|
t.Errorf("Scopes = %v, want %v", cfg.Scopes, expectedScopes)
|
|
}
|
|
})
|
|
|
|
t.Run("preserves custom scopes", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
Scopes: []string{"openid", "custom"},
|
|
}
|
|
cfg.ApplyDefaults("")
|
|
|
|
if len(cfg.Scopes) != 2 || cfg.Scopes[1] != "custom" {
|
|
t.Errorf("Scopes = %v, want [openid custom]", cfg.Scopes)
|
|
}
|
|
})
|
|
|
|
t.Run("default claims", func(t *testing.T) {
|
|
cfg := &OIDCConfig{}
|
|
cfg.ApplyDefaults("")
|
|
|
|
if cfg.UsernameClaim != "preferred_username" {
|
|
t.Errorf("UsernameClaim = %q, want %q", cfg.UsernameClaim, "preferred_username")
|
|
}
|
|
if cfg.EmailClaim != "email" {
|
|
t.Errorf("EmailClaim = %q, want %q", cfg.EmailClaim, "email")
|
|
}
|
|
})
|
|
|
|
t.Run("preserves custom claims", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
UsernameClaim: "sub",
|
|
EmailClaim: "mail",
|
|
}
|
|
cfg.ApplyDefaults("")
|
|
|
|
if cfg.UsernameClaim != "sub" {
|
|
t.Errorf("UsernameClaim = %q, want %q", cfg.UsernameClaim, "sub")
|
|
}
|
|
if cfg.EmailClaim != "mail" {
|
|
t.Errorf("EmailClaim = %q, want %q", cfg.EmailClaim, "mail")
|
|
}
|
|
})
|
|
|
|
t.Run("sets redirect URL from public URL", func(t *testing.T) {
|
|
cfg := &OIDCConfig{}
|
|
cfg.ApplyDefaults("https://pulse.example.com")
|
|
|
|
expected := "https://pulse.example.com/api/oidc/callback"
|
|
if cfg.RedirectURL != expected {
|
|
t.Errorf("RedirectURL = %q, want %q", cfg.RedirectURL, expected)
|
|
}
|
|
})
|
|
|
|
t.Run("preserves explicit redirect URL", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
RedirectURL: "https://custom.example.com/callback",
|
|
}
|
|
cfg.ApplyDefaults("https://pulse.example.com")
|
|
|
|
if cfg.RedirectURL != "https://custom.example.com/callback" {
|
|
t.Errorf("RedirectURL should not be overwritten")
|
|
}
|
|
})
|
|
|
|
t.Run("normalises lists", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
AllowedGroups: []string{"admin", " admin ", "users"},
|
|
AllowedDomains: []string{" example.com "},
|
|
AllowedEmails: []string{"user@example.com", ""},
|
|
}
|
|
cfg.ApplyDefaults("")
|
|
|
|
if len(cfg.AllowedGroups) != 2 {
|
|
t.Errorf("AllowedGroups should be deduplicated, got %v", cfg.AllowedGroups)
|
|
}
|
|
if cfg.AllowedDomains[0] != "example.com" {
|
|
t.Errorf("AllowedDomains should be trimmed, got %v", cfg.AllowedDomains)
|
|
}
|
|
if len(cfg.AllowedEmails) != 1 {
|
|
t.Errorf("AllowedEmails should have empty entries removed, got %v", cfg.AllowedEmails)
|
|
}
|
|
})
|
|
|
|
t.Run("initialises EnvOverrides map", func(t *testing.T) {
|
|
cfg := &OIDCConfig{}
|
|
cfg.ApplyDefaults("")
|
|
|
|
if cfg.EnvOverrides == nil {
|
|
t.Error("EnvOverrides should be initialized")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestOIDCConfigValidate(t *testing.T) {
|
|
t.Run("nil config is valid", func(t *testing.T) {
|
|
var cfg *OIDCConfig
|
|
if err := cfg.Validate(); err != nil {
|
|
t.Errorf("Validate() = %v, want nil", err)
|
|
}
|
|
})
|
|
|
|
t.Run("disabled config is valid", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
Enabled: false,
|
|
}
|
|
if err := cfg.Validate(); err != nil {
|
|
t.Errorf("Validate() = %v, want nil", err)
|
|
}
|
|
})
|
|
|
|
t.Run("enabled requires issuer URL", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
Enabled: true,
|
|
ClientID: "client-123",
|
|
RedirectURL: "https://pulse.example.com/callback",
|
|
Scopes: []string{"openid"},
|
|
}
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Error("Validate() should fail without issuer URL")
|
|
}
|
|
})
|
|
|
|
t.Run("enabled requires valid issuer URL", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
Enabled: true,
|
|
IssuerURL: "not-a-valid-url",
|
|
ClientID: "client-123",
|
|
RedirectURL: "https://pulse.example.com/callback",
|
|
Scopes: []string{"openid"},
|
|
}
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Error("Validate() should fail with invalid issuer URL")
|
|
}
|
|
})
|
|
|
|
t.Run("enabled requires client ID", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
Enabled: true,
|
|
IssuerURL: "https://issuer.example.com",
|
|
RedirectURL: "https://pulse.example.com/callback",
|
|
Scopes: []string{"openid"},
|
|
}
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Error("Validate() should fail without client ID")
|
|
}
|
|
})
|
|
|
|
t.Run("enabled requires redirect URL", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
Enabled: true,
|
|
IssuerURL: "https://issuer.example.com",
|
|
ClientID: "client-123",
|
|
Scopes: []string{"openid"},
|
|
}
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Error("Validate() should fail without redirect URL")
|
|
}
|
|
})
|
|
|
|
t.Run("enabled requires valid redirect URL", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
Enabled: true,
|
|
IssuerURL: "https://issuer.example.com",
|
|
ClientID: "client-123",
|
|
RedirectURL: "not-a-valid-url",
|
|
Scopes: []string{"openid"},
|
|
}
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Error("Validate() should fail with invalid redirect URL")
|
|
}
|
|
})
|
|
|
|
t.Run("enabled requires at least one scope", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
Enabled: true,
|
|
IssuerURL: "https://issuer.example.com",
|
|
ClientID: "client-123",
|
|
RedirectURL: "https://pulse.example.com/callback",
|
|
Scopes: []string{},
|
|
}
|
|
if err := cfg.Validate(); err == nil {
|
|
t.Error("Validate() should fail without scopes")
|
|
}
|
|
})
|
|
|
|
t.Run("valid enabled config", func(t *testing.T) {
|
|
cfg := &OIDCConfig{
|
|
Enabled: true,
|
|
IssuerURL: "https://issuer.example.com",
|
|
ClientID: "client-123",
|
|
RedirectURL: "https://pulse.example.com/callback",
|
|
Scopes: []string{"openid", "profile"},
|
|
}
|
|
if err := cfg.Validate(); err != nil {
|
|
t.Errorf("Validate() = %v, want nil", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestOIDCConfigMergeFromEnv(t *testing.T) {
|
|
t.Run("nil config", func(t *testing.T) {
|
|
var cfg *OIDCConfig
|
|
cfg.MergeFromEnv(map[string]string{"OIDC_ENABLED": "true"}) // Should not panic
|
|
})
|
|
|
|
t.Run("merges all fields", func(t *testing.T) {
|
|
cfg := &OIDCConfig{}
|
|
env := map[string]string{
|
|
"OIDC_ENABLED": "true",
|
|
"OIDC_ISSUER_URL": "https://issuer.example.com",
|
|
"OIDC_CLIENT_ID": "client-123",
|
|
"OIDC_CLIENT_SECRET": "secret",
|
|
"OIDC_REDIRECT_URL": "https://pulse.example.com/callback",
|
|
"OIDC_LOGOUT_URL": "https://issuer.example.com/logout",
|
|
"OIDC_SCOPES": "openid,profile,email",
|
|
"OIDC_USERNAME_CLAIM": "sub",
|
|
"OIDC_EMAIL_CLAIM": "mail",
|
|
"OIDC_GROUPS_CLAIM": "groups",
|
|
"OIDC_ALLOWED_GROUPS": "admin,users",
|
|
"OIDC_ALLOWED_DOMAINS": "example.com,test.com",
|
|
"OIDC_ALLOWED_EMAILS": "user@example.com",
|
|
"OIDC_CA_BUNDLE": "-----BEGIN CERTIFICATE-----",
|
|
}
|
|
|
|
cfg.MergeFromEnv(env)
|
|
|
|
if !cfg.Enabled {
|
|
t.Error("Enabled should be true")
|
|
}
|
|
if cfg.IssuerURL != "https://issuer.example.com" {
|
|
t.Errorf("IssuerURL = %q, want %q", cfg.IssuerURL, "https://issuer.example.com")
|
|
}
|
|
if cfg.ClientID != "client-123" {
|
|
t.Errorf("ClientID = %q, want %q", cfg.ClientID, "client-123")
|
|
}
|
|
if cfg.ClientSecret != "secret" {
|
|
t.Errorf("ClientSecret = %q, want %q", cfg.ClientSecret, "secret")
|
|
}
|
|
if cfg.RedirectURL != "https://pulse.example.com/callback" {
|
|
t.Errorf("RedirectURL = %q", cfg.RedirectURL)
|
|
}
|
|
if cfg.LogoutURL != "https://issuer.example.com/logout" {
|
|
t.Errorf("LogoutURL = %q", cfg.LogoutURL)
|
|
}
|
|
if len(cfg.Scopes) != 3 {
|
|
t.Errorf("Scopes = %v, want 3 elements", cfg.Scopes)
|
|
}
|
|
if cfg.UsernameClaim != "sub" {
|
|
t.Errorf("UsernameClaim = %q, want %q", cfg.UsernameClaim, "sub")
|
|
}
|
|
if cfg.EmailClaim != "mail" {
|
|
t.Errorf("EmailClaim = %q, want %q", cfg.EmailClaim, "mail")
|
|
}
|
|
if cfg.GroupsClaim != "groups" {
|
|
t.Errorf("GroupsClaim = %q, want %q", cfg.GroupsClaim, "groups")
|
|
}
|
|
if len(cfg.AllowedGroups) != 2 {
|
|
t.Errorf("AllowedGroups = %v, want 2 elements", cfg.AllowedGroups)
|
|
}
|
|
if len(cfg.AllowedDomains) != 2 {
|
|
t.Errorf("AllowedDomains = %v, want 2 elements", cfg.AllowedDomains)
|
|
}
|
|
if len(cfg.AllowedEmails) != 1 {
|
|
t.Errorf("AllowedEmails = %v, want 1 element", cfg.AllowedEmails)
|
|
}
|
|
if cfg.CABundle != "-----BEGIN CERTIFICATE-----" {
|
|
t.Errorf("CABundle = %q", cfg.CABundle)
|
|
}
|
|
})
|
|
|
|
t.Run("tracks env overrides", func(t *testing.T) {
|
|
cfg := &OIDCConfig{}
|
|
env := map[string]string{
|
|
"OIDC_ENABLED": "true",
|
|
"OIDC_ISSUER_URL": "https://issuer.example.com",
|
|
}
|
|
|
|
cfg.MergeFromEnv(env)
|
|
|
|
if !cfg.EnvOverrides["enabled"] {
|
|
t.Error("enabled should be marked as env override")
|
|
}
|
|
if !cfg.EnvOverrides["issuerUrl"] {
|
|
t.Error("issuerUrl should be marked as env override")
|
|
}
|
|
if cfg.EnvOverrides["clientId"] {
|
|
t.Error("clientId should not be marked as env override")
|
|
}
|
|
})
|
|
|
|
t.Run("enabled with 1", func(t *testing.T) {
|
|
cfg := &OIDCConfig{}
|
|
cfg.MergeFromEnv(map[string]string{"OIDC_ENABLED": "1"})
|
|
|
|
if !cfg.Enabled {
|
|
t.Error("Enabled should be true for '1'")
|
|
}
|
|
})
|
|
|
|
t.Run("enabled false for other values", func(t *testing.T) {
|
|
cfg := &OIDCConfig{}
|
|
cfg.MergeFromEnv(map[string]string{"OIDC_ENABLED": "false"})
|
|
|
|
if cfg.Enabled {
|
|
t.Error("Enabled should be false for 'false'")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestNewOIDCConfig(t *testing.T) {
|
|
cfg := NewOIDCConfig()
|
|
|
|
if cfg == nil {
|
|
t.Fatal("NewOIDCConfig() returned nil")
|
|
}
|
|
|
|
// Should have default scopes applied
|
|
if len(cfg.Scopes) != 3 {
|
|
t.Errorf("Scopes = %v, want default 3 scopes", cfg.Scopes)
|
|
}
|
|
|
|
// Should have default claims
|
|
if cfg.UsernameClaim != "preferred_username" {
|
|
t.Errorf("UsernameClaim = %q, want %q", cfg.UsernameClaim, "preferred_username")
|
|
}
|
|
if cfg.EmailClaim != "email" {
|
|
t.Errorf("EmailClaim = %q, want %q", cfg.EmailClaim, "email")
|
|
}
|
|
|
|
// Should have initialized EnvOverrides
|
|
if cfg.EnvOverrides == nil {
|
|
t.Error("EnvOverrides should be initialized")
|
|
}
|
|
}
|
|
|
|
// TestOIDCEnvVarsWithNilConfig is a regression test for issue #853.
|
|
// It ensures that when starting with a nil OIDCConfig (no oidc.enc file),
|
|
// setting OIDC_* environment variables properly initializes and configures OIDC.
|
|
// The bug was that MergeFromEnv() on a nil receiver silently returned,
|
|
// so env vars were ignored when no persisted oidc.enc existed.
|
|
func TestOIDCEnvVarsWithNilConfig(t *testing.T) {
|
|
t.Run("nil config must be initialized before MergeFromEnv", func(t *testing.T) {
|
|
// Simulate the bug: calling MergeFromEnv on nil does nothing
|
|
var nilCfg *OIDCConfig
|
|
nilCfg.MergeFromEnv(map[string]string{"OIDC_ENABLED": "true"})
|
|
// nilCfg is still nil - this was the bug
|
|
if nilCfg != nil {
|
|
t.Error("MergeFromEnv on nil receiver should leave it nil (this is expected)")
|
|
}
|
|
})
|
|
|
|
t.Run("proper pattern: initialize before merge", func(t *testing.T) {
|
|
// This is the correct pattern used in config.go after the fix
|
|
var cfg *OIDCConfig
|
|
env := map[string]string{
|
|
"OIDC_ENABLED": "true",
|
|
"OIDC_ISSUER_URL": "https://auth.example.com",
|
|
"OIDC_CLIENT_ID": "my-client",
|
|
}
|
|
|
|
// The fix: initialize if nil before merging
|
|
if len(env) > 0 {
|
|
if cfg == nil {
|
|
cfg = NewOIDCConfig()
|
|
}
|
|
cfg.MergeFromEnv(env)
|
|
}
|
|
|
|
// Verify env vars were applied
|
|
if cfg == nil {
|
|
t.Fatal("cfg should be initialized")
|
|
}
|
|
if !cfg.Enabled {
|
|
t.Error("Enabled should be true from env")
|
|
}
|
|
if cfg.IssuerURL != "https://auth.example.com" {
|
|
t.Errorf("IssuerURL = %q, want %q", cfg.IssuerURL, "https://auth.example.com")
|
|
}
|
|
if cfg.ClientID != "my-client" {
|
|
t.Errorf("ClientID = %q, want %q", cfg.ClientID, "my-client")
|
|
}
|
|
// Should also have defaults from NewOIDCConfig
|
|
if len(cfg.Scopes) != 3 {
|
|
t.Errorf("Scopes should have defaults, got %v", cfg.Scopes)
|
|
}
|
|
})
|
|
}
|