diff --git a/apps/api/internal/httpapi/security_events_test.go b/apps/api/internal/httpapi/security_events_test.go index ab0e162..59b913a 100644 --- a/apps/api/internal/httpapi/security_events_test.go +++ b/apps/api/internal/httpapi/security_events_test.go @@ -40,6 +40,18 @@ func TestReceiveSecurityEventUsesPreparedReceiverBeforeFirstActivation(t *testin } } +func TestReceiveSecurityEventReturnsNotFoundWithoutConfiguredReceiver(t *testing.T) { + server := &Server{identityRuntime: identityruntime.NewManager(nil, &preparedReceiverBuilder{})} + request := httptest.NewRequest(http.MethodPost, "/api/v1/security-events/ssf", nil) + response := httptest.NewRecorder() + + server.receiveSecurityEvent(response, request) + + if response.Code != http.StatusNotFound { + t.Fatalf("unconfigured SSF status=%d, want %d", response.Code, http.StatusNotFound) + } +} + func TestSecurityEventWriteAuditFailsClosedBeforeMutation(t *testing.T) { server := &Server{} request := httptest.NewRequest(http.MethodPost, "/api/admin/system/security-events/connection/verify", nil) diff --git a/apps/api/internal/identityruntime/manager.go b/apps/api/internal/identityruntime/manager.go index 9060bad..2460b5d 100644 --- a/apps/api/internal/identityruntime/manager.go +++ b/apps/api/internal/identityruntime/manager.go @@ -105,7 +105,10 @@ func (manager *Manager) SecurityEventReceiver() http.Handler { if runtime := manager.Current(); runtime != nil && runtime.SecurityEvents != nil { return runtime.SecurityEvents } - return manager.SecurityEventManager() + if securityEventManager := manager.SecurityEventManager(); securityEventManager != nil { + return securityEventManager + } + return nil } // SecurityEventManager resolves the manager used by administrative recovery diff --git a/apps/api/internal/identityruntime/manager_test.go b/apps/api/internal/identityruntime/manager_test.go index 6ef7dac..fbd00d6 100644 --- a/apps/api/internal/identityruntime/manager_test.go +++ b/apps/api/internal/identityruntime/manager_test.go @@ -630,6 +630,14 @@ func TestSecurityEventManagerExposesPreparedRecoveryManagerWithoutActiveRuntime( } } +func TestSecurityEventReceiverReturnsNilWithoutConfiguredManager(t *testing.T) { + manager := NewManager(&runtimeRepositoryFake{}, &runtimeBuilderFake{}) + + if manager.SecurityEventReceiver() != nil { + t.Fatal("unconfigured security event receiver should be nil") + } +} + func TestSecurityEventManagerPrefersActiveRuntime(t *testing.T) { active := &securityevents.ConnectionManager{} prepared := &securityevents.ConnectionManager{}