fix: When editing nodes only show the credentials in the dropdown that the user is allowed to use in that workflow (#9718)

This commit is contained in:
Danny Martini
2024-06-14 14:48:49 +02:00
committed by GitHub
parent 2dad9ce44c
commit 2cf4364ee0
16 changed files with 682 additions and 22 deletions

View File

@@ -30,6 +30,7 @@ import {
import type { SuperAgentTest } from '../shared/types';
import { mockInstance } from '../../shared/mocking';
import { createTeamProject, linkUserToProject } from '../shared/db/projects';
import { createWorkflow, shareWorkflowWithUsers } from '@test-integration/db/workflows';
const testServer = utils.setupTestServer({
endpointGroups: ['credentials'],
@@ -243,6 +244,256 @@ describe('GET /credentials', () => {
});
});
describe('GET /credentials/for-workflow', () => {
describe('for team projects', () => {
test.each([
['workflowId', 'member', () => member],
['projectId', 'member', () => member],
['workflowId', 'owner', () => owner],
['projectId', 'owner', () => owner],
])(
'it will only return the credentials in that project if "%s" is used as the query parameter and the actor is a "%s"',
async (_, queryParam, actorGetter) => {
const actor = actorGetter();
// Credential in personal project that should not be returned
await saveCredential(randomCredentialPayload(), { user: actor });
const teamProject = await createTeamProject();
await linkUserToProject(actor, teamProject, 'project:viewer');
const savedCredential = await saveCredential(randomCredentialPayload(), {
project: teamProject,
});
const savedWorkflow = await createWorkflow({}, teamProject);
{
const response = await testServer
.authAgentFor(actor)
.get('/credentials/for-workflow')
.query(
queryParam === 'workflowId'
? { workflowId: savedWorkflow.id }
: { projectId: teamProject.id },
);
expect(response.statusCode).toBe(200);
expect(response.body.data).toHaveLength(1);
expect(response.body.data).toContainEqual(
expect.objectContaining({
id: savedCredential.id,
scopes: expect.arrayContaining(['credential:read']),
}),
);
}
},
);
});
describe('for personal projects', () => {
test.each(['projectId', 'workflowId'])(
'it returns only personal credentials for a members, if "%s" is used as the query parameter',
async (queryParam) => {
const savedWorkflow = await createWorkflow({}, member);
await shareWorkflowWithUsers(savedWorkflow, [anotherMember]);
// should be returned respectively
const savedCredential = await saveCredential(randomCredentialPayload(), { user: member });
const anotherSavedCredential = await saveCredential(randomCredentialPayload(), {
user: anotherMember,
});
// should not be returned
await saveCredential(randomCredentialPayload(), { user: owner });
const teamProject = await createTeamProject();
await saveCredential(randomCredentialPayload(), { project: teamProject });
// member should only see their credential
{
const response = await testServer
.authAgentFor(member)
.get('/credentials/for-workflow')
.query(
queryParam === 'workflowId'
? { workflowId: savedWorkflow.id }
: { projectId: memberPersonalProject.id },
);
expect(response.statusCode).toBe(200);
expect(response.body.data).toHaveLength(1);
expect(response.body.data).toContainEqual(
expect.objectContaining({
id: savedCredential.id,
scopes: expect.arrayContaining(['credential:read']),
}),
);
}
// another member should only see their credential
{
const response = await testServer
.authAgentFor(anotherMember)
.get('/credentials/for-workflow')
.query(
queryParam === 'workflowId'
? { workflowId: savedWorkflow.id }
: { projectId: anotherMemberPersonalProject.id },
);
expect(response.statusCode).toBe(200);
expect(response.body.data).toHaveLength(1);
expect(response.body.data).toContainEqual(
expect.objectContaining({
id: anotherSavedCredential.id,
scopes: expect.arrayContaining(['credential:read']),
}),
);
}
},
);
test('if the actor is a global owner and the workflow has not been shared with them, it returns all credentials of all projects the workflow is part of', async () => {
const memberWorkflow = await createWorkflow({}, member);
await shareWorkflowWithUsers(memberWorkflow, [owner]);
// should be returned
const memberCredential = await saveCredential(randomCredentialPayload(), { user: member });
const ownerCredential = await saveCredential(randomCredentialPayload(), { user: owner });
// should not be returned
await saveCredential(randomCredentialPayload(), { user: anotherMember });
const teamProject = await createTeamProject();
await saveCredential(randomCredentialPayload(), { project: teamProject });
const response = await testServer
.authAgentFor(owner)
.get('/credentials/for-workflow')
.query({ workflowId: memberWorkflow.id });
expect(response.statusCode).toBe(200);
expect(response.body.data).toHaveLength(2);
expect(response.body.data).toContainEqual(
expect.objectContaining({
id: memberCredential.id,
scopes: expect.arrayContaining(['credential:read']),
}),
);
expect(response.body.data).toContainEqual(
expect.objectContaining({
id: ownerCredential.id,
scopes: expect.arrayContaining(['credential:read']),
}),
);
});
test('if the actor is a global owner and the workflow has been shared with them, it returns all credentials of all projects the workflow is part of', async () => {
const memberWorkflow = await createWorkflow({}, member);
await shareWorkflowWithUsers(memberWorkflow, [anotherMember]);
// should be returned
const memberCredential = await saveCredential(randomCredentialPayload(), { user: member });
const anotherMemberCredential = await saveCredential(randomCredentialPayload(), {
user: anotherMember,
});
// should not be returned
await saveCredential(randomCredentialPayload(), { user: owner });
const teamProject = await createTeamProject();
await saveCredential(randomCredentialPayload(), { project: teamProject });
const response = await testServer
.authAgentFor(owner)
.get('/credentials/for-workflow')
.query({ workflowId: memberWorkflow.id });
expect(response.statusCode).toBe(200);
expect(response.body.data).toHaveLength(2);
expect(response.body.data).toContainEqual(
expect.objectContaining({
id: memberCredential.id,
scopes: expect.arrayContaining(['credential:read']),
}),
);
expect(response.body.data).toContainEqual(
expect.objectContaining({
id: anotherMemberCredential.id,
scopes: expect.arrayContaining(['credential:read']),
}),
);
});
test('if the projectId is passed by a global owner it will return all credentials in that project', async () => {
// should be returned
const memberCredential = await saveCredential(randomCredentialPayload(), { user: member });
// should not be returned
await saveCredential(randomCredentialPayload(), { user: anotherMember });
await saveCredential(randomCredentialPayload(), { user: owner });
const teamProject = await createTeamProject();
await saveCredential(randomCredentialPayload(), { project: teamProject });
const response = await testServer
.authAgentFor(owner)
.get('/credentials/for-workflow')
.query({ projectId: memberPersonalProject.id });
expect(response.statusCode).toBe(200);
expect(response.body.data).toHaveLength(1);
expect(response.body.data).toContainEqual(
expect.objectContaining({
id: memberCredential.id,
scopes: expect.arrayContaining(['credential:read']),
}),
);
});
test.each(['workflowId', 'projectId'] as const)(
'if the global owner owns the workflow it will return all credentials of all personal projects, when using "%s" as the query parameter',
async (queryParam) => {
const ownerWorkflow = await createWorkflow({}, owner);
// should be returned
const memberCredential = await saveCredential(randomCredentialPayload(), { user: member });
const anotherMemberCredential = await saveCredential(randomCredentialPayload(), {
user: anotherMember,
});
const ownerCredential = await saveCredential(randomCredentialPayload(), { user: owner });
// should not be returned
const teamProject = await createTeamProject();
await saveCredential(randomCredentialPayload(), { project: teamProject });
const response = await testServer
.authAgentFor(owner)
.get('/credentials/for-workflow')
.query(
queryParam === 'workflowId'
? { workflowId: ownerWorkflow.id }
: { projectId: ownerPersonalProject.id },
);
expect(response.statusCode).toBe(200);
expect(response.body.data).toHaveLength(3);
expect(response.body.data).toContainEqual(
expect.objectContaining({
id: memberCredential.id,
scopes: expect.arrayContaining(['credential:read']),
}),
);
expect(response.body.data).toContainEqual(
expect.objectContaining({
id: anotherMemberCredential.id,
scopes: expect.arrayContaining(['credential:read']),
}),
);
expect(response.body.data).toContainEqual(
expect.objectContaining({
id: ownerCredential.id,
scopes: expect.arrayContaining(['credential:read']),
}),
);
},
);
});
});
// ----------------------------------------
// GET /credentials/:id - fetch a certain credential
// ----------------------------------------