mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
fix(jotform): harden the error envelope against quoted codes and non-JSON bodies
Jotform quotes `responseCode` on some endpoints and not others, so a typeof-number test skipped the check on the quoted ones and turned an auth failure into a successful tool result with empty output. Also caps the raw body fallback, since an upstream gateway can answer with an HTML page instead of the documented envelope.
This commit is contained in:
@@ -420,3 +420,27 @@ describe('label resources', () => {
|
||||
expect(depth).toBeLessThanOrEqual(32)
|
||||
})
|
||||
})
|
||||
|
||||
describe('error envelope robustness', () => {
|
||||
/**
|
||||
* Jotform quotes `responseCode` on some endpoints and not others. A
|
||||
* `typeof === 'number'` test silently skips the check on the quoted ones, turning
|
||||
* an auth failure into a successful tool result with empty output.
|
||||
*/
|
||||
it('throws on a quoted non-2xx responseCode', async () => {
|
||||
await expect(
|
||||
parseJotformResponse(
|
||||
jsonResponse({ responseCode: '401', message: 'Invalid API Key' }),
|
||||
'Jotform Get Form'
|
||||
)
|
||||
).rejects.toThrow('Jotform Get Form error (401): Invalid API Key')
|
||||
})
|
||||
|
||||
/** An upstream gateway can answer with an HTML page instead of the JSON envelope. */
|
||||
it('caps a non-JSON error body instead of inlining the whole page', async () => {
|
||||
const page = `<html>${'x'.repeat(5000)}</html>`
|
||||
await expect(
|
||||
parseJotformResponse(new Response(page, { status: 502 }), 'Jotform Get Form')
|
||||
).rejects.toThrow(/^Jotform Get Form error \(502\): .{1,320}$/s)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getErrorMessage } from '@sim/utils/errors'
|
||||
import { truncate } from '@sim/utils/string'
|
||||
|
||||
/**
|
||||
* Jotform serves the same REST surface from three regional hosts, and an API key
|
||||
@@ -75,11 +76,17 @@ export async function parseJotformResponse(
|
||||
}
|
||||
|
||||
const message = typeof data?.message === 'string' ? data.message : null
|
||||
const responseCode = typeof data?.responseCode === 'number' ? data.responseCode : null
|
||||
/* Jotform types `responseCode` inconsistently across endpoints, quoting it on some,
|
||||
so a `typeof === 'number'` test would skip the check on the quoted ones. */
|
||||
const responseCode = toNumberOrNull(data?.responseCode)
|
||||
|
||||
if (!response.ok || (responseCode !== null && (responseCode < 200 || responseCode >= 300))) {
|
||||
const status = responseCode ?? response.status
|
||||
throw new Error(`${label} error (${status}): ${message || text || response.statusText}`)
|
||||
/* An error body is not always the documented JSON envelope — an upstream gateway
|
||||
can return an HTML page — so the raw fallback is capped before it becomes the
|
||||
error message. */
|
||||
const detail = message || truncate(text, 300) || response.statusText
|
||||
throw new Error(`${label} error (${status}): ${detail}`)
|
||||
}
|
||||
|
||||
const rawResultSet = data?.resultSet as Record<string, unknown> | undefined
|
||||
|
||||
Reference in New Issue
Block a user