Skip to content

feat(error-rules): 添加错误响应覆盖功能#225

Merged
ding113 merged 16 commits intoding113:feat/error_overidefrom
sususu98:feat/error_overide
Nov 28, 2025
Merged

feat(error-rules): 添加错误响应覆盖功能#225
ding113 merged 16 commits intoding113:feat/error_overidefrom
sususu98:feat/error_overide

Conversation

@sususu98
Copy link
Contributor

概述

添加错误规则匹配时覆盖错误响应和状态码的能力:

  • 新增数据库字段override_response (JSONB) 和 override_status_code
  • 运行时覆盖逻辑:在 error-handler 中实现,支持状态码验证(400-599 范围)
  • 新增验证器:Claude API 错误格式验证,10KB 大小限制
  • 前端:覆盖配置组件,支持实时 JSON 验证
  • 前端:错误规则测试器,可预览覆盖行为
  • 支持空消息时回退到原始错误
  • 完全向后兼容:无覆盖配置时行为不变

变更内容

数据库

  • errorRules 表添加 override_response (JSONB) 和 override_status_code 字段
  • 新增迁移文件:0021_broad_black_panther.sql

后端

  • src/app/v1/_lib/proxy/error-handler.ts - 覆盖逻辑及验证
  • src/app/v1/_lib/proxy/errors.ts - 错误响应处理
  • src/lib/error-override-validator.ts - Claude API 错误格式验证器
  • src/lib/error-rule-detector.ts - 增强规则检测
  • src/repository/error-rules.ts - 仓库层更新
  • src/actions/error-rules.ts - CRUD Server Actions

前端

  • src/app/[locale]/settings/error-rules/_components/override-section.tsx - 覆盖配置 UI
  • src/app/[locale]/settings/error-rules/_components/error-rule-tester.tsx - 规则测试器
  • 所有支持语言的 i18n 消息(en、ja、ru、zh-CN、zh-TW)

测试计划

  • 验证可创建带覆盖配置的新错误规则
  • 测试错误规则测试器的示例错误功能
  • 验证规则匹配时正确返回覆盖响应
  • 确认现有规则的向后兼容性(无覆盖配置)

🤖 Generated with Claude Code

github-actions bot and others added 16 commits November 28, 2025 09:59
Add ability to override error responses and status codes when error rules match:
- New DB fields: override_response (JSONB) and override_status_code
- Runtime override logic in error-handler with validation (400-599 range)
- New validator for Claude API error format with 10KB size limit
- Frontend: override section component with real-time JSON validation
- Frontend: error rule tester to preview override behavior
- Support empty message fallback to original error
- Backward compatible: no behavior change without override config

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @sususu98, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求引入了一项重要功能,允许系统管理员根据预定义的错误规则自定义返回给客户端的错误响应和 HTTP 状态码。这使得系统能够将复杂的上游错误转换为更具描述性或标准化的客户端消息,同时仍然在后端记录原始错误以供调试。该功能包括对覆盖配置的严格验证、对 Claude API 错误格式的支持,以及一个直观的前端测试工具,以简化配置和验证过程。

Highlights

  • 错误响应覆盖功能: 引入了根据匹配的错误规则自定义错误响应体和 HTTP 状态码的能力,以提供更友好的客户端错误信息。
  • 数据库和后端逻辑增强: 在 errorRules 表中新增了 override_response (JSONB) 和 override_status_code 字段,并在错误处理逻辑中实现了运行时覆盖、状态码验证(400-599 范围)和 Claude API 错误格式验证(10KB 大小限制)。
  • 前端配置与测试工具: 新增了错误覆盖配置的用户界面组件,支持实时 JSON 验证,并提供了一个交互式的“错误规则测试器”,允许用户预览错误消息如何被匹配和覆盖。
  • 增强的错误信息提取: 改进了从上游错误响应中提取 request_id 的逻辑,支持多种嵌套格式和响应头,确保在错误覆盖时能正确透传请求 ID。
  • 向后兼容性与缓存优化: 确保了现有规则在没有覆盖配置时行为不变,并优化了错误规则检测器的缓存机制,避免重复加载和不一致的状态。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@ding113 ding113 added the size/L Large PR (< 1000 lines) label Nov 28, 2025
@ding113
Copy link
Owner

ding113 commented Nov 28, 2025

📊 PR Size Analysis

This PR is Large (L) with ~3,674 total lines changed across 26 files.

Breakdown

Category Lines Notes
Auto-generated ~1,925 Drizzle snapshot, migration, journal
Seed data ~314 litellm-prices.json
Actual code ~1,435 Backend, frontend, i18n

📝 Assessment

This PR implements a single cohesive feature (error response override functionality) with properly structured changes:

Database layer: Schema + migration
Backend logic: Error handler, validator, detector
Server Actions: CRUD operations
Frontend UI: Config components, rule tester
i18n: All 5 locales updated
Documentation: CHANGELOG updated

🤔 Split Recommendation

While this PR is large, splitting is NOT strongly recommended because:

  1. All changes are tightly coupled to the same feature
  2. Splitting would create incomplete/broken intermediate states
  3. The large line count is inflated by:
    • Auto-generated Drizzle snapshot (1,602 lines)
    • Seed data updates (314 lines)
    • i18n translations (170 lines across 5 files)

If splitting is desired, the only reasonable approach would be:

  1. PR 1: Database schema + backend logic (~800 lines)

    • Schema changes, migrations
    • error-handler.ts, errors.ts, validator, detector
    • Repository + actions
  2. PR 2: Frontend UI + i18n (~600 lines)

    • Override section, rule tester components
    • Dialog updates, page changes
    • All i18n files

However, this would require PR 1 to merge first and PR 2 would need the API from PR 1.


🤖 Automated analysis by Claude AI

@ding113 ding113 added the enhancement New feature or request label Nov 28, 2025
@ding113
Copy link
Owner

ding113 commented Nov 28, 2025

🔒 Security Scan Results

No critical or high severity security vulnerabilities detected

This PR has been scanned against OWASP Top 10, CWE Top 25, and common security anti-patterns. The implementation follows security best practices.


📋 OWASP Top 10 Coverage

  • A01: Injection - Clean

    • No SQL injection: Uses Drizzle ORM with parameterized queries throughout
    • JSON parsing properly validated before use (validateErrorOverrideResponse)
    • Status codes validated to 400-599 range before creating HTTP Response
  • A02: Broken Authentication - Clean

    • Admin-only access properly enforced via getSession() checks in all server actions
    • No credentials exposed or hardcoded
  • A03: Sensitive Data Exposure - Clean

    • Error messages are sanitized before returning to clients
    • request_id from override config is explicitly stripped and replaced with upstream value
    • No sensitive data logged
  • A04: XML External Entities - N/A (No XML processing)

  • A05: Broken Access Control - Clean

    • All mutating server actions (createErrorRuleAction, updateErrorRuleAction, deleteErrorRuleAction, testErrorRuleAction) verify admin role
    • Proper authorization checks before CRUD operations
  • A06: Security Misconfiguration - Clean

    • Default values are secure (override disabled by default)
    • Proper status code range validation (400-599)
  • A07: XSS - Clean

    • React auto-escaping used throughout (no dangerouslySetInnerHTML)
    • JSON displayed in <pre> tag with proper JSON.stringify encoding
    • User input not directly interpolated into HTML
  • A08: Insecure Deserialization - Clean

    • JSON.parse() results validated against schema before use
    • Size limit enforced (10KB max for override response)
    • Invalid JSON gracefully rejected with proper error messages
  • A09: Known Vulnerabilities - N/A (No new dependencies added)

  • A10: Logging & Monitoring - Clean

    • Errors logged with appropriate context
    • Security-relevant operations (override applications) logged for audit

🛡️ Security Strengths Observed

  1. Defense in Depth for Override Response Validation

    • Validation at repository layer (sanitizeOverrideResponse)
    • Validation at detector load time (isValidErrorOverrideResponse)
    • Runtime validation in error handler (double-check before response)
  2. Input Validation

    • Status code range: 400-599 (prevents RangeError in Response constructor)
    • JSON structure validation enforces required type: "error" and error.type, error.message fields
    • Response body size limit: 10KB
  3. Regex Security

    • Uses safe-regex library to detect and skip ReDoS-vulnerable patterns
    • Potentially dangerous regexes logged and excluded from processing
  4. Error Handling

    • Original errors logged to database for audit
    • Graceful fallback when override config is invalid
    • request_id properly sanitized and only used if string type

📝 Informational Notes (Not Security Issues)

  1. Error Override Feature Design: The new error override feature allows admins to customize error responses returned to API clients. This is properly restricted to admin users only and validated at multiple layers.

  2. Cache Consistency: The code uses atomic replacement of pattern arrays during reload to prevent race conditions where detect() might see partial data.

  3. WeakMap for Detection Cache: Using WeakMap for error detection caching is appropriate - prevents memory leaks as Error objects are garbage collected.


🔍 Scanned Files

File Status
src/actions/error-rules.ts ✅ Clean
src/app/v1/_lib/proxy/error-handler.ts ✅ Clean
src/app/v1/_lib/proxy/errors.ts ✅ Clean
src/app/v1/_lib/proxy/responses.ts ✅ Clean
src/lib/error-override-validator.ts ✅ Clean
src/lib/error-rule-detector.ts ✅ Clean
src/repository/error-rules.ts ✅ Clean
src/drizzle/schema.ts ✅ Clean
Frontend components ✅ Clean

🤖 Automated security scan by Claude AI - OWASP Top 10 & CWE coverage

Copy link
Owner

@ding113 ding113 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Code Review Summary

This PR adds error response override functionality to the error rules system, allowing administrators to customize error responses when specific patterns match. The implementation is comprehensive with database migrations, backend logic, frontend UI, and i18n support.

🔍 Issues Found

  • Critical (🔴): 0 issues
  • High (🟠): 1 issue
  • Medium (🟡): 3 issues
  • Low (🟢): 1 issue

🎯 Priority Actions

  1. 🟠 High: The buildError function signature in responses.ts was not updated to accept request_id, but it's being called with 5 arguments in error-handler.ts - this will silently ignore the request_id parameter for non-override error paths
  2. 🟡 Medium: syncDefaultErrorRules() no longer emits the errorRulesUpdated event, but refreshCacheAction() relies on this for proper cache coordination - potential for inconsistent cache state in multi-instance deployments
  3. 🟡 Medium: The extractJsonFromString method has unbounded loop iteration on malformed input - consider adding a max iteration limit
  4. 🟡 Medium: Missing test coverage for the new override functionality, especially edge cases like empty messages and invalid status codes

💡 General Observations

  • The error override validation is thorough with both schema-level and runtime checks
  • The request_id extraction logic handles many edge cases but could benefit from unit tests
  • Consider adding database-level constraints for the status code range to prevent invalid data from external sources

🤖 Automated review by Claude AI - focused on identifying issues for improvement

@@ -6,17 +6,50 @@ All notable changes to this project will be documented in this file.

### Added

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Missing Feature Documentation: PR #225 feature not documented in CHANGELOG

Problem: This PR adds a significant new feature "Error Response Override" (错误响应覆盖) that allows users to customize error responses and status codes when error rules match. However, the CHANGELOG.md does not include any entry for this PR's main feature.

The PR:

  • Adds override_response and override_status_code database fields
  • Implements runtime override logic with validation (400-599 range)
  • Adds Claude API error format validator with 10KB size limit
  • Creates UI components for override configuration and error rule testing
  • Supports i18n for all 5 languages

Impact: Users reviewing the changelog will not be aware of this new capability, which defeats the purpose of maintaining a changelog.

Suggested Fix:
Add an entry under ### Added section:

- Add error response override feature with customizable error responses and status codes for error rules (#225) @ding113

Or more detailed:

- Add error response override feature allowing custom error responses and status codes when error rules match, with real-time JSON validation and error rule tester UI (#225) @ding113

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

这个 PR 引入了一个重要的功能:错误响应覆盖。它允许在错误规则匹配时自定义返回给客户端的响应体和状态码。整体实现非常出色,考虑了数据库迁移、后端覆盖逻辑、前端配置界面和测试工具等多个方面。代码质量很高,特别是在错误处理和验证方面做了很多健壮性设计,例如对 requestId 的提取和注入、对数据库中可能存在的脏数据进行运行时校验等。

我提出了几点改进建议,主要集中在提高代码的可维护性和简洁性上:

  1. 更新日志:建议在 CHANGELOG.md 中为这个新功能添加一条记录。
  2. 代码去重:状态码的验证逻辑和相关常量在 error-handler.tserror-rules.ts 中存在重复,建议将其统一到 error-override-validator.ts 中,以遵循 DRY 原则。
  3. 代码简化:在 testErrorRuleAction 中,对 matchType 的验证可以简化,因为其类型已由上游保证。

总的来说,这是一个高质量的提交,我的建议旨在做一些锦上添花的改进。


### Added

- Add provider availability monitoring dashboard with real-time health status, metrics, and heatmap visualization (#216) @ding113
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这是一个很棒的新功能,但它似乎没有被记录在 CHANGELOG.mdAdded 部分。为了方便用户了解版本更新,建议为这个新的错误响应覆盖功能添加一条更新日志。

Suggested change
- Add provider availability monitoring dashboard with real-time health status, metrics, and heatmap visualization (#216) @ding113
- Add error response override functionality with status code and body customization, including a frontend tester for real-time validation.
- Add provider availability monitoring dashboard with real-time health status, metrics, and heatmap visualization (#216) @ding113

Comment on lines +12 to +37
/** 覆写状态码最小值 */
const OVERRIDE_STATUS_CODE_MIN = 400;
/** 覆写状态码最大值 */
const OVERRIDE_STATUS_CODE_MAX = 599;

/**
* 验证覆写状态码范围
*
* @param statusCode - 要验证的状态码
* @returns 错误消息(如果验证失败)或 null(验证通过)
*/
function validateOverrideStatusCodeRange(statusCode: number | null | undefined): string | null {
if (statusCode === null || statusCode === undefined) {
return null;
}

if (
!Number.isInteger(statusCode) ||
statusCode < OVERRIDE_STATUS_CODE_MIN ||
statusCode > OVERRIDE_STATUS_CODE_MAX
) {
return `覆写状态码必须是 ${OVERRIDE_STATUS_CODE_MIN}-${OVERRIDE_STATUS_CODE_MAX} 范围内的整数`;
}

return null;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这个 validateOverrideStatusCodeRange 函数和相关的常量是通用的验证逻辑。为了提高代码的模块化和可复用性,建议将它们统一移动到 src/lib/error-override-validator.ts 文件中。这样,其他地方(如 error-handler.ts)的重复逻辑就可以被替换掉。

Comment on lines +475 to +480
const validMatchTypes = ["regex", "contains", "exact"] as const;
const matchType = validMatchTypes.includes(
detection.matchType as (typeof validMatchTypes)[number]
)
? (detection.matchType as "regex" | "contains" | "exact")
: "regex";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这里的 matchType 验证逻辑有些复杂。errorRuleDetectordetectdetectAsync 方法已经确保了返回的 detection.matchType 必定是 "regex", "contains", 或 "exact" 中的一个。我们可以通过直接进行类型断言来简化此处的代码,这样更清晰,也更符合类型契约。

Suggested change
const validMatchTypes = ["regex", "contains", "exact"] as const;
const matchType = validMatchTypes.includes(
detection.matchType as (typeof validMatchTypes)[number]
)
? (detection.matchType as "regex" | "contains" | "exact")
: "regex";
const matchType = detection.matchType as "regex" | "contains" | "exact";

Comment on lines +9 to +12
/** 覆写状态码最小值 */
const OVERRIDE_STATUS_CODE_MIN = 400;
/** 覆写状态码最大值 */
const OVERRIDE_STATUS_CODE_MAX = 599;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这里的常量 OVERRIDE_STATUS_CODE_MINOVERRIDE_STATUS_CODE_MAXsrc/actions/error-rules.ts 中也重复定义了。为了避免代码重复并提高可维护性,建议将这些常量和相关的验证函数 (validateOverrideStatusCodeRange) 统一移动到 src/lib/error-override-validator.ts 文件中,并在此处及其他地方导入使用。

@ding113
Copy link
Owner

ding113 commented Nov 28, 2025

📝 Documentation Review

📊 Issues Summary

  • Critical (🔴): 1 - Must fix before merge
  • High (🟠): 0 - Should fix before merge
  • Medium (🟡): 0 - Consider addressing
  • Low (🟢): 0 - Optional improvements

⚡ Priority Fixes

  1. 🔴 Missing Feature Documentation: The main feature of this PR (Error Response Override / 错误响应覆盖功能) is not documented in CHANGELOG.md. The changelog includes entries from PRs release #199, fix bugs #207, small update #210, release #216, fix(ui): 修复供应商可用性监控页面排序顺序 #219, fix: 故障转移后无条件更新 Session 绑定 #220, but not the new feature being added in PR feat(error-rules): 添加错误响应覆盖功能 #225.

📋 Review Coverage

  • Technical accuracy - 0 issues (changelog entries reference valid PRs)
  • Completeness - 1 critical issue (missing PR feat(error-rules): 添加错误响应覆盖功能 #225 feature entry)
  • Code examples - N/A (no code examples in changelog)
  • Links and references - 0 issues (all PR numbers verified)
  • Clarity and organization - 0 issues (follows Keep a Changelog format)

💡 General Observations

Positive aspects:

Issue to address:
The PR adds a significant new feature (error response override with database fields, validators, UI components, and i18n support) but the CHANGELOG.md doesn't document this feature. Please add an entry such as:

### Added
- Add error response override feature with customizable error responses and status codes for error rules (#225) @ding113

🤖 Automated docs review by Claude AI

Copy link
Owner

@ding113 ding113 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detailed Review Comments

Issue 1: ProxyResponses.buildError signature mismatch (🟠 High)

File: src/app/v1/_lib/proxy/error-handler.ts:161

The buildError function in responses.ts has a 4-parameter signature, but error-handler.ts calls it with 5 arguments including safeRequestId. TypeScript won't catch this because extra arguments are silently ignored in JavaScript. This means the request_id will never appear in non-override error responses.

Fix: Update the buildError signature in responses.ts to accept an optional requestId parameter.


Issue 2: syncDefaultErrorRules event emission removed (🟡 Medium)

File: src/repository/error-rules.ts:355-356

The eventEmitter.emit('errorRulesUpdated') was removed from syncDefaultErrorRules(), but the comment says "由调用方决定是否刷新缓存". However, if multiple server instances are running, other instances won't know about the sync because the event is no longer emitted. This could lead to stale cache in distributed deployments.

Fix: Either restore the event emission or add documentation explaining that this function should only be called from refreshCacheAction which handles cache refresh.


Issue 3: extractJsonFromString unbounded loop (🟡 Medium)

File: src/app/v1/_lib/proxy/errors.ts:226-257 (extractJsonFromString method)

The extractJsonFromString method iterates over the entire string character by character. On malformed input with an opening brace but no matching closing brace, this will iterate through the entire string length. For very large error responses, this could cause performance issues.

Fix: Add a maximum iteration limit or string length check:

private static extractJsonFromString(str: string): string | null {
  const MAX_JSON_LENGTH = 10000; // 10KB limit
  if (!str.startsWith('{') || str.length > MAX_JSON_LENGTH) {
    return null;
  }
  // ... rest of implementation
}

Issue 4: Missing newline at end of migration file (🟢 Low)

File: drizzle/0021_broad_black_panther.sql

The migration file is missing a trailing newline, which is a POSIX standard for text files and can cause issues with some tools.

Fix: Add a newline at the end of the file.

@ding113 ding113 changed the base branch from dev to feat/error_overide November 28, 2025 04:08
@ding113 ding113 merged commit 26bfeca into ding113:feat/error_overide Nov 28, 2025
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size/L Large PR (< 1000 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments