96 lines
2.7 KiB
TypeScript
96 lines
2.7 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import type { AuditInput } from '../db/browser-session-repo.js';
|
|
import { assertProfileOwner } from './browser-session-auth.js';
|
|
|
|
interface FakeRepo {
|
|
audit: (input: AuditInput) => void;
|
|
rows: AuditInput[];
|
|
}
|
|
|
|
function makeFakeRepo(): FakeRepo {
|
|
const rows: AuditInput[] = [];
|
|
return {
|
|
rows,
|
|
audit(input: AuditInput) {
|
|
rows.push(input);
|
|
},
|
|
};
|
|
}
|
|
|
|
describe('assertProfileOwner — fail-closed owner enforcement', () => {
|
|
let fake: FakeRepo;
|
|
|
|
beforeEach(() => {
|
|
fake = makeFakeRepo();
|
|
});
|
|
|
|
it('passes when job.ownerId equals profile.ownerId', () => {
|
|
expect(() =>
|
|
assertProfileOwner(
|
|
{ id: 7, ownerId: 'user-a' },
|
|
{ id: 'job-1', ownerId: 'user-a' },
|
|
fake,
|
|
),
|
|
).not.toThrow();
|
|
expect(fake.rows.length).toBe(0);
|
|
});
|
|
|
|
it('throws and audits when job.ownerId is null (legacy / dev-mode jobs)', () => {
|
|
expect(() =>
|
|
assertProfileOwner(
|
|
{ id: 7, ownerId: 'user-a' },
|
|
{ id: 'job-1', ownerId: null },
|
|
fake,
|
|
),
|
|
).toThrow('Browser session profile owner mismatch');
|
|
expect(fake.rows).toHaveLength(1);
|
|
expect(fake.rows[0]).toMatchObject({
|
|
actorUserId: null,
|
|
ownerId: 'user-a',
|
|
profileId: 7,
|
|
action: 'use',
|
|
result: 'error',
|
|
jobId: 'job-1',
|
|
});
|
|
expect(fake.rows[0]!.reason).toContain('job.owner=null');
|
|
expect(fake.rows[0]!.reason).toContain('profile.owner=user-a');
|
|
});
|
|
|
|
it('throws and audits when job.ownerId is undefined', () => {
|
|
expect(() =>
|
|
assertProfileOwner(
|
|
{ id: 7, ownerId: 'user-a' },
|
|
{ id: 'job-2', ownerId: undefined },
|
|
fake,
|
|
),
|
|
).toThrow('Browser session profile owner mismatch');
|
|
expect(fake.rows).toHaveLength(1);
|
|
expect(fake.rows[0]!.reason).toContain('job.owner=null');
|
|
});
|
|
|
|
it('throws and audits when job.ownerId is empty string', () => {
|
|
expect(() =>
|
|
assertProfileOwner(
|
|
{ id: 7, ownerId: 'user-a' },
|
|
{ id: 'job-3', ownerId: '' },
|
|
fake,
|
|
),
|
|
).toThrow('Browser session profile owner mismatch');
|
|
expect(fake.rows).toHaveLength(1);
|
|
});
|
|
|
|
it('throws and audits when job.ownerId differs from profile.ownerId', () => {
|
|
expect(() =>
|
|
assertProfileOwner(
|
|
{ id: 9, ownerId: 'user-a' },
|
|
{ id: 'job-4', ownerId: 'user-b' },
|
|
fake,
|
|
),
|
|
).toThrow('Browser session profile owner mismatch');
|
|
expect(fake.rows).toHaveLength(1);
|
|
expect(fake.rows[0]!.reason).toContain('job.owner=user-b');
|
|
expect(fake.rows[0]!.reason).toContain('profile.owner=user-a');
|
|
expect(fake.rows[0]!.actorUserId).toBe('user-b');
|
|
});
|
|
});
|