package auth import ( "testing" "github.com/jfraeys/fetch_ml/internal/auth" ) func TestGenerateAPIKey(t *testing.T) { t.Parallel() // Enable parallel execution key1 := auth.GenerateAPIKey() if len(key1) != 64 { // 32 bytes = 64 hex chars t.Errorf("Expected key length 64, got %d", len(key1)) } // Test uniqueness key2 := auth.GenerateAPIKey() if key1 == key2 { t.Error("Generated keys should be unique") } } func TestHashAPIKey(t *testing.T) { t.Parallel() // Enable parallel execution key := "test-key-123" hash := auth.HashAPIKey(key) if len(hash) != 64 { // SHA256 = 64 hex chars t.Errorf("Expected hash length 64, got %d", len(hash)) } // Test consistency hash2 := auth.HashAPIKey(key) if hash != hash2 { t.Error("Hash should be consistent for same key") } // Test different keys produce different hashes hash3 := auth.HashAPIKey("different-key") if hash == hash3 { t.Error("Different keys should produce different hashes") } } func TestValidateAPIKey(t *testing.T) { t.Parallel() // Enable parallel execution config := auth.AuthConfig{ Enabled: true, APIKeys: map[auth.Username]auth.APIKeyEntry{ "admin": { Hash: auth.APIKeyHash(auth.HashAPIKey("admin-key")), Admin: true, }, "data_scientist": { Hash: auth.APIKeyHash(auth.HashAPIKey("ds-key")), Admin: false, }, }, } tests := []struct { name string apiKey string wantErr bool wantUser string wantAdmin bool }{ { name: "valid admin key", apiKey: "admin-key", wantErr: false, wantUser: "admin", wantAdmin: true, }, { name: "valid user key", apiKey: "ds-key", wantErr: false, wantUser: "data_scientist", wantAdmin: false, }, { name: "invalid key", apiKey: "wrong-key", wantErr: true, }, { name: "empty key", apiKey: "", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { user, err := config.ValidateAPIKey(tt.apiKey) if tt.wantErr { if err == nil { t.Error("Expected error but got none") } return } if err != nil { t.Errorf("Unexpected error: %v", err) return } if user.Name != tt.wantUser { t.Errorf("Expected user %s, got %s", tt.wantUser, user.Name) } if user.Admin != tt.wantAdmin { t.Errorf("Expected admin %v, got %v", tt.wantAdmin, user.Admin) } }) } } func TestValidateAPIKeyAuthDisabled(t *testing.T) { t.Setenv("FETCH_ML_ALLOW_INSECURE_AUTH", "1") defer t.Setenv("FETCH_ML_ALLOW_INSECURE_AUTH", "") config := auth.AuthConfig{ Enabled: false, APIKeys: map[auth.Username]auth.APIKeyEntry{}, // Empty } user, err := config.ValidateAPIKey("any-key") if err != nil { t.Errorf("Unexpected error when auth disabled: %v", err) } if user == nil { t.Fatal("Expected user, got nil") } if user.Name != "default" { t.Errorf("Expected default user, got %s", user.Name) } if !user.Admin { t.Error("Default user should be admin") } } func TestAdminDetection(t *testing.T) { t.Parallel() // Enable parallel execution config := auth.AuthConfig{ Enabled: true, APIKeys: map[auth.Username]auth.APIKeyEntry{ "admin": {Hash: auth.APIKeyHash(auth.HashAPIKey("key1")), Admin: true}, "admin_user": {Hash: auth.APIKeyHash(auth.HashAPIKey("key2")), Admin: true}, "superadmin": {Hash: auth.APIKeyHash(auth.HashAPIKey("key3")), Admin: true}, "regular": {Hash: auth.APIKeyHash(auth.HashAPIKey("key4")), Admin: false}, "user_admin": {Hash: auth.APIKeyHash(auth.HashAPIKey("key5")), Admin: false}, }, } tests := []struct { apiKey string expected bool }{ {"key1", true}, // admin {"key2", true}, // admin_user {"key3", true}, // superadmin {"key4", false}, // regular {"key5", false}, // user_admin (not admin based on explicit flag) } for _, tt := range tests { t.Run(tt.apiKey, func(t *testing.T) { user, err := config.ValidateAPIKey(tt.apiKey) if err != nil { t.Fatalf("Unexpected error: %v", err) } if user.Admin != tt.expected { t.Errorf("Expected admin=%v for key %s, got %v", tt.expected, tt.apiKey, user.Admin) } }) } }