-
-
Notifications
You must be signed in to change notification settings - Fork 730
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Cherry pick the fix merged in #8084 Co-authored-by: Fredrik Strand Oseberg <[email protected]>
- Loading branch information
1 parent
b7301dc
commit 36e780b
Showing
7 changed files
with
247 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ lerna-debug | |
npm-debug | ||
.DS_Store | ||
/dist | ||
.vscode | ||
|
||
# Logs | ||
logs | ||
|
121 changes: 121 additions & 0 deletions
121
src/lib/features/project/can-grant-project-role.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import { canGrantProjectRole } from './can-grant-project-role'; | ||
|
||
describe('canGrantProjectRole', () => { | ||
test('should return true if the granter has all the permissions the receiver needs', () => { | ||
const granterPermissions = [ | ||
{ | ||
project: 'test', | ||
environment: undefined, | ||
permission: 'CREATE_FEATURE', | ||
}, | ||
{ | ||
project: 'test', | ||
environment: 'production', | ||
permission: 'UPDATE_FEATURE_ENVIRONMENT', | ||
}, | ||
{ | ||
project: 'test', | ||
environment: 'production', | ||
permission: 'APPROVE_CHANGE_REQUEST', | ||
}, | ||
]; | ||
|
||
const receiverPermissions = [ | ||
{ | ||
id: 28, | ||
name: 'UPDATE_FEATURE_ENVIRONMENT', | ||
environment: 'production', | ||
displayName: 'Enable/disable flags', | ||
type: 'environment', | ||
}, | ||
{ | ||
id: 29, | ||
name: 'APPROVE_CHANGE_REQUEST', | ||
environment: 'production', | ||
displayName: 'Enable/disable flags', | ||
type: 'environment', | ||
}, | ||
]; | ||
|
||
canGrantProjectRole(granterPermissions, receiverPermissions); | ||
}); | ||
|
||
test('should return false if the granter and receiver permissions have different environments', () => { | ||
const granterPermissions = [ | ||
{ | ||
project: 'test', | ||
environment: 'production', | ||
permission: 'UPDATE_FEATURE_ENVIRONMENT', | ||
}, | ||
{ | ||
project: 'test', | ||
environment: 'production', | ||
permission: 'APPROVE_CHANGE_REQUEST', | ||
}, | ||
]; | ||
|
||
const receiverPermissions = [ | ||
{ | ||
id: 28, | ||
name: 'UPDATE_FEATURE_ENVIRONMENT', | ||
environment: 'development', | ||
displayName: 'Enable/disable flags', | ||
type: 'environment', | ||
}, | ||
{ | ||
id: 29, | ||
name: 'APPROVE_CHANGE_REQUEST', | ||
environment: 'development', | ||
displayName: 'Enable/disable flags', | ||
type: 'environment', | ||
}, | ||
]; | ||
|
||
expect( | ||
canGrantProjectRole(granterPermissions, receiverPermissions), | ||
).toBeFalsy(); | ||
}); | ||
|
||
test('should return false if the granter does not have all receiver permissions', () => { | ||
const granterPermissions = [ | ||
{ | ||
project: 'test', | ||
environment: 'production', | ||
permission: 'UPDATE_FEATURE_ENVIRONMENT', | ||
}, | ||
{ | ||
project: 'test', | ||
environment: 'production', | ||
permission: 'APPROVE_CHANGE_REQUEST', | ||
}, | ||
]; | ||
|
||
const receiverPermissions = [ | ||
{ | ||
id: 28, | ||
name: 'UPDATE_FEATURE_ENVIRONMENT', | ||
environment: 'production', | ||
displayName: 'Enable/disable flags', | ||
type: 'environment', | ||
}, | ||
{ | ||
id: 29, | ||
name: 'APPROVE_CHANGE_REQUEST', | ||
environment: 'production', | ||
displayName: 'Enable/disable flags', | ||
type: 'environment', | ||
}, | ||
{ | ||
id: 26, | ||
name: 'UPDATE_FEATURE_STRATEGY', | ||
environment: 'production', | ||
displayName: 'Update activation strategies', | ||
type: 'environment', | ||
}, | ||
]; | ||
|
||
expect( | ||
canGrantProjectRole(granterPermissions, receiverPermissions), | ||
).toBeFalsy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import type { IPermission } from '../../types'; | ||
import type { IUserPermission } from '../../types/stores/access-store'; | ||
|
||
export const canGrantProjectRole = ( | ||
granterPermissions: IUserPermission[], | ||
receiverPermissions: IPermission[], | ||
) => { | ||
return receiverPermissions.every((receiverPermission) => { | ||
return granterPermissions.some((granterPermission) => { | ||
if (granterPermission.environment) { | ||
return ( | ||
granterPermission.permission === receiverPermission.name && | ||
granterPermission.environment === | ||
receiverPermission.environment | ||
); | ||
} | ||
|
||
return granterPermission.permission === receiverPermission.name; | ||
}); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -772,72 +772,92 @@ describe('Managing Project access', () => { | |
), | ||
); | ||
}); | ||
test('Users can not assign roles they do not have to a user through explicit roles endpoint', async () => { | ||
|
||
test('Users can not assign roles where they do not hold the same permissions', async () => { | ||
const project = { | ||
id: 'user_fail_assign_to_user', | ||
name: 'user_fail_assign_to_user', | ||
description: '', | ||
mode: 'open' as const, | ||
defaultStickiness: 'clientId', | ||
}; | ||
|
||
const auditUser = extractAuditInfoFromUser(user); | ||
await projectService.createProject(project, user, auditUser); | ||
const projectUser = await stores.userStore.insert({ | ||
name: 'Some project user', | ||
email: '[email protected]', | ||
}); | ||
const projectAuditUser = extractAuditInfoFromUser(projectUser); | ||
const secondUser = await stores.userStore.insert({ | ||
name: 'Some other user', | ||
email: '[email protected]', | ||
}); | ||
const customRole = await stores.roleStore.create({ | ||
name: 'role_that_noone_has', | ||
roleType: 'custom', | ||
description: | ||
'Used to prove that you can not assign a role you do not have via setRolesForUser', | ||
}); | ||
|
||
const customRoleUserAccess = await accessService.createRole( | ||
{ | ||
name: 'Project-permissions-lead', | ||
description: 'Role', | ||
permissions: [ | ||
{ | ||
name: 'PROJECT_USER_ACCESS_WRITE', | ||
}, | ||
], | ||
createdByUserId: SYSTEM_USER_ID, | ||
}, | ||
SYSTEM_USER_AUDIT, | ||
); | ||
|
||
const customRoleUpdateEnvironments = await accessService.createRole( | ||
{ | ||
name: 'Project Lead', | ||
description: 'Role', | ||
permissions: [ | ||
{ | ||
name: 'UPDATE_FEATURE_ENVIRONMENT', | ||
environment: 'production', | ||
}, | ||
{ | ||
name: 'CREATE_FEATURE_STRATEGY', | ||
environment: 'production', | ||
}, | ||
], | ||
createdByUserId: SYSTEM_USER_ID, | ||
}, | ||
SYSTEM_USER_AUDIT, | ||
); | ||
|
||
await projectService.setRolesForUser( | ||
project.id, | ||
projectUser.id, | ||
[customRoleUserAccess.id], | ||
auditUser, | ||
); | ||
|
||
const auditProjectUser = extractAuditInfoFromUser(projectUser); | ||
|
||
await expect( | ||
projectService.setRolesForUser( | ||
project.id, | ||
secondUser.id, | ||
[customRole.id], | ||
projectAuditUser, | ||
[customRoleUpdateEnvironments.id], | ||
auditProjectUser, | ||
), | ||
).rejects.toThrow( | ||
new InvalidOperationError( | ||
'User tried to assign a role they did not have access to', | ||
), | ||
); | ||
}); | ||
test('Users can not assign roles they do not have to a group through explicit roles endpoint', async () => { | ||
const project = { | ||
id: 'user_fail_assign_to_group', | ||
name: 'user_fail_assign_to_group', | ||
description: '', | ||
mode: 'open' as const, | ||
defaultStickiness: 'clientId', | ||
}; | ||
await projectService.createProject(project, user, auditUser); | ||
const projectUser = await stores.userStore.insert({ | ||
name: 'Some project user', | ||
email: '[email protected]', | ||
}); | ||
const projectAuditUser = extractAuditInfoFromUser(projectUser); | ||
|
||
const group = await stores.groupStore.create({ | ||
name: 'Some group_awaiting_role', | ||
}); | ||
const customRole = await stores.roleStore.create({ | ||
name: 'role_that_noone_has_fail_assign_group', | ||
roleType: 'custom', | ||
description: | ||
'Used to prove that you can not assign a role you do not have via setRolesForGroup', | ||
}); | ||
return expect( | ||
|
||
await expect( | ||
projectService.setRolesForGroup( | ||
project.id, | ||
group.id, | ||
[customRole.id], | ||
projectAuditUser, | ||
[customRoleUpdateEnvironments.id], | ||
auditProjectUser, | ||
), | ||
).rejects.toThrow( | ||
new InvalidOperationError( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.