fetch_ml/tests/unit/auth/keychain_test.go
Jeremie Fraeys ea15af1833 Fix multi-user authentication and clean up debug code
- Fix YAML tags in auth config struct (json -> yaml)
- Update CLI configs to use pre-hashed API keys
- Remove double hashing in WebSocket client
- Fix port mapping (9102 -> 9103) in CLI commands
- Update permission keys to use jobs:read, jobs:create, etc.
- Clean up all debug logging from CLI and server
- All user roles now authenticate correctly:
  * Admin: Can queue jobs and see all jobs
  * Researcher: Can queue jobs and see own jobs
  * Analyst: Can see status (read-only access)

Multi-user authentication is now fully functional.
2025-12-06 12:35:32 -05:00

159 lines
3.9 KiB
Go

package auth
import (
"strings"
"testing"
"github.com/jfraeys/fetch_ml/internal/auth"
)
func TestNewKeychainManager(t *testing.T) {
t.Parallel() // Enable parallel execution
km := auth.NewKeychainManager()
if km == nil {
t.Fatal("NewKeychainManager returned nil")
}
// Test that ListAvailableMethods works
methods := km.ListAvailableMethods()
if len(methods) == 0 {
t.Error("Expected at least one available method")
}
}
func TestKeychainIsAvailable(t *testing.T) {
t.Parallel() // Enable parallel execution
km := auth.NewKeychainManager()
// IsAvailable should return a boolean without error
available := km.IsAvailable()
// We can't predict the result since it depends on the test environment,
// but it should not panic
t.Logf("Keychain availability: %v", available)
}
func TestKeychainBasicOperations(t *testing.T) {
t.Parallel() // Enable parallel execution
km := auth.NewKeychainManager()
service := "test-service"
account := "test-account"
secret := "test-secret"
// Test storing API key
if err := km.StoreAPIKey(service, account, secret); err != nil {
t.Fatalf("StoreAPIKey failed: %v", err)
}
// Test retrieving API key
retrieved, err := km.GetAPIKey(service, account)
if err != nil {
t.Fatalf("GetAPIKey failed: %v", err)
}
if retrieved != secret {
t.Errorf("Expected secret %s, got %s", secret, retrieved)
}
// Test deleting API key
if err := km.DeleteAPIKey(service, account); err != nil {
t.Fatalf("DeleteAPIKey failed: %v", err)
}
// Verify deletion - should fail to retrieve
_, err = km.GetAPIKey(service, account)
if err == nil {
t.Error("Expected error when retrieving deleted key")
}
}
func TestKeychainListMethods(t *testing.T) {
t.Parallel() // Enable parallel execution
km := auth.NewKeychainManager()
methods := km.ListAvailableMethods()
if len(methods) == 0 {
t.Error("Expected at least one available method")
}
// Check that fallback method is always included
hasFallback := false
for _, method := range methods {
if method == "OS keyring" {
// OS keyring might be available
continue
}
if len(method) > 0 {
hasFallback = true
break
}
}
if !hasFallback {
t.Error("Expected fallback method to be available")
}
t.Logf("Available methods: %v", methods)
}
func TestKeychainErrorHandling(t *testing.T) {
t.Parallel() // Enable parallel execution
km := auth.NewKeychainManager()
// Test getting non-existent key
_, err := km.GetAPIKey("non-existent", "non-existent")
if err == nil {
t.Error("Expected error when getting non-existent key")
}
// Test deleting non-existent key (should not error)
if err := km.DeleteAPIKey("non-existent", "non-existent"); err != nil {
t.Errorf("DeleteAPIKey should not error for non-existent key: %v", err)
}
}
func TestKeychainMultipleKeys(t *testing.T) {
t.Parallel() // Enable parallel execution
km := auth.NewKeychainManager()
keys := map[string]string{
"service1:account1": "secret1",
"service1:account2": "secret2",
"service2:account1": "secret3",
}
// Store multiple keys
for serviceAccount, secret := range keys {
parts := strings.SplitN(serviceAccount, ":", 2)
service, account := parts[0], parts[1]
if err := km.StoreAPIKey(service, account, secret); err != nil {
t.Fatalf("StoreAPIKey failed for %s: %v", serviceAccount, err)
}
}
// Retrieve and verify all keys
for serviceAccount, expectedSecret := range keys {
parts := strings.SplitN(serviceAccount, ":", 2)
service, account := parts[0], parts[1]
retrieved, err := km.GetAPIKey(service, account)
if err != nil {
t.Fatalf("GetAPIKey failed for %s: %v", serviceAccount, err)
}
if retrieved != expectedSecret {
t.Errorf("Expected secret %s for %s, got %s", expectedSecret, serviceAccount, retrieved)
}
// Clean up each key
if err := km.DeleteAPIKey(service, account); err != nil {
t.Fatalf("DeleteAPIKey failed for %s: %v", serviceAccount, err)
}
}
}