From 6b36753b37f9acf7be2733495e85c8ef6bb704ab Mon Sep 17 00:00:00 2001 From: brother7 <7brother7@gmail.com> Date: Wed, 26 Aug 2026 19:26:05 +0800 Subject: [PATCH] fix(coding): reject mismatched Data Service errors --- electron/services/data-service-client.ts | 17 +++++++++++++++++ tests/unit/data-service-client.test.ts | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/electron/services/data-service-client.ts b/electron/services/data-service-client.ts index a1d40f8..6c8d7cb 100644 --- a/electron/services/data-service-client.ts +++ b/electron/services/data-service-client.ts @@ -56,6 +56,22 @@ const CONTEXT_KEYS = new Set([ 'retry_after_seconds', ]); const CONTEXT_RESOURCES = new Set(['instances', 'collections', 'documents', 'bytes']); +const ERROR_STATUS_BY_CODE: Readonly> = { + invalid_cursor: 400, + instance_not_found: 404, + collection_not_found: 404, + document_not_found: 404, + cursor_expired: 410, + revision_conflict: 409, + quota_exceeded: 409, + document_too_large: 413, + invalid_project_id: 422, + invalid_collection_name: 422, + invalid_document_id: 422, + invalid_document_data: 422, + invalid_revision: 422, + rate_limited: 429, +}; type FetchImplementation = typeof fetch; type AccessTokenGetter = typeof getValidWorksSquareAccessToken; @@ -376,6 +392,7 @@ function projectError(payload: unknown, response: Response): DataServiceHostR const detail = payload.detail; const rawCode = boundedString(detail.code, 64); if (!rawCode || !KNOWN_ERROR_CODES.has(rawCode)) return invalidResponse(); + if (ERROR_STATUS_BY_CODE[rawCode] !== response.status) return invalidResponse(); if (detail.retryable !== undefined && typeof detail.retryable !== 'boolean') return invalidResponse(); if (detail.context !== undefined && !isRecord(detail.context)) return invalidResponse(); const code = rawCode; diff --git a/tests/unit/data-service-client.test.ts b/tests/unit/data-service-client.test.ts index 08d2ded..242b30b 100644 --- a/tests/unit/data-service-client.test.ts +++ b/tests/unit/data-service-client.test.ts @@ -202,6 +202,24 @@ describe('DataServiceCloudClient', () => { }); }); + it('rejects a known error code paired with the wrong HTTP status', async () => { + const client = new DataServiceCloudClient({ + fetchImpl: vi.fn().mockResolvedValue( + jsonResponse({ detail: { code: 'quota_exceeded' } }, { status: 400 }), + ), + getAccessToken: vi.fn().mockResolvedValue('access-token'), + }); + + const result = await client.inspect(projectId); + + expect(result).toMatchObject({ + success: false, + status: 502, + code: 'upstream_invalid_response', + data: null, + }); + }); + it('normalizes malformed client errors and all upstream 5xx responses safely', async () => { const fetchImpl = vi.fn() .mockResolvedValueOnce(new Response(null, { status: 404 }))