From 5432760cf7142f7b4048058a202ff280f8489b87 Mon Sep 17 00:00:00 2001 From: easyai Date: Wed, 22 Jul 2026 08:48:36 +0800 Subject: [PATCH] =?UTF-8?q?fix(identity):=20=E9=81=BF=E5=85=8D=E6=9C=AA?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=20SSF=20=E6=97=B6=E8=A7=A6=E5=8F=91=E7=A9=BA?= =?UTF-8?q?=E6=8C=87=E9=92=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SecurityEventReceiver 不再把空 ConnectionManager 包装为非空接口;未启用 SSF 时公开端点明确返回 404。补充运行时和 HTTP 回归测试。\n\n验证:go test ./internal/identityruntime ./internal/httpapi。 --- apps/api/internal/httpapi/security_events_test.go | 12 ++++++++++++ apps/api/internal/identityruntime/manager.go | 5 ++++- apps/api/internal/identityruntime/manager_test.go | 8 ++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) 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{}