Pure-function module that mirrors crates/manager-core/src/authz.rs and lets dashboard pages decide which create / edit / delete affordances to render. Widens the vitest include so the truth-table test runs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import type { AppRole, MeDto } from './api';
|
|
import { canAdminApp, canCreateApp, canManageUsers, canWriteApp } from './capabilities';
|
|
|
|
function me(role: MeDto['instance_role']): MeDto {
|
|
return { id: 'u', username: 'u', instance_role: role, email: null };
|
|
}
|
|
|
|
const ROLES: MeDto['instance_role'][] = ['owner', 'admin', 'member'];
|
|
const APP_ROLES: (AppRole | null)[] = ['app_admin', 'editor', 'viewer', null];
|
|
|
|
describe('capabilities', () => {
|
|
it('null caller is denied everything', () => {
|
|
expect(canCreateApp(null)).toBe(false);
|
|
expect(canManageUsers(null)).toBe(false);
|
|
expect(canWriteApp(null, 'app_admin')).toBe(false);
|
|
expect(canAdminApp(null, 'app_admin')).toBe(false);
|
|
});
|
|
|
|
it('canCreateApp + canManageUsers: owner/admin yes, member no', () => {
|
|
expect(canCreateApp(me('owner'))).toBe(true);
|
|
expect(canCreateApp(me('admin'))).toBe(true);
|
|
expect(canCreateApp(me('member'))).toBe(false);
|
|
expect(canManageUsers(me('owner'))).toBe(true);
|
|
expect(canManageUsers(me('admin'))).toBe(true);
|
|
expect(canManageUsers(me('member'))).toBe(false);
|
|
});
|
|
|
|
it('owner + admin can write and admin every app regardless of my_role', () => {
|
|
for (const role of ['owner', 'admin'] as const) {
|
|
for (const appRole of APP_ROLES) {
|
|
expect(canWriteApp(me(role), appRole)).toBe(true);
|
|
expect(canAdminApp(me(role), appRole)).toBe(true);
|
|
}
|
|
}
|
|
});
|
|
|
|
it('member: write requires app_admin or editor; admin requires app_admin', () => {
|
|
const m = me('member');
|
|
expect(canWriteApp(m, 'app_admin')).toBe(true);
|
|
expect(canWriteApp(m, 'editor')).toBe(true);
|
|
expect(canWriteApp(m, 'viewer')).toBe(false);
|
|
expect(canWriteApp(m, null)).toBe(false);
|
|
|
|
expect(canAdminApp(m, 'app_admin')).toBe(true);
|
|
expect(canAdminApp(m, 'editor')).toBe(false);
|
|
expect(canAdminApp(m, 'viewer')).toBe(false);
|
|
expect(canAdminApp(m, null)).toBe(false);
|
|
});
|
|
|
|
it('canAdminApp implies canWriteApp for every combination', () => {
|
|
for (const role of ROLES) {
|
|
for (const appRole of APP_ROLES) {
|
|
if (canAdminApp(me(role), appRole)) {
|
|
expect(canWriteApp(me(role), appRole)).toBe(true);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|