5xx 错误响应不再回带 provider task id
- TaskFailure / OutputSchema / 上游兜底分支只回固定文案,完整错误写入服务端日志 - 补一条断言 502 details 不含 task id 与 provider 原文的用例
This commit is contained in:
@@ -84,21 +84,32 @@ pub(crate) fn map_provider_error(error: TripoError) -> AppError {
|
||||
"tripo-api-rejected",
|
||||
error.to_string(),
|
||||
),
|
||||
TripoError::TaskFailure { .. } => (
|
||||
StatusCode::BAD_GATEWAY,
|
||||
"tripo-task-failed",
|
||||
error.to_string(),
|
||||
),
|
||||
TripoError::OutputSchema { .. } => (
|
||||
StatusCode::BAD_GATEWAY,
|
||||
"tripo-output-schema",
|
||||
error.to_string(),
|
||||
),
|
||||
TripoError::Request { .. } | TripoError::Sdk { .. } | TripoError::Api { .. } => (
|
||||
StatusCode::BAD_GATEWAY,
|
||||
"tripo-upstream-error",
|
||||
error.to_string(),
|
||||
),
|
||||
// 以下都是 5xx:完整错误只进日志。`TripoError` 的 Display 会带上 provider task id,
|
||||
// 直接回给客户端会破坏本文件「不暴露 task id」的口径,因此对外只给固定文案。
|
||||
TripoError::TaskFailure { .. } => {
|
||||
tracing::error!(error = %error, "tripo task failed");
|
||||
(
|
||||
StatusCode::BAD_GATEWAY,
|
||||
"tripo-task-failed",
|
||||
"3D 生成任务在 provider 侧执行失败。".to_string(),
|
||||
)
|
||||
}
|
||||
TripoError::OutputSchema { .. } => {
|
||||
tracing::error!(error = %error, "tripo task output schema error");
|
||||
(
|
||||
StatusCode::BAD_GATEWAY,
|
||||
"tripo-output-schema",
|
||||
"3D 生成任务的结果格式不符合预期,未落库。".to_string(),
|
||||
)
|
||||
}
|
||||
TripoError::Request { .. } | TripoError::Sdk { .. } | TripoError::Api { .. } => {
|
||||
tracing::error!(error = %error, "tripo upstream error");
|
||||
(
|
||||
StatusCode::BAD_GATEWAY,
|
||||
"tripo-upstream-error",
|
||||
"3D 生成服务暂时不可用,请稍后重试。".to_string(),
|
||||
)
|
||||
}
|
||||
};
|
||||
AppError::from_status(status).with_details(json!({
|
||||
"provider": TRIPO_PROVIDER,
|
||||
@@ -166,4 +177,29 @@ mod tests {
|
||||
});
|
||||
assert_eq!(error.status_code(), StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
/// 本模块头部承诺「任何分支都不把 provider task id 带进响应」,502 分支必须守住。
|
||||
#[test]
|
||||
fn provider_5xx_does_not_leak_task_id() {
|
||||
let cases = [
|
||||
TripoError::TaskFailure {
|
||||
task_id: "task-secret-123".to_string(),
|
||||
status: "failed".to_string(),
|
||||
message: Some("provider exploded".to_string()),
|
||||
},
|
||||
TripoError::OutputSchema {
|
||||
task_id: "task-secret-456".to_string(),
|
||||
message: "output schema error".to_string(),
|
||||
},
|
||||
];
|
||||
for case in cases {
|
||||
let error = map_provider_error(case);
|
||||
assert_eq!(error.status_code(), StatusCode::BAD_GATEWAY);
|
||||
let serialized = serde_json::to_string(error.details().expect("details 必须存在"))
|
||||
.expect("details 必须可序列化");
|
||||
for leaked in ["task-secret", "provider exploded", "output schema error"] {
|
||||
assert!(!serialized.contains(leaked), "{serialized}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user