feat(core-api): harden signed urls and llm rate limits

This commit is contained in:
zouantchaw
2026-02-24 10:17:48 -05:00
parent e733f36d28
commit 52c3fbad40
7 changed files with 162 additions and 13 deletions

View File

@@ -1,10 +1,17 @@
import test from 'node:test';
import test, { beforeEach } from 'node:test';
import assert from 'node:assert/strict';
import request from 'supertest';
import { createApp } from '../src/app.js';
import { __resetLlmRateLimitForTests } from '../src/services/llm-rate-limit.js';
process.env.AUTH_BYPASS = 'true';
process.env.LLM_MOCK = 'true';
beforeEach(() => {
process.env.AUTH_BYPASS = 'true';
process.env.LLM_MOCK = 'true';
process.env.SIGNED_URL_MOCK = 'true';
process.env.MAX_SIGNED_URL_SECONDS = '900';
process.env.LLM_RATE_LIMIT_PER_MINUTE = '20';
__resetLlmRateLimitForTests();
});
test('GET /healthz returns healthy response', async () => {
const app = createApp();
@@ -34,7 +41,7 @@ test('POST /core/create-signed-url returns signed URL', async () => {
.post('/core/create-signed-url')
.set('Authorization', 'Bearer test-token')
.send({
fileUri: 'gs://krow-workforce-dev-private/foo.pdf',
fileUri: 'gs://krow-workforce-dev-private/uploads/test-user/foo.pdf',
expiresInSeconds: 300,
});
@@ -44,6 +51,35 @@ test('POST /core/create-signed-url returns signed URL', async () => {
assert.equal(typeof res.body.requestId, 'string');
});
test('POST /core/create-signed-url rejects non-owned path', async () => {
const app = createApp();
const res = await request(app)
.post('/core/create-signed-url')
.set('Authorization', 'Bearer test-token')
.send({
fileUri: 'gs://krow-workforce-dev-private/uploads/other-user/foo.pdf',
expiresInSeconds: 300,
});
assert.equal(res.status, 403);
assert.equal(res.body.code, 'FORBIDDEN');
});
test('POST /core/create-signed-url enforces expiry cap', async () => {
process.env.MAX_SIGNED_URL_SECONDS = '300';
const app = createApp();
const res = await request(app)
.post('/core/create-signed-url')
.set('Authorization', 'Bearer test-token')
.send({
fileUri: 'gs://krow-workforce-dev-private/uploads/test-user/foo.pdf',
expiresInSeconds: 301,
});
assert.equal(res.status, 400);
assert.equal(res.body.code, 'VALIDATION_ERROR');
});
test('POST /invokeLLM legacy alias works', async () => {
const app = createApp();
const res = await request(app)
@@ -59,3 +95,31 @@ test('POST /invokeLLM legacy alias works', async () => {
assert.equal(typeof res.body.result, 'object');
assert.equal(typeof res.body.model, 'string');
});
test('POST /core/invoke-llm enforces per-user rate limit', async () => {
process.env.LLM_RATE_LIMIT_PER_MINUTE = '1';
const app = createApp();
const first = await request(app)
.post('/core/invoke-llm')
.set('Authorization', 'Bearer test-token')
.send({
prompt: 'hello',
responseJsonSchema: { type: 'object' },
fileUrls: [],
});
const second = await request(app)
.post('/core/invoke-llm')
.set('Authorization', 'Bearer test-token')
.send({
prompt: 'hello again',
responseJsonSchema: { type: 'object' },
fileUrls: [],
});
assert.equal(first.status, 200);
assert.equal(second.status, 429);
assert.equal(second.body.code, 'RATE_LIMITED');
assert.equal(typeof second.headers['retry-after'], 'string');
});