session.idle_timeout (minutes, default 15) joins the app-config registry and drives the onboarding Garmin session eviction, distinct from session.duration (the login cookie lifetime in hours). The raw Keycloak ID token no longer rides in auth.Claims through every request context: it's minted into the session cookie separately and read back only by the logout handler via IDTokenFromSessionCookie. OnboardingWizard uses the type-imported FormEvent<HTMLFormElement> instead of the React.FormEvent namespace alias. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
86 lines
2.9 KiB
Go
86 lines
2.9 KiB
Go
package config
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestLoadApp(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
overrides map[string]string
|
|
want time.Duration
|
|
wantIdle time.Duration
|
|
wantErr string
|
|
}{
|
|
{name: "defaults when no overrides", overrides: nil, want: 720 * time.Hour, wantIdle: 15 * time.Minute},
|
|
{name: "override applied", overrides: map[string]string{"session.duration": "168"}, want: 168 * time.Hour, wantIdle: 15 * time.Minute},
|
|
{name: "idle timeout override applied", overrides: map[string]string{"session.idle_timeout": "30"}, want: 720 * time.Hour, wantIdle: 30 * time.Minute},
|
|
{name: "invalid stored value", overrides: map[string]string{"session.duration": "zero"}, wantErr: "session.duration"},
|
|
{name: "invalid idle timeout", overrides: map[string]string{"session.idle_timeout": "0"}, wantErr: "session.idle_timeout"},
|
|
{name: "unknown stored key", overrides: map[string]string{"bogus.key": "1"}, wantErr: "unknown configuration key"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := LoadApp(tt.overrides)
|
|
if tt.wantErr != "" {
|
|
if err == nil || !strings.Contains(err.Error(), tt.wantErr) {
|
|
t.Fatalf("err = %v, want containing %q", err, tt.wantErr)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("LoadApp: %v", err)
|
|
}
|
|
if got.SessionDuration != tt.want {
|
|
t.Fatalf("SessionDuration = %v, want %v", got.SessionDuration, tt.want)
|
|
}
|
|
if got.SetupSessionIdleTimeout != tt.wantIdle {
|
|
t.Fatalf("SetupSessionIdleTimeout = %v, want %v", got.SetupSessionIdleTimeout, tt.wantIdle)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateAppValue(t *testing.T) {
|
|
if err := ValidateAppValue("session.duration", "24"); err != nil {
|
|
t.Fatalf("valid value rejected: %v", err)
|
|
}
|
|
if err := ValidateAppValue("session.duration", "-1"); err == nil {
|
|
t.Fatal("negative hours accepted")
|
|
}
|
|
if err := ValidateAppValue("session.duration", "1.5"); err == nil {
|
|
t.Fatal("non-integer accepted")
|
|
}
|
|
if err := ValidateAppValue("nope", "1"); err == nil {
|
|
t.Fatal("unknown key accepted")
|
|
}
|
|
}
|
|
|
|
func TestDisplayEnv_MasksSecrets(t *testing.T) {
|
|
cfg := EnvConfig{
|
|
BackendAddr: ":8080", OIDCClientSecret: "hunter2",
|
|
SessionSecret: []byte("0123456789abcdef0123456789abcdef"),
|
|
}
|
|
entries := map[string]string{}
|
|
for _, e := range cfg.DisplayEnv() {
|
|
entries[e.Name] = e.Value
|
|
}
|
|
if entries["GENIUSRUN_BACKEND_ADDR"] != ":8080" {
|
|
t.Errorf("GENIUSRUN_BACKEND_ADDR = %q", entries["GENIUSRUN_BACKEND_ADDR"])
|
|
}
|
|
if entries["GENIUSRUN_OIDC_CLIENT_SECRET"] != "•••• (set)" {
|
|
t.Errorf("client secret not masked: %q", entries["GENIUSRUN_OIDC_CLIENT_SECRET"])
|
|
}
|
|
if entries["GENIUSRUN_SESSION_SECRET"] != "•••• (set)" {
|
|
t.Errorf("session secret not masked: %q", entries["GENIUSRUN_SESSION_SECRET"])
|
|
}
|
|
empty := EnvConfig{}
|
|
for _, e := range empty.DisplayEnv() {
|
|
if e.Name == "GENIUSRUN_OIDC_CLIENT_SECRET" && e.Value != "(unset)" {
|
|
t.Errorf("unset secret = %q, want (unset)", e.Value)
|
|
}
|
|
}
|
|
}
|