mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
feat: check for cred when updating workflow and remove credential_usage table (#4350) (no-changelog)
* feat: check for cred when updating workflow and remove credential_usage table
This commit is contained in:
@@ -11,6 +11,7 @@ import config from '../../config';
|
||||
import type { AuthAgent, SaveCredentialFunction } from './shared/types';
|
||||
import { makeWorkflow } from './shared/utils';
|
||||
import { randomCredentialPayload } from './shared/random';
|
||||
import { INode, INodes } from 'n8n-workflow';
|
||||
|
||||
jest.mock('../../src/telemetry');
|
||||
|
||||
@@ -72,7 +73,7 @@ describe('PUT /workflows/:id', () => {
|
||||
expect(sharedWorkflows).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('PUT /workflows/:id/share should not fail when sharing with invalid user-id', async () => {
|
||||
test('PUT /workflows/:id/share should succeed when sharing with invalid user-id', async () => {
|
||||
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
@@ -218,12 +219,9 @@ describe('POST /workflows', () => {
|
||||
const response = await authAgent(owner).post('/workflows').send(workflow);
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
const usedCredentials = await testDb.getCredentialUsageInWorkflow(response.body.data.id);
|
||||
expect(usedCredentials).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('Should save credential usage when saving a new workflow', async () => {
|
||||
it('Should save a new workflow with credentials', async () => {
|
||||
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: owner });
|
||||
@@ -235,9 +233,6 @@ describe('POST /workflows', () => {
|
||||
const response = await authAgent(owner).post('/workflows').send(workflow);
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
const usedCredentials = await testDb.getCredentialUsageInWorkflow(response.body.data.id);
|
||||
expect(usedCredentials).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('Should not allow saving a workflow using credential you have no access', async () => {
|
||||
@@ -273,8 +268,6 @@ describe('POST /workflows', () => {
|
||||
const response = await authAgent(owner).post('/workflows').send(workflow);
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
const usedCredentials = await testDb.getCredentialUsageInWorkflow(response.body.data.id);
|
||||
expect(usedCredentials).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('Should allow saving a workflow using a credential owned by others and shared with you', async () => {
|
||||
@@ -291,7 +284,162 @@ describe('POST /workflows', () => {
|
||||
|
||||
const response = await authAgent(member2).post('/workflows').send(workflow);
|
||||
expect(response.statusCode).toBe(200);
|
||||
const usedCredentials = await testDb.getCredentialUsageInWorkflow(response.body.data.id);
|
||||
expect(usedCredentials).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PATCH /workflows/:id', () => {
|
||||
it('Should succeed when saving unchanged workflow nodes', async () => {
|
||||
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: owner });
|
||||
const workflow = await createWorkflow(
|
||||
{
|
||||
nodes: [
|
||||
{
|
||||
id: 'uuid-1234',
|
||||
name: 'Start',
|
||||
parameters: {},
|
||||
position: [-20, 260],
|
||||
type: 'n8n-nodes-base.start',
|
||||
typeVersion: 1,
|
||||
credentials: {
|
||||
default: {
|
||||
id: savedCredential.id.toString(),
|
||||
name: savedCredential.name,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
owner,
|
||||
);
|
||||
|
||||
const response = await authAgent(owner).patch(`/workflows/${workflow.id}`).send({
|
||||
name: 'new name',
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
});
|
||||
|
||||
it('Should allow owner to add node containing credential not shared with the owner', async () => {
|
||||
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
const member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: member });
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
const response = await authAgent(owner)
|
||||
.patch(`/workflows/${workflow.id}`)
|
||||
.send({
|
||||
nodes: [
|
||||
{
|
||||
id: 'uuid-1234',
|
||||
name: 'Start',
|
||||
parameters: {},
|
||||
position: [-20, 260],
|
||||
type: 'n8n-nodes-base.start',
|
||||
typeVersion: 1,
|
||||
credentials: {
|
||||
default: {
|
||||
id: savedCredential.id.toString(),
|
||||
name: savedCredential.name,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
});
|
||||
|
||||
it('Should prevent member from adding node containing credential inaccessible to member', async () => {
|
||||
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
const member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: owner });
|
||||
const workflow = await createWorkflow({}, member);
|
||||
|
||||
const response = await authAgent(member)
|
||||
.patch(`/workflows/${workflow.id}`)
|
||||
.send({
|
||||
nodes: [
|
||||
{
|
||||
id: 'uuid-1234',
|
||||
name: 'Start',
|
||||
parameters: {},
|
||||
position: [-20, 260],
|
||||
type: 'n8n-nodes-base.start',
|
||||
typeVersion: 1,
|
||||
credentials: {},
|
||||
},
|
||||
{
|
||||
id: 'uuid-12345',
|
||||
name: 'Start',
|
||||
parameters: {},
|
||||
position: [-20, 260],
|
||||
type: 'n8n-nodes-base.start',
|
||||
typeVersion: 1,
|
||||
credentials: {
|
||||
default: {
|
||||
id: savedCredential.id.toString(),
|
||||
name: savedCredential.name,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(400);
|
||||
});
|
||||
|
||||
it('Should succeed but prevent modifying nodes that are read-only for the requester', async () => {
|
||||
const member1 = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const member2 = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: member1 });
|
||||
|
||||
const originalNodes: INode[] = [
|
||||
{
|
||||
id: 'uuid-1234',
|
||||
name: 'Start',
|
||||
parameters: {},
|
||||
position: [-20, 260],
|
||||
type: 'n8n-nodes-base.start',
|
||||
typeVersion: 1,
|
||||
credentials: {
|
||||
default: {
|
||||
id: savedCredential.id.toString(),
|
||||
name: savedCredential.name,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const changedNodes: INode[] = [
|
||||
{
|
||||
id: 'uuid-1234',
|
||||
name: 'End',
|
||||
parameters: {},
|
||||
position: [-20, 260],
|
||||
type: 'n8n-nodes-base.no-op',
|
||||
typeVersion: 1,
|
||||
credentials: {
|
||||
default: {
|
||||
id: '200',
|
||||
name: 'fake credential',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const workflow = await createWorkflow({ nodes: originalNodes }, member1);
|
||||
await testDb.shareWorkflowWithUsers(workflow, [member2]);
|
||||
|
||||
const response = await authAgent(member2).patch(`/workflows/${workflow.id}`).send({
|
||||
nodes: changedNodes,
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body.data.nodes).toMatchObject(originalNodes);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user