feat(editor): Add routing middleware, permission checks, RBAC store, RBAC component (#7702)
Github issue / Community forum post (link here to close automatically): --------- Co-authored-by: Csaba Tuncsik <csaba@n8n.io>
This commit is contained in:
152
packages/editor-ui/src/stores/__tests__/rbac.store.test.ts
Normal file
152
packages/editor-ui/src/stores/__tests__/rbac.store.test.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
import { useRBACStore } from '@/stores/rbac.store';
|
||||
import type { Scope } from '@n8n/permissions';
|
||||
import { hasScope } from '@n8n/permissions';
|
||||
|
||||
vi.mock('@n8n/permissions', async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||
const { hasScope } = await vi.importActual<typeof import('@n8n/permissions')>('@n8n/permissions');
|
||||
return {
|
||||
hasScope: vi.fn().mockImplementation(hasScope),
|
||||
};
|
||||
});
|
||||
|
||||
describe('RBAC store', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia());
|
||||
});
|
||||
|
||||
describe('addGlobalScope()', () => {
|
||||
it('should add global scope', () => {
|
||||
const newScope = 'example:list' as Scope;
|
||||
const rbacStore = useRBACStore();
|
||||
rbacStore.addGlobalScope(newScope);
|
||||
expect(rbacStore.globalScopes).toContain(newScope);
|
||||
});
|
||||
|
||||
it('should not add global scope if it already exists', () => {
|
||||
const newScope = 'example:list' as Scope;
|
||||
const rbacStore = useRBACStore();
|
||||
rbacStore.addGlobalScope(newScope);
|
||||
rbacStore.addGlobalScope(newScope);
|
||||
expect(rbacStore.globalScopes.filter((scope) => scope === newScope)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addProjectScope()', () => {
|
||||
it('should add project scope', () => {
|
||||
const newScope = 'example:list' as Scope;
|
||||
const rbacStore = useRBACStore();
|
||||
rbacStore.addProjectScope(newScope, { projectId: '1' });
|
||||
expect(rbacStore.scopesByProjectId['1']).toContain(newScope);
|
||||
});
|
||||
|
||||
it('should not add project scope if it already exists', () => {
|
||||
const newScope = 'example:list' as Scope;
|
||||
const rbacStore = useRBACStore();
|
||||
rbacStore.addProjectScope(newScope, { projectId: '1' });
|
||||
rbacStore.addProjectScope(newScope, { projectId: '1' });
|
||||
expect(rbacStore.scopesByProjectId['1'].filter((scope) => scope === newScope)).toHaveLength(
|
||||
1,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addResourceScope()', () => {
|
||||
it('should add resource scope', () => {
|
||||
const newScope = 'example:list' as Scope;
|
||||
const rbacStore = useRBACStore();
|
||||
rbacStore.addResourceScope(newScope, { resourceId: '1', resourceType: 'variable' });
|
||||
expect(rbacStore.scopesByResourceId['variable']['1']).toContain(newScope);
|
||||
});
|
||||
|
||||
it('should not add resource scope if it already exists', () => {
|
||||
const newScope = 'example:list' as Scope;
|
||||
const rbacStore = useRBACStore();
|
||||
rbacStore.addResourceScope(newScope, { resourceId: '1', resourceType: 'variable' });
|
||||
rbacStore.addResourceScope(newScope, { resourceId: '1', resourceType: 'variable' });
|
||||
expect(
|
||||
rbacStore.scopesByResourceId['variable']['1'].filter((scope) => scope === newScope),
|
||||
).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasScope()', () => {
|
||||
it('evaluates global scope correctly', () => {
|
||||
const newScope = 'example:list' as Scope;
|
||||
const store = useRBACStore();
|
||||
store.addGlobalScope(newScope);
|
||||
|
||||
const result = store.hasScope(newScope, {});
|
||||
expect(result).toBe(true);
|
||||
expect(vi.mocked(hasScope)).toHaveBeenCalledWith(
|
||||
newScope,
|
||||
{
|
||||
global: expect.arrayContaining([newScope]),
|
||||
project: [],
|
||||
resource: [],
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it('evaluates project scope correctly', () => {
|
||||
const newScope = 'example:list' as Scope;
|
||||
const store = useRBACStore();
|
||||
store.addProjectScope(newScope, { projectId: '1' });
|
||||
|
||||
const result = store.hasScope(newScope, { projectId: '1' });
|
||||
expect(result).toBe(true);
|
||||
expect(vi.mocked(hasScope)).toHaveBeenCalledWith(
|
||||
newScope,
|
||||
{
|
||||
global: expect.any(Array),
|
||||
project: expect.arrayContaining([newScope]),
|
||||
resource: [],
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it('evaluates resource scope correctly', () => {
|
||||
const newScope = 'example:list' as Scope;
|
||||
const store = useRBACStore();
|
||||
store.addResourceScope(newScope, { resourceId: '1', resourceType: 'variable' });
|
||||
|
||||
const result = store.hasScope(newScope, { resourceId: '1', resourceType: 'variable' });
|
||||
expect(result).toBe(true);
|
||||
expect(vi.mocked(hasScope)).toHaveBeenCalledWith(
|
||||
newScope,
|
||||
{
|
||||
global: expect.any(Array),
|
||||
project: [],
|
||||
resource: expect.arrayContaining([newScope]),
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it('evaluates project and resource scope correctly', () => {
|
||||
const newScope = 'example:list' as Scope;
|
||||
const store = useRBACStore();
|
||||
store.addProjectScope(newScope, { projectId: '1' });
|
||||
store.addResourceScope(newScope, { resourceId: '1', resourceType: 'variable' });
|
||||
|
||||
const result = store.hasScope(newScope, {
|
||||
projectId: '1',
|
||||
resourceId: '1',
|
||||
resourceType: 'variable',
|
||||
});
|
||||
expect(result).toBe(true);
|
||||
expect(vi.mocked(hasScope)).toHaveBeenCalledWith(
|
||||
newScope,
|
||||
{
|
||||
global: expect.any(Array),
|
||||
project: expect.arrayContaining([newScope]),
|
||||
resource: expect.arrayContaining([newScope]),
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user