feat(storage): 统一二进制对象存储与公开错误
新增 Aliyun OSS 与 S3 协议、通道内重试和按优先级跨通道切换,保留 server-main 兼容与环境 OSS 内存通道。 将请求及结果中的 Base64、Data URI、Buffer、multipart 和内联二进制统一对象化,生产路径不再写入本机静态目录,历史本地资源仅保留只读兼容。 引入 PublicErrorV1 并统一 API、异步查询、兼容协议和失败回调的安全错误输出,同时补充迁移、管理端、指标、OpenAPI 与本地模拟验收。 验证:go test ./... -count=1;go vet ./...;pnpm lint;pnpm test;pnpm build;pnpm openapi;tests/ci/migrations-test.sh。
This commit is contained in:
@@ -47,7 +47,7 @@ func TestProtocolAPIKeyStoreFailureIs503InsteadOf401(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProtocolErrorsUseOfficialShapesWithoutGatewayExtensions(t *testing.T) {
|
||||
func TestProtocolErrorsUseCompatibleShapesWithStandardPublicErrors(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
protocol string
|
||||
@@ -78,10 +78,10 @@ func TestProtocolErrorsUseOfficialShapesWithoutGatewayExtensions(t *testing.T) {
|
||||
name: "volces", protocol: clients.ProtocolVolcesContents, status: http.StatusBadGateway,
|
||||
assertBody: func(t *testing.T, body map[string]any) {
|
||||
errorBody := requireObject(t, body["error"])
|
||||
if errorBody["code"] != "upstream_submission_unknown" {
|
||||
if errorBody["code"] != "upstream_submission_unknown" || errorBody["httpStatus"] != float64(http.StatusBadGateway) || errorBody["retryable"] != true {
|
||||
t.Fatalf("unexpected Volces error: %+v", body)
|
||||
}
|
||||
assertNoKeys(t, errorBody, "status", "retryable", "taskId", "gateway_status")
|
||||
assertNoKeys(t, errorBody, "status", "taskId", "gateway_status")
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -135,6 +135,44 @@ func TestWireResponsePassthroughPreservesStatusUnknownFieldsAndAllowedHeaders(t
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompatibilityErrorWritersNeverExposeTransportDetails(t *testing.T) {
|
||||
raw := "read tcp 10.42.0.72:54960->47.77.191.126:443: read: connection reset by peer"
|
||||
tests := []struct {
|
||||
name string
|
||||
write func(http.ResponseWriter)
|
||||
}{
|
||||
{name: "openai", write: func(w http.ResponseWriter) {
|
||||
writeProtocolError(w, clients.ProtocolOpenAIResponses, http.StatusOK, raw, map[string]any{
|
||||
"provider": "secret-provider", "endpoint": "https://private.example.invalid", "bucket": "private-bucket",
|
||||
}, "response_read_error")
|
||||
}},
|
||||
{name: "volces", write: func(w http.ResponseWriter) {
|
||||
writeVolcesError(w, http.StatusOK, raw, "response_read_error")
|
||||
}},
|
||||
{name: "kling", write: func(w http.ResponseWriter) {
|
||||
writeKlingCompatError(w, http.StatusOK, raw, "response_read_error")
|
||||
}},
|
||||
{name: "keling", write: func(w http.ResponseWriter) {
|
||||
writeKelingCompatError(w, "request-1", newKelingCompatError(http.StatusOK, 5001, raw))
|
||||
}},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
test.write(recorder)
|
||||
if recorder.Code != http.StatusBadGateway {
|
||||
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
body := recorder.Body.String()
|
||||
if strings.Contains(body, "10.42.0.72") || strings.Contains(body, "47.77.191.126") ||
|
||||
strings.Contains(body, "secret-provider") || strings.Contains(body, "private.example.invalid") || strings.Contains(body, "private-bucket") ||
|
||||
!strings.Contains(body, "upstream_connection_interrupted") {
|
||||
t.Fatalf("transport details were not standardized: %s", body)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompatibilityStatusMappings(t *testing.T) {
|
||||
for internal, want := range map[string]string{
|
||||
"queued": "queued", "running": "running", "succeeded": "succeeded", "failed": "failed", "cancelled": "cancelled",
|
||||
|
||||
Reference in New Issue
Block a user