Add admin identity module: better-auth, per-app permissions, invitations (#12)
Jenkins Production Deployment
Jenkins Production Deployment
Reviewed-on: #12 Co-authored-by: Patrick Müller <mail@pmueller.me> Co-committed-by: Patrick Müller <mail@pmueller.me>
This commit was merged in pull request #12.
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import {describe, expect, it} from 'vitest';
|
||||
import {
|
||||
ACCESS_ROLE,
|
||||
appsOf,
|
||||
isAppPermission,
|
||||
isAppRole,
|
||||
toPermissions
|
||||
} from '../../src/models/admin/admin.schema.js';
|
||||
|
||||
/**
|
||||
* The permission model is (app, role). These tests pin the two properties the
|
||||
* rest of the module leans on: that the older `['tickets']` shape still means
|
||||
* "tickets at the access role", and that nothing outside APP_ROLES gets in.
|
||||
*/
|
||||
|
||||
describe('toPermissions', () => {
|
||||
it('reads the full (app, role) form', () => {
|
||||
expect(toPermissions([{app: 'tickets', role: 'access'}])).toEqual([
|
||||
{app: 'tickets', role: 'access'}
|
||||
]);
|
||||
});
|
||||
|
||||
it('reads a plain app list as that app at the access role', () => {
|
||||
expect(toPermissions(['feedback', 'admin'])).toEqual([
|
||||
{app: 'feedback', role: ACCESS_ROLE},
|
||||
{app: 'admin', role: ACCESS_ROLE}
|
||||
]);
|
||||
});
|
||||
|
||||
it('accepts the two forms mixed, which is what a half-migrated caller sends', () => {
|
||||
expect(toPermissions(['feedback', {app: 'tickets', role: 'access'}])).toEqual([
|
||||
{app: 'feedback', role: ACCESS_ROLE},
|
||||
{app: 'tickets', role: ACCESS_ROLE}
|
||||
]);
|
||||
});
|
||||
|
||||
it('drops duplicates of the same (app, role)', () => {
|
||||
expect(toPermissions(['tickets', {app: 'tickets', role: 'access'}])).toEqual([
|
||||
{app: 'tickets', role: ACCESS_ROLE}
|
||||
]);
|
||||
});
|
||||
|
||||
it('rejects rather than silently dropping an unknown app', () => {
|
||||
// Silently ignoring it would let "grant calendar + nonsense" look like a
|
||||
// success while granting less than the caller asked for.
|
||||
expect(toPermissions(['calendar', 'nonsense'])).toBeNull();
|
||||
});
|
||||
|
||||
it('rejects an unknown role', () => {
|
||||
expect(toPermissions([{app: 'tickets', role: 'refund'}])).toBeNull();
|
||||
});
|
||||
|
||||
it('rejects anything that is not a list', () => {
|
||||
expect(toPermissions('admin')).toBeNull();
|
||||
expect(toPermissions(null)).toBeNull();
|
||||
expect(toPermissions({app: 'admin', role: 'access'})).toBeNull();
|
||||
});
|
||||
|
||||
it('reads an empty list as "no permissions", not as invalid', () => {
|
||||
expect(toPermissions([])).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAppRole', () => {
|
||||
it('accepts the access role for every app', () => {
|
||||
expect(isAppRole('admin', ACCESS_ROLE)).toBe(true);
|
||||
expect(isAppRole('calendar', ACCESS_ROLE)).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects a role that does not exist yet', () => {
|
||||
expect(isAppRole('tickets', 'refund')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAppPermission', () => {
|
||||
it('needs both halves to be valid', () => {
|
||||
expect(isAppPermission({app: 'tickets', role: ACCESS_ROLE})).toBe(true);
|
||||
expect(isAppPermission({app: 'tickets'})).toBe(false);
|
||||
expect(isAppPermission({role: ACCESS_ROLE})).toBe(false);
|
||||
expect(isAppPermission(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('appsOf', () => {
|
||||
it('collapses several roles on one app to a single entry', () => {
|
||||
// The point of the derived list: a user with two roles on tickets has
|
||||
// access to tickets once, not twice.
|
||||
const apps = appsOf([
|
||||
{app: 'tickets', role: ACCESS_ROLE},
|
||||
{app: 'tickets', role: 'future-role'},
|
||||
{app: 'admin', role: ACCESS_ROLE}
|
||||
]);
|
||||
expect(apps).toEqual(['tickets', 'admin']);
|
||||
});
|
||||
|
||||
it('is empty for no permissions', () => {
|
||||
expect(appsOf([])).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user