mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-17 13:39:44 +02:00
fix(API): Let global members grant folder scopes to API keys (#37654)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
418f85e9eb
commit
aa91e71893
|
|
@ -212,6 +212,11 @@ export const API_KEY_SCOPES_FOR_IMPLICIT_PERSONAL_PROJECT: ApiKeyScope[] = [
|
|||
'dataTableRow:update',
|
||||
'dataTableRow:delete',
|
||||
'dataTableRow:upsert',
|
||||
'folder:create',
|
||||
'folder:delete',
|
||||
'folder:read',
|
||||
'folder:update',
|
||||
'folder:list',
|
||||
'dataTableColumn:create',
|
||||
'dataTableColumn:read',
|
||||
'dataTableColumn:update',
|
||||
|
|
|
|||
|
|
@ -144,5 +144,27 @@ describe('PublicApiKeyService', () => {
|
|||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should let a member grant folder scopes, which apply to their own projects', async () => {
|
||||
// Arrange
|
||||
const folderScopes: ApiKeyScope[] = [
|
||||
'folder:create',
|
||||
'folder:read',
|
||||
'folder:update',
|
||||
'folder:delete',
|
||||
'folder:list',
|
||||
];
|
||||
|
||||
// Act
|
||||
const result = publicApiKeyService.apiKeyHasValidScopesForRole(
|
||||
{
|
||||
role: GLOBAL_MEMBER_ROLE,
|
||||
},
|
||||
folderScopes,
|
||||
);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -507,6 +507,24 @@ describe('Member', () => {
|
|||
expect(newApiKeyResponse.statusCode).toBe(400);
|
||||
});
|
||||
|
||||
test('POST /api-keys should create an api key with folder scopes', async () => {
|
||||
const folderScopes: ApiKeyScope[] = [
|
||||
'folder:create',
|
||||
'folder:read',
|
||||
'folder:update',
|
||||
'folder:delete',
|
||||
'folder:list',
|
||||
];
|
||||
|
||||
const newApiKeyResponse = await testServer
|
||||
.authAgentFor(member)
|
||||
.post('/api-keys')
|
||||
.send({ label: 'My API Key', expiresAt: null, scopes: folderScopes })
|
||||
.expect(200);
|
||||
|
||||
expect(newApiKeyResponse.body.data.scopes).toEqual(folderScopes);
|
||||
});
|
||||
|
||||
test('GET /api-keys should fetch the api key redacted', async () => {
|
||||
const expirationDateInTheFuture = Date.now() + 1000;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import * as utils from '../shared/utils/';
|
|||
let owner: User;
|
||||
let member: User;
|
||||
let ownerPersonalProject: Project;
|
||||
let memberPersonalProject: Project;
|
||||
let authOwnerAgent: SuperAgentTest;
|
||||
let authMemberAgent: SuperAgentTest;
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ beforeEach(async () => {
|
|||
};
|
||||
|
||||
ownerPersonalProject = await createPersonalProject(owner);
|
||||
await createPersonalProject(member);
|
||||
memberPersonalProject = await createPersonalProject(member);
|
||||
|
||||
authOwnerAgent = testServer.publicApiAgentFor(owner);
|
||||
authMemberAgent = testServer.publicApiAgentFor(member);
|
||||
|
|
@ -295,6 +296,18 @@ describe('GET /projects/:projectId/folders', () => {
|
|||
expect(response.body.data).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('should list folders in their own personal project when user is a member', async () => {
|
||||
testServer.license.enable('feat:folders');
|
||||
|
||||
await createFolder(memberPersonalProject, { name: 'Member Folder' });
|
||||
|
||||
const response = await authMemberAgent.get(`/projects/${memberPersonalProject.id}/folders`);
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body.count).toBe(1);
|
||||
expect(response.body.data).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should list folders in a team project when user is a member', async () => {
|
||||
testServer.license.enable('feat:folders');
|
||||
testServer.license.setQuota('quota:maxTeamProjects', -1);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user