import { test } from 'node:test'; import assert from 'node:assert/strict'; import { actorFromHeaders } from '../src/common/auth-context.js'; test('auth context keeps local explicit roles for dev', () => { const actor = actorFromHeaders({ 'x-casan-actor': 'alice', 'x-casan-role': 'project-admin', 'x-casan-project': 'okr', 'x-casan-tenant': 'tenant-a', }); assert.deepEqual(actor, { actor: 'alice', role: 'project-admin', project: 'okr', tenant: 'tenant-a' }); }); test('auth context maps IdP group claim to RBAC role', () => { const actor = actorFromHeaders({ 'x-auth-request-user': 'bob@example.com', 'x-auth-request-groups': 'engineering,casan-approver,casan-project:AINative_OKR_CASAN4', }); assert.equal(actor.actor, 'bob@example.com'); assert.equal(actor.role, 'approver'); assert.equal(actor.project, 'AINative_OKR_CASAN4'); }); test('auth context fails closed to viewer for unknown role claim', () => { const actor = actorFromHeaders({ 'x-auth-request-user': 'eve@example.com', 'x-auth-request-groups': 'unknown-admin', }); assert.equal(actor.role, 'viewer'); }); test('JWT mode rejects direct spoofed identity headers without middleware verification', () => { const prior = process.env.CASAN_CP_AUTH_MODE; process.env.CASAN_CP_AUTH_MODE = 'jwt'; try { assert.throws(() => actorFromHeaders({ 'x-casan-actor': 'attacker', 'x-casan-role': 'org-admin', }), /AUTH_VERIFIED_IDENTITY_REQUIRED/); } finally { if (prior === undefined) delete process.env.CASAN_CP_AUTH_MODE; else process.env.CASAN_CP_AUTH_MODE = prior; } });