fix(errors): 区分平台限流并保留上游状态码
原因:公开错误层将平台并发限流误标为上游限流,并把多种上游 4xx 统一压成 400,影响定位和客户端处理。 影响:新增公开错误 source,平台限流使用 gateway_rate_limited,上游请求按安全分类返回对应状态;数据库与管理端继续保留原始错误码、消息和状态用于审计。 验证:Go 全量测试、pnpm test、pnpm lint、pnpm build、pnpm openapi、gofmt 和 diff 检查均通过。
This commit is contained in:
@@ -8,6 +8,8 @@ import (
|
||||
func TestMaskAdminGatewayTaskRecursivelyMasksSecretsWithoutMutatingSource(t *testing.T) {
|
||||
source := AdminGatewayTask{
|
||||
GatewayTask: GatewayTask{
|
||||
ErrorCode: "http_404",
|
||||
ErrorMessage: "404 page not found from upstream route /private/v1/images",
|
||||
Request: map[string]any{
|
||||
"model": "example",
|
||||
"headers": map[string]any{
|
||||
@@ -20,12 +22,17 @@ func TestMaskAdminGatewayTaskRecursivelyMasksSecretsWithoutMutatingSource(t *tes
|
||||
"nested": []any{map[string]any{"password": "private-password"}},
|
||||
},
|
||||
Attempts: []TaskAttempt{{
|
||||
ErrorCode: "http_404",
|
||||
ErrorMessage: "404 page not found from upstream route /private/v1/images",
|
||||
RequestSnapshot: map[string]any{"client_secret": "private-client-secret"},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
masked := MaskAdminGatewayTask(source)
|
||||
if masked.ErrorCode != source.ErrorCode || masked.ErrorMessage != source.ErrorMessage || masked.Attempts[0].ErrorMessage != source.Attempts[0].ErrorMessage {
|
||||
t.Fatalf("admin error audit fields must preserve raw upstream values: %#v", masked)
|
||||
}
|
||||
headers := masked.Request["headers"].(map[string]any)
|
||||
if headers["Authorization"] != maskedAdminTaskValue || headers["X-Api-Key"] != maskedAdminTaskValue {
|
||||
t.Fatalf("sensitive headers were not masked: %#v", headers)
|
||||
|
||||
@@ -94,7 +94,7 @@ func (e *RateLimitExceededError) Error() string {
|
||||
}
|
||||
|
||||
func (e *RateLimitExceededError) ErrorCode() string {
|
||||
return "rate_limit"
|
||||
return "gateway_rate_limited"
|
||||
}
|
||||
|
||||
func (e *RateLimitExceededError) Unwrap() error {
|
||||
@@ -349,6 +349,7 @@ type FinishTaskFailureInput struct {
|
||||
ExecutionToken string
|
||||
Code string
|
||||
Message string
|
||||
StatusCode int
|
||||
Result map[string]any
|
||||
RequestID string
|
||||
Metrics map[string]any
|
||||
|
||||
@@ -2068,7 +2068,7 @@ func (s *Store) FinishTaskFailure(ctx context.Context, input FinishTaskFailureIn
|
||||
metricsJSON, _ := json.Marshal(sanitizeJSONForStorage(emptyObjectIfNil(input.Metrics)))
|
||||
resultJSON, _ := json.Marshal(minimalTaskResult(nil))
|
||||
message := truncateUTF8Bytes(input.Message, 2048)
|
||||
publicErrorJSON := encodePublicErrorSnapshot(input.Code, message, 0, true, input.RequestID, input.TaskID)
|
||||
publicErrorJSON := encodePublicErrorSnapshot(input.Code, message, input.StatusCode, true, input.RequestID, input.TaskID)
|
||||
finalizedAdmission := false
|
||||
err := s.beginTransaction(ctx, func(tx pgx.Tx) error {
|
||||
tag, err := tx.Exec(ctx, `
|
||||
|
||||
Reference in New Issue
Block a user