-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cu 86c0bkuxc add a mechanism to migrate users from the old roles to new rbac roles #1234
base: master
Are you sure you want to change the base?
Changes from all commits
813d610
25f97ff
b6a944b
8653852
5d5c178
70d5447
424337a
1c6a39d
304e8f4
2977c06
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -13,9 +13,11 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||
KeystoreModel, | ||||||||||||||||||||||||||||||||||||||||||||||
PassportModel, | ||||||||||||||||||||||||||||||||||||||||||||||
UserModel, | ||||||||||||||||||||||||||||||||||||||||||||||
VisualizerModel | ||||||||||||||||||||||||||||||||||||||||||||||
VisualizerModel, | ||||||||||||||||||||||||||||||||||||||||||||||
RoleModel, | ||||||||||||||||||||||||||||||||||||||||||||||
ChannelModel, | ||||||||||||||||||||||||||||||||||||||||||||||
roles | ||||||||||||||||||||||||||||||||||||||||||||||
} from '../../src/model' | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
describe('Upgrade DB Tests', () => { | ||||||||||||||||||||||||||||||||||||||||||||||
const originalUpgradeFuncs = [...upgradeDB.upgradeFuncs] | ||||||||||||||||||||||||||||||||||||||||||||||
upgradeDB.upgradeFuncs.length = 0 | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -546,4 +548,94 @@ describe('Upgrade DB Tests', () => { | |||||||||||||||||||||||||||||||||||||||||||||
passports.length.should.eql(2) | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
describe(`updateFunction4 - Create default roles with permissions`, () => { | ||||||||||||||||||||||||||||||||||||||||||||||
const upgradeFunc = originalUpgradeFuncs[4].func | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
beforeEach(async () => { | ||||||||||||||||||||||||||||||||||||||||||||||
await RoleModel.deleteMany({}) | ||||||||||||||||||||||||||||||||||||||||||||||
await ChannelModel.deleteMany({}) | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
afterEach(async () => { | ||||||||||||||||||||||||||||||||||||||||||||||
await RoleModel.deleteMany({}) | ||||||||||||||||||||||||||||||||||||||||||||||
await ChannelModel.deleteMany({}) | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
it('should create default roles if they do not exist', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||
await upgradeFunc() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const existingRoles = await RoleModel.find() | ||||||||||||||||||||||||||||||||||||||||||||||
existingRoles.length.should.be.exactly(Object.keys(roles).length) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const roleNames = existingRoles.map(r => r.name) | ||||||||||||||||||||||||||||||||||||||||||||||
Object.keys(roles).forEach(roleName => { | ||||||||||||||||||||||||||||||||||||||||||||||
roleNames.should.containEql(roleName) | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+569
to
+574
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid variable shadowing of 'roles' variable The local variable To improve clarity and prevent any unintended behavior, consider renaming the local variables. Here's an example: - const existingRoles = await RoleModel.find()
- existingRoles.length.should.be.exactly(Object.keys(roles).length)
- const roleNames = existingRoles.map(r => r.name)
- Object.keys(roles).forEach(roleName => {
+ const defaultRoleNames = Object.keys(roles)
+ existingRoles.length.should.be.exactly(defaultRoleNames.length)
+ const roleNames = existingRoles.map(r => r.name)
+ defaultRoleNames.forEach(roleName => {
roleNames.should.containEql(roleName)
}) This change avoids confusion between the imported
|
||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+565
to
+575
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid variable shadowing of 'roles' The local variable To improve clarity and prevent any unintended behavior, consider renaming the variables: - const existingRoles = await RoleModel.find()
- existingRoles.length.should.be.exactly(Object.keys(roles).length)
+ const createdRoles = await RoleModel.find()
+ createdRoles.length.should.be.exactly(Object.keys(roles).length)
- const roleNames = existingRoles.map(r => r.name)
+ const createdRoleNames = createdRoles.map(r => r.name)
- Object.keys(roles).forEach(roleName => {
+ Object.keys(roles).forEach(defaultRoleName => {
- roleNames.should.containEql(roleName)
+ createdRoleNames.should.containEql(defaultRoleName)
}) This change avoids confusion between the imported 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
it('should not create duplicate roles if they already exist', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||
await new RoleModel({name: 'admin', permissions: {}}).save() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
await upgradeFunc() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const existingRoles = await RoleModel.find() | ||||||||||||||||||||||||||||||||||||||||||||||
existingRoles.length.should.be.exactly(Object.keys(roles).length) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const adminRoles = existingRoles.filter(r => r.name === 'admin') | ||||||||||||||||||||||||||||||||||||||||||||||
adminRoles.length.should.be.exactly(1) | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
it('should set correct permissions for each role', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||
// Create test channels | ||||||||||||||||||||||||||||||||||||||||||||||
const channel1 = await new ChannelModel({ | ||||||||||||||||||||||||||||||||||||||||||||||
name: 'Channel 1', | ||||||||||||||||||||||||||||||||||||||||||||||
urlPattern: '/channel1', | ||||||||||||||||||||||||||||||||||||||||||||||
allow: ['admin', 'manager'], | ||||||||||||||||||||||||||||||||||||||||||||||
txViewAcl: ['admin'], | ||||||||||||||||||||||||||||||||||||||||||||||
txRerunAcl: ['admin'], | ||||||||||||||||||||||||||||||||||||||||||||||
txViewFullAcl: ['admin'] | ||||||||||||||||||||||||||||||||||||||||||||||
}).save() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const channel2 = await new ChannelModel({ | ||||||||||||||||||||||||||||||||||||||||||||||
name: 'Channel 2', | ||||||||||||||||||||||||||||||||||||||||||||||
urlPattern: '/channel2', | ||||||||||||||||||||||||||||||||||||||||||||||
allow: ['admin', 'manager', 'operator'], | ||||||||||||||||||||||||||||||||||||||||||||||
txViewAcl: ['admin', 'manager', 'operator'], | ||||||||||||||||||||||||||||||||||||||||||||||
txRerunAcl: ['admin'], | ||||||||||||||||||||||||||||||||||||||||||||||
txViewFullAcl: ['admin'] | ||||||||||||||||||||||||||||||||||||||||||||||
}).save() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
await upgradeFunc() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
const createdRoles = await RoleModel.find() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
for (const role of createdRoles) { | ||||||||||||||||||||||||||||||||||||||||||||||
should.exist(role) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// Check default permissions | ||||||||||||||||||||||||||||||||||||||||||||||
if (roles[role.name]) { | ||||||||||||||||||||||||||||||||||||||||||||||
Object.entries(roles[role.name].permissions).forEach(([key, value]) => { | ||||||||||||||||||||||||||||||||||||||||||||||
should(role.permissions[key]).eql(value) | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// Check channel-specific permissions | ||||||||||||||||||||||||||||||||||||||||||||||
if (role.name === 'admin') { | ||||||||||||||||||||||||||||||||||||||||||||||
role.permissions['transaction-view-specified'].should.containEql('Channel 1') | ||||||||||||||||||||||||||||||||||||||||||||||
role.permissions['transaction-view-specified'].should.containEql('Channel 2') | ||||||||||||||||||||||||||||||||||||||||||||||
role.permissions['transaction-rerun-specified'].should.containEql('Channel 1') | ||||||||||||||||||||||||||||||||||||||||||||||
role.permissions['transaction-rerun-specified'].should.containEql('Channel 2') | ||||||||||||||||||||||||||||||||||||||||||||||
role.permissions['transaction-view-body-specified'].should.containEql('Channel 1') | ||||||||||||||||||||||||||||||||||||||||||||||
role.permissions['transaction-view-body-specified'].should.containEql('Channel 2') | ||||||||||||||||||||||||||||||||||||||||||||||
} else if (role.name === 'manager') { | ||||||||||||||||||||||||||||||||||||||||||||||
role.permissions['transaction-view-specified'].should.not.containEql('Channel 1') | ||||||||||||||||||||||||||||||||||||||||||||||
role.permissions['transaction-view-specified'].should.containEql('Channel 2') | ||||||||||||||||||||||||||||||||||||||||||||||
} else if (role.name === 'operator') { | ||||||||||||||||||||||||||||||||||||||||||||||
role.permissions['transaction-view-specified'].should.not.containEql('Channel 1') | ||||||||||||||||||||||||||||||||||||||||||||||
role.permissions['transaction-view-specified'].should.containEql('Channel 2') | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+589
to
+639
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance test robustness and coverage The test case is comprehensive, but consider the following improvements:
afterEach(async () => {
await RoleModel.deleteMany({})
await ChannelModel.deleteMany({})
})
const channelPermissions = {
'Channel 1': {
view: ['admin'],
rerun: ['admin'],
viewBody: ['admin']
},
'Channel 2': {
view: ['admin', 'manager', 'operator'],
rerun: ['admin'],
viewBody: ['admin']
}
}
for (const role of createdRoles) {
for (const [channelName, permissions] of Object.entries(channelPermissions)) {
for (const [action, allowedRoles] of Object.entries(permissions)) {
const permissionKey = `transaction-${action}-specified`
if (allowedRoles.includes(role.name)) {
role.permissions[permissionKey].should.containEql(channelName)
} else {
role.permissions[permissionKey].should.not.containEql(channelName)
}
}
}
}
for (const [roleName, roleData] of Object.entries(roles)) {
const createdRole = createdRoles.find(r => r.name === roleName)
should.exist(createdRole, `Role ${roleName} should exist`)
Object.entries(roleData.permissions).forEach(([key, value]) => {
should(createdRole.permissions[key]).eql(value, `Permission ${key} for role ${roleName} should match`)
})
} These changes will make the test more robust, easier to maintain, and ensure complete coverage of all defined roles and their permissions. |
||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unnecessary check and LGTM for ACL processing
The ACL processing logic is well-structured and correctly maps ACL types to corresponding permission types. However, there's an unnecessary check that can be removed:
The
Array.isArray(channel.allow)
check is not used in the subsequent logic and can be safely removed.📝 Committable suggestion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the allow array holds the groups/roles allowed to access a channel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@drizzentic, thank you for the clarification. You're right, the
channel.allow
array holds the groups/roles allowed to access a channel, so theArray.isArray(channel.allow)
check is necessary to ensure proper handling of channel permissions. I appreciate your explanation.🐰🤔
✏️ Learnings added