diff --git a/.jules/bolt.md b/.jules/bolt.md index 31adfad..e21defa 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -12,3 +12,11 @@ The default Express `express.json()` middleware limits incoming JSON payloads to Action: Increased the JSON payload limit in `src/index.js` to 10mb, and added an explicit error handler to intercept `err.type === 'entity.too.large'` and return a standardized `413 Payload Too Large` JSON response. + +## 2024-05-24 — Improve array validation and bound computationCache memory map size + +Learning: +Unbounded Map caches in repeated serverless or long-running operations can cause memory leaks. Also, `req.body.messages` without `Array.isArray()` validation can lead to crashes if a string is provided and later mapped. + +Action: +Added strict `!Array.isArray(messages)` validation to the `/v1/chat/completions` API route, and restricted the `computationCache` Map size to 1000 items in `src/index.js` to ensure long-term stability and resilience. diff --git a/src/index.js b/src/index.js index 59961d9..8f2c17f 100644 --- a/src/index.js +++ b/src/index.js @@ -37,8 +37,8 @@ app.use((err, req, res, next) => { // API endpoints app.post('/v1/chat/completions', (req, res) => { const { model, messages } = req.body || {}; - if (!model || !messages) { - return res.status(400).json({ error: 'Missing model or messages' }); + if (!model || !messages || !Array.isArray(messages)) { + return res.status(400).json({ error: 'Missing or invalid model or messages' }); } // Mock unified response @@ -91,6 +91,11 @@ function heavyComputation(iterations) { return computationCache.get(iterations); } + // Prevent memory leak from unbounded cache growth + if (computationCache.size >= 1000) { + computationCache.clear(); + } + let sum = 0; for (let i = 0; i < iterations; i++) { sum += Math.sqrt(i) * Math.sin(i * 0.01); diff --git a/tests/api.test.js b/tests/api.test.js index e184779..29ed2eb 100644 --- a/tests/api.test.js +++ b/tests/api.test.js @@ -33,7 +33,19 @@ test('POST /v1/chat/completions fails without model', async () => { }); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error, 'Missing model or messages'); + assert.strictEqual(res.body.error, 'Missing or invalid model or messages'); +}); + +test('POST /v1/chat/completions fails when messages is not an array', async () => { + const res = await request(app) + .post('/v1/chat/completions') + .send({ + model: 'gpt-4', + messages: "Hello!" + }); + + assert.strictEqual(res.status, 400); + assert.strictEqual(res.body.error, 'Missing or invalid model or messages'); }); test('POST /v1/chat/completions fails with invalid JSON gracefully', async () => { diff --git a/tests/api_robustness.test.js b/tests/api_robustness.test.js index 0575486..59f5d70 100644 --- a/tests/api_robustness.test.js +++ b/tests/api_robustness.test.js @@ -10,7 +10,7 @@ test('POST /v1/chat/completions handles undefined req.body (e.g. non-JSON conten .send('some text'); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error, 'Missing model or messages'); + assert.strictEqual(res.body.error, 'Missing or invalid model or messages'); }); test('POST /v1/chat/completions handles payload too large gracefully', async () => {