BillTracker/tests/securityCoverage.test.js

74 lines
2.7 KiB
JavaScript
Raw Permalink Normal View History

'use strict';
// Security invariant: every API router mount is either explicitly public or carries
// requireAuth (+ CSRF for authenticated routers). This is a static guard so a new
// route added without auth/CSRF fails CI instead of silently exposing data.
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const server = fs.readFileSync(path.join(__dirname, '..', 'server.cts'), 'utf8');
// Routers that are intentionally public (or handle their own auth internally).
const PUBLIC_ROUTERS = new Set([
'auth', // login/register/csrf-token are public; authed sub-routes guard themselves
'authOidc', // OIDC login/callback are public entry points
'calendarFeed', // token-authenticated ICS feed (no session)
'about', // public marketing/info
'privacy', // public policy
'version', // public version / release-notes / update-status
]);
// Match: app.use('<path>', <middleware...>, require('./routes/<file>.cts'))
const mountRe =
/app\.use\(\s*['"](\/api\/[^'"]+)['"]([\s\S]*?)require\(\s*['"]\.\/routes\/([A-Za-z0-9_-]+)\.cts['"]\s*\)/g;
const mounts = [];
for (let m; (m = mountRe.exec(server));) {
mounts.push({ path: m[1], middleware: m[2], router: m[3] });
}
test('server.cts mounts are discoverable', () => {
assert.ok(mounts.length >= 20, `expected many router mounts, found ${mounts.length}`);
});
test('every non-public router mount requires authentication', () => {
const offenders = mounts
.filter((m) => !PUBLIC_ROUTERS.has(m.router))
.filter((m) => !/requireAuth/.test(m.middleware))
.map((m) => `${m.path} → routes/${m.router}.cts`);
assert.deepEqual(
offenders,
[],
`router mounts missing requireAuth:\n ${offenders.join('\n ')}`,
);
});
test('every authenticated router mount enforces CSRF', () => {
const offenders = mounts
.filter((m) => !PUBLIC_ROUTERS.has(m.router))
.filter((m) => !/csrfMiddleware/.test(m.middleware))
.map((m) => `${m.path} → routes/${m.router}.cts`);
assert.deepEqual(
offenders,
[],
`authed router mounts missing csrfMiddleware:\n ${offenders.join('\n ')}`,
);
});
test('admin router mounts require admin', () => {
const adminMounts = mounts.filter(
(m) => m.path.startsWith('/api/admin') || m.router === 'aboutAdmin' || m.router === 'status',
);
assert.ok(adminMounts.length >= 1, 'expected at least one admin mount');
const offenders = adminMounts
.filter((m) => !/requireAdmin/.test(m.middleware))
.map((m) => `${m.path} → routes/${m.router}.cts`);
assert.deepEqual(
offenders,
[],
`admin mounts missing requireAdmin:\n ${offenders.join('\n ')}`,
);
});