feat(core-api): harden signed urls and llm rate limits
This commit is contained in:
@@ -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');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user