fix: migrate legacy admin role to granular roles at startup
Some checks failed
CI / lint (pull_request) Has been cancelled
CI / typecheck (pull_request) Has been cancelled
CI / test (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
CI / package (pull_request) Has been cancelled

- Add migrateAdminRole() that runs on mcpd boot
- Converts { role: 'admin', resource: X } → edit + run bindings
- Adds operation bindings for wildcard admin (impersonate, logs, etc.)
- Add tests verifying unknown/legacy roles are denied by canAccess

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Michal
2026-02-23 11:31:15 +00:00
parent 50b4112398
commit ec1dfe7438
2 changed files with 93 additions and 0 deletions

View File

@@ -680,4 +680,52 @@ describe('RbacService', () => {
expect(perms).toEqual([]);
});
});
describe('unknown/legacy roles are denied', () => {
let service: RbacService;
beforeEach(() => {
const repo = mockRepo([
makeDef({
roleBindings: [{ role: 'admin', resource: '*' }],
}),
]);
const prisma = mockPrisma({
user: { findUnique: vi.fn(async () => ({ email: 'alice@example.com' })) },
groupMember: { findMany: vi.fn(async () => []) },
});
service = new RbacService(repo, prisma);
});
it('denies view when only legacy admin role exists', async () => {
expect(await service.canAccess('user-1', 'view', 'servers')).toBe(false);
});
it('denies create when only legacy admin role exists', async () => {
expect(await service.canAccess('user-1', 'create', 'servers')).toBe(false);
});
it('denies edit when only legacy admin role exists', async () => {
expect(await service.canAccess('user-1', 'edit', 'servers')).toBe(false);
});
it('denies delete when only legacy admin role exists', async () => {
expect(await service.canAccess('user-1', 'delete', 'servers')).toBe(false);
});
it('denies any made-up role', async () => {
const repo = mockRepo([
makeDef({
roleBindings: [{ role: 'superuser', resource: 'servers' }],
}),
]);
const prisma = mockPrisma({
user: { findUnique: vi.fn(async () => ({ email: 'alice@example.com' })) },
groupMember: { findMany: vi.fn(async () => []) },
});
const svc = new RbacService(repo, prisma);
expect(await svc.canAccess('user-1', 'view', 'servers')).toBe(false);
expect(await svc.canAccess('user-1', 'edit', 'servers')).toBe(false);
});
});
});