Files
bface/test/api-filters.test.js
Amer Agovic 859db6ccb2 Release 1.0.8 with platform, security, and UI hardening.
Adds API filter registry, style theme registry, SW bitmask cache clear, KV namespacing, session expiry checks, accessibility improvements, and expanded test coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-10 21:08:21 -05:00

121 lines
3.7 KiB
JavaScript

import { beforeEach, describe, test } from 'node:test';
import assert from 'node:assert';
import {
applyRequestAuthorization,
createAPIFilterRegistry,
normalizeRequestAuthorization
} from '../src/platform/api-filters.js';
import {
SECURITY_REQUEST_FILTER,
createSecurityRequestFilter
} from '../src/security/runtime/api-auth.js';
describe('api-filters', () => {
/** @type {ReturnType<typeof createAPIFilterRegistry>} */
let registry;
beforeEach(() => {
registry = createAPIFilterRegistry();
});
test('normalizeRequestAuthorization supports string, scheme/token, and custom headers', () => {
assert.deepStrictEqual(
normalizeRequestAuthorization('Bearer abc'),
{ name: 'Authorization', value: 'Bearer abc' }
);
assert.deepStrictEqual(
normalizeRequestAuthorization({ scheme: 'Basic', token: 'dXNlcjpwYXNz' }),
{ name: 'Authorization', value: 'Basic dXNlcjpwYXNz' }
);
assert.deepStrictEqual(
normalizeRequestAuthorization({ name: 'X-Api-Key', value: 'secret' }),
{ name: 'X-Api-Key', value: 'secret' }
);
});
test('applyRequestFilters runs in priority order and supports async filters', async () => {
const calls = [];
registry.registerRequestFilter('second', async (ctx) => {
calls.push('second');
return {
...ctx,
headers: applyRequestAuthorization(ctx.headers, { name: 'X-Second', value: '2' })
};
}, { priority: 20 });
registry.registerRequestFilter('first', async (ctx) => {
calls.push('first');
return {
...ctx,
headers: applyRequestAuthorization(ctx.headers, { name: 'X-First', value: '1' })
};
}, { priority: 10 });
const result = await registry.applyRequestFilters({
url: '/api/items',
endpoint: '/items',
headers: new Headers()
});
assert.deepStrictEqual(calls, ['first', 'second']);
assert.strictEqual(result.headers.get('X-First'), '1');
assert.strictEqual(result.headers.get('X-Second'), '2');
});
test('skipRequestFilters can skip named filters', async () => {
registry.registerRequestFilter('tenant', (ctx) => ({
...ctx,
headers: applyRequestAuthorization(ctx.headers, { name: 'X-Tenant', value: 'acme' })
}), { priority: 10 });
registry.registerRequestFilter('auth', (ctx) => ({
...ctx,
headers: applyRequestAuthorization(ctx.headers, { scheme: 'Bearer', token: 'token' })
}), { priority: 100 });
const result = await registry.applyRequestFilters({
url: '/api/login',
endpoint: '/login',
headers: new Headers(),
skipRequestFilters: ['auth']
});
assert.strictEqual(result.headers.get('X-Tenant'), 'acme');
assert.strictEqual(result.headers.get('Authorization'), null);
});
test('security request filter delegates authorization to the active policy', async () => {
const securityService = {
state: {
enabled: true,
provider: 'basic',
isAuthenticated: true,
session: { jwt_token: 'ignored-if-policy-returns' },
user: { id: 'user-1' },
profile: null,
realm: null,
config: {},
policy: {
async getRequestAuthorization() {
return { name: 'X-Api-Key', value: 'policy-key' };
}
}
}
};
const result = await createSecurityRequestFilter(securityService)({
url: '/api/items',
endpoint: '/items',
headers: new Headers()
});
assert.strictEqual(result.headers.get('X-Api-Key'), 'policy-key');
assert.strictEqual(result.headers.get('Authorization'), null);
});
test('installable security filter id is stable', () => {
assert.strictEqual(SECURITY_REQUEST_FILTER, 'security.auth');
});
});