From e01c917a970bb563158afc81d03ac8ecfca9e344 Mon Sep 17 00:00:00 2001 From: wucm667 Date: Fri, 7 Aug 2026 20:29:17 +0800 Subject: [PATCH] fix(risk-control): block prompts when risk control backend fails - Change loadRuntimeSnapshot failure from fail-open to fail-closed - Return block decision with 500 status when config cannot be loaded - Add regression test for snapshot failure scenario - Fixes #5388 --- .../internal/service/content_moderation.go | 9 +++++++- .../service/content_moderation_test.go | 21 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/backend/internal/service/content_moderation.go b/backend/internal/service/content_moderation.go index acf38bf49b..d916b673ea 100644 --- a/backend/internal/service/content_moderation.go +++ b/backend/internal/service/content_moderation.go @@ -831,7 +831,14 @@ func (s *ContentModerationService) Check(ctx context.Context, input ContentModer "endpoint", input.Endpoint, "protocol", input.Protocol, "error", err) - return allow, nil + return &ContentModerationDecision{ + Allowed: false, + Blocked: true, + Flagged: false, + Message: "风控系统暂时不可用,请稍后重试", + StatusCode: http.StatusInternalServerError, + Action: ContentModerationActionError, + }, nil } if !runtimeSnapshot.riskControlEnabled { slog.Info("content_moderation.skip_feature_disabled", diff --git a/backend/internal/service/content_moderation_test.go b/backend/internal/service/content_moderation_test.go index 1cacc67477..e910326900 100644 --- a/backend/internal/service/content_moderation_test.go +++ b/backend/internal/service/content_moderation_test.go @@ -19,6 +19,7 @@ import ( type contentModerationTestSettingRepo struct { values map[string]string + err error } func (r *contentModerationTestSettingRepo) Get(ctx context.Context, key string) (*Setting, error) { @@ -44,6 +45,9 @@ func (r *contentModerationTestSettingRepo) Set(ctx context.Context, key, value s } func (r *contentModerationTestSettingRepo) GetMultiple(ctx context.Context, keys []string) (map[string]string, error) { + if r.err != nil { + return nil, r.err + } out := map[string]string{} for _, key := range keys { if value, ok := r.values[key]; ok { @@ -53,6 +57,23 @@ func (r *contentModerationTestSettingRepo) GetMultiple(ctx context.Context, keys return out, nil } +func TestContentModerationCheck_LoadRuntimeSnapshotFailureBlocks(t *testing.T) { + svc := &ContentModerationService{ + settingRepo: &contentModerationTestSettingRepo{err: fmt.Errorf("settings unavailable")}, + repo: &contentModerationTestRepo{}, + } + + decision, err := svc.Check(context.Background(), ContentModerationCheckInput{UserID: 1}) + + require.NoError(t, err) + require.False(t, decision.Allowed) + require.True(t, decision.Blocked) + require.False(t, decision.Flagged) + require.Equal(t, ContentModerationActionError, decision.Action) + require.Equal(t, "风控系统暂时不可用,请稍后重试", decision.Message) + require.Equal(t, http.StatusInternalServerError, decision.StatusCode) +} + func (r *contentModerationTestSettingRepo) SetMultiple(ctx context.Context, settings map[string]string) error { if r.values == nil { r.values = map[string]string{}