mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 12:57:29 -08:00
test: Ensure all subworkflow execution policies are tested (#5010)
This commit is contained in:
parent
22fcc8f2be
commit
789682763c
|
@ -1,10 +1,14 @@
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { INodeTypeData, INodeTypes, Workflow } from 'n8n-workflow';
|
import { INodeTypeData, INodeTypes, SubworkflowOperationError, Workflow } from 'n8n-workflow';
|
||||||
|
|
||||||
|
import config from '@/config';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import * as testDb from '../integration/shared/testDb';
|
import * as testDb from '../integration/shared/testDb';
|
||||||
import { NodeTypes as MockNodeTypes } from './Helpers';
|
import { NodeTypes as MockNodeTypes } from './Helpers';
|
||||||
|
import { UserService } from '@/user/user.service';
|
||||||
import { PermissionChecker } from '@/UserManagement/PermissionChecker';
|
import { PermissionChecker } from '@/UserManagement/PermissionChecker';
|
||||||
|
import * as UserManagementHelper from '@/UserManagement/UserManagementHelper';
|
||||||
|
import { WorkflowsService } from '@/workflows/workflows.services';
|
||||||
import {
|
import {
|
||||||
randomCredentialPayload as randomCred,
|
randomCredentialPayload as randomCred,
|
||||||
randomPositiveDigit,
|
randomPositiveDigit,
|
||||||
|
@ -205,6 +209,163 @@ describe('PermissionChecker.check()', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('PermissionChecker.checkSubworkflowExecutePolicy', () => {
|
||||||
|
test('sets default policy from environment when subworkflow has none', async () => {
|
||||||
|
const userId = 'abcde';
|
||||||
|
config.set('workflows.callerPolicyDefaultOption', 'none');
|
||||||
|
jest.spyOn(UserManagementHelper, 'getWorkflowOwner').mockImplementation(async (workflowId) => {
|
||||||
|
return { id: userId };
|
||||||
|
});
|
||||||
|
jest.spyOn(UserManagementHelper, 'isSharingEnabled').mockReturnValue(true);
|
||||||
|
|
||||||
|
const subworkflow = new Workflow({
|
||||||
|
nodes: [],
|
||||||
|
connections: {},
|
||||||
|
active: false,
|
||||||
|
nodeTypes: MockNodeTypes(),
|
||||||
|
id: '2',
|
||||||
|
});
|
||||||
|
await expect(
|
||||||
|
PermissionChecker.checkSubworkflowExecutePolicy(subworkflow, userId, userId),
|
||||||
|
).rejects.toThrow(`Target workflow ID ${subworkflow.id} may not be called`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('if sharing is disabled, ensures that workflows are owner by same user', async () => {
|
||||||
|
const userId = 'abcde';
|
||||||
|
const fakeUser = { id: userId, firstName: 'Test', email: 'email@email.com' };
|
||||||
|
jest
|
||||||
|
.spyOn(UserManagementHelper, 'getWorkflowOwner')
|
||||||
|
.mockImplementation(async (workflowId) => fakeUser);
|
||||||
|
jest.spyOn(UserManagementHelper, 'isSharingEnabled').mockReturnValue(false);
|
||||||
|
jest.spyOn(UserService, 'get').mockImplementation(async () => fakeUser);
|
||||||
|
jest.spyOn(WorkflowsService, 'getSharing').mockImplementation(async () => {
|
||||||
|
return {
|
||||||
|
role: {
|
||||||
|
name: 'not owner',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const subworkflow = new Workflow({
|
||||||
|
nodes: [],
|
||||||
|
connections: {},
|
||||||
|
active: false,
|
||||||
|
nodeTypes: MockNodeTypes(),
|
||||||
|
id: '2',
|
||||||
|
settings: { userId: 'bcdef' },
|
||||||
|
});
|
||||||
|
await expect(
|
||||||
|
PermissionChecker.checkSubworkflowExecutePolicy(subworkflow, userId, userId),
|
||||||
|
).rejects.toThrow(`Target workflow ID ${subworkflow.id} may not be called`);
|
||||||
|
|
||||||
|
// Check description
|
||||||
|
try {
|
||||||
|
await PermissionChecker.checkSubworkflowExecutePolicy(
|
||||||
|
subworkflow,
|
||||||
|
subworkflow.settings.userId as string,
|
||||||
|
'abcde',
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof SubworkflowOperationError) {
|
||||||
|
expect(error.description).toBe(
|
||||||
|
`${fakeUser.firstName} (${fakeUser.email}) can make this change. You may need to tell them the ID of this workflow, which is ${subworkflow.id}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('list of ids must include the parent workflow id', async () => {
|
||||||
|
const userId = 'abcde';
|
||||||
|
const fakeUser = { id: userId };
|
||||||
|
jest
|
||||||
|
.spyOn(UserManagementHelper, 'getWorkflowOwner')
|
||||||
|
.mockImplementation(async (workflowId) => fakeUser);
|
||||||
|
jest.spyOn(UserManagementHelper, 'isSharingEnabled').mockReturnValue(true);
|
||||||
|
jest.spyOn(UserService, 'get').mockImplementation(async () => fakeUser);
|
||||||
|
jest.spyOn(WorkflowsService, 'getSharing').mockImplementation(async () => {
|
||||||
|
return {
|
||||||
|
role: {
|
||||||
|
name: 'not owner',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const subworkflow = new Workflow({
|
||||||
|
nodes: [],
|
||||||
|
connections: {},
|
||||||
|
active: false,
|
||||||
|
nodeTypes: MockNodeTypes(),
|
||||||
|
id: '2',
|
||||||
|
settings: {
|
||||||
|
userId: 'bcdef',
|
||||||
|
callerPolicy: 'workflowsFromAList',
|
||||||
|
callerIds: '123,456,bcdef ',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await expect(
|
||||||
|
PermissionChecker.checkSubworkflowExecutePolicy(subworkflow, userId, userId),
|
||||||
|
).rejects.toThrow(`Target workflow ID ${subworkflow.id} may not be called`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('sameOwner passes when both workflows are owned by the same user', async () => {
|
||||||
|
const userId = 'abcde';
|
||||||
|
const fakeUser = { id: userId };
|
||||||
|
jest
|
||||||
|
.spyOn(UserManagementHelper, 'getWorkflowOwner')
|
||||||
|
.mockImplementation(async (workflowId) => fakeUser);
|
||||||
|
jest.spyOn(UserManagementHelper, 'isSharingEnabled').mockReturnValue(false);
|
||||||
|
jest.spyOn(UserService, 'get').mockImplementation(async () => fakeUser);
|
||||||
|
jest.spyOn(WorkflowsService, 'getSharing').mockImplementation(async () => {
|
||||||
|
return {
|
||||||
|
role: {
|
||||||
|
name: 'owner',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const subworkflow = new Workflow({
|
||||||
|
nodes: [],
|
||||||
|
connections: {},
|
||||||
|
active: false,
|
||||||
|
nodeTypes: MockNodeTypes(),
|
||||||
|
id: '2',
|
||||||
|
settings: { userId: userId },
|
||||||
|
});
|
||||||
|
expect(PermissionChecker.checkSubworkflowExecutePolicy(subworkflow, userId, userId)).resolves;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('workflowsFromAList works when the list contains the parent id', async () => {
|
||||||
|
const userId = 'abcde';
|
||||||
|
const fakeUser = { id: userId };
|
||||||
|
jest
|
||||||
|
.spyOn(UserManagementHelper, 'getWorkflowOwner')
|
||||||
|
.mockImplementation(async (workflowId) => fakeUser);
|
||||||
|
jest.spyOn(UserManagementHelper, 'isSharingEnabled').mockReturnValue(true);
|
||||||
|
jest.spyOn(UserService, 'get').mockImplementation(async () => fakeUser);
|
||||||
|
jest.spyOn(WorkflowsService, 'getSharing').mockImplementation(async () => {
|
||||||
|
return {
|
||||||
|
role: {
|
||||||
|
name: 'not owner',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const subworkflow = new Workflow({
|
||||||
|
nodes: [],
|
||||||
|
connections: {},
|
||||||
|
active: false,
|
||||||
|
nodeTypes: MockNodeTypes(),
|
||||||
|
id: '2',
|
||||||
|
settings: {
|
||||||
|
userId: 'bcdef',
|
||||||
|
callerPolicy: 'workflowsFromAList',
|
||||||
|
callerIds: `123,456,bcdef, ${userId}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(PermissionChecker.checkSubworkflowExecutePolicy(subworkflow, userId, userId)).resolves;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const MOCK_NODE_TYPES_DATA = ['start', 'actionNetwork'].reduce<INodeTypeData>((acc, nodeName) => {
|
const MOCK_NODE_TYPES_DATA = ['start', 'actionNetwork'].reduce<INodeTypeData>((acc, nodeName) => {
|
||||||
return (
|
return (
|
||||||
(acc[`n8n-nodes-base.${nodeName}`] = {
|
(acc[`n8n-nodes-base.${nodeName}`] = {
|
||||||
|
|
Loading…
Reference in a new issue