Files
stack/packages/webui/tests/workspace-http.test.mjs

30 lines
2.3 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { requestHTTP, REQUEST_ROUTE } from '../src/request-http.mjs';
const session = { name: 'owner', provider: 'test', iss: 'test', sub: 'owner' };
const reply = { available: true, entries: [{ name: 'src/app.js' }], truncated: false, contentAvailable: false, observedAt: '2026-11-05T00:00:00.000Z' };
async function attempt({ path = '/api/requests/r1/workspace', url = path, method = 'GET', read = async () => reply, live = () => session, headersDistinct = {} } = {}) {
const req = { url, method, headersDistinct }, res = { writeHead(status, headers) { this.status = status; this.headers = headers; }, end(data) { this.body = data; } };
await requestHTTP(req, res, { path, session, live, requestRead: read, origin: 'https://console.test', log() {} }); return res;
}
test('owner workspace GET sends only the request identifier and validates result', async () => {
let call;
const res = await attempt({ read: async (...args) => { call = args; return reply; } });
assert.equal(res.status, 200); assert.deepEqual(call[0], 'request.workspace.console'); assert.deepEqual(call[1], { request: 'r1' });
assert.equal(res.headers['cache-control'], 'no-store');
assert.equal((await attempt({ read: async () => ({ ...reply, entries: [{ name: '../secret' }] }) })).status, 503);
assert.equal((await attempt({ read: async () => ({ ...reply, entries: Array(101).fill({ name: 'x' }) }) })).status, 503);
assert.equal((await attempt({ read: async () => ({ ...reply, path: '/etc' }) })).status, 503);
});
test('workspace route refuses traversal, other modes, query, foreign origin and stale session', async () => {
assert.equal((await attempt({ path: '/api/requests/%2e%2e/workspace' })).status, 404);
assert.equal((await attempt({ url: '/api/requests/r1/workspace?path=..' })).status, 400);
assert.equal((await attempt({ method: 'POST' })).status, 405);
assert.equal((await attempt({ headersDistinct: { origin: ['https://evil.test'] } })).status, 403);
let reads = 0;
assert.equal((await attempt({ read: async () => { reads++; return reply; }, live: () => reads ? null : session })).status, 401);
assert.doesNotMatch('/api/requests/r1/workspace/a/text', REQUEST_ROUTE);
assert.doesNotMatch('/api/requests/r1/workspace/a/download', REQUEST_ROUTE);
});