-
-
Notifications
You must be signed in to change notification settings - Fork 723
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
chore: improve access service #4689
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 2 Ignored Deployments
|
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.
Makes sense to me 🤷
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.
Seems reasonable.
await accessService.addPermissionToRole( | ||
role.id, | ||
builtInRole.id, |
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 test is adding a permission to the builtInRole, something that is not possible because of some validations at the service layer. Because the test is also creating a new role, I have the impression that the intention of the test is not to use the builtin role but the newly created one.
); | ||
} else { | ||
// this branch uses id 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.
This is the reason why we're making this change, we want to be able to use names instead of ids for permissions
id: joi.number(), | ||
name: joi.string(), |
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.
This validation now expects that either you provide the id or the name (or both)
src/lib/db/access-store.ts
Outdated
environment: permissions.find( | ||
(p) => p.name === (row.permission as string), | ||
)?.environment, |
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.
I don't like the performance of this... a find inside a map is not ideal
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.
Is it a problem? O(n*m) isn't an issue when n and m are small. Should be easy enough to build a Map earlier in the function and get O(1) lookups
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.
Exactly what I had in mind
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.
Assume positive intentions here, I'm struggling with formulating the question.
Why are we fetching ids again? Wasn't the goal to change to names as the primary key?
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.
Wasn't the goal to change to names as the primary key?
Yes, but our OpenAPI spec states that ids are required while names are optional. Adding the name as required is a breaking change having to wait until the next major release. I think because of this reason we can't drop support for id's (customers might be using them already).
On another note, I think I solved the n*m problem with a map
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.
I think this is correct, we can trade off some performance for correctness for a while. When we make a breaking change we can clean this up
A lot changed since this review
// use for debugging only, try not to commit tests with verbose set to true | ||
noLoggerProvider.setVerbose = (beVerbose: boolean) => { | ||
verbose = beVerbose; | ||
}; | ||
|
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.
Unrelated, but I thought it might be useful
req.user = await userService.createUser({ | ||
email: '[email protected]', | ||
rootRole: role.id, | ||
}); |
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.
I've refactored this method, not sure what we were trying to do here:
- Get Viewer built-in role
- Create a user A
- Create a new role "token creator" without permissions
- Add CREATE_PROJECT permission to the Viewer role (shouldn't be possible to add permissions programmatically)
- Add user A to the "token creator role" in project 'default' (now A has the root role Viewer and "token creator role" in 'default')
- Create a new user B with root role Viewer (that now has the new permission)
- Associate req.user to the newly created user B
Then the test tries to create an API token using the newly created user B.
Why did we take all those efforts to setup user A if we're not using it in the test? Apparently the only important steps are the ones in bold. At least taking into account the title of the test: A role with only CREATE_PROJECT_API_TOKEN can create project tokens
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.
Guessing copy paste bug. Something something don't trust tests you haven't seen fail
email: '[email protected]', | ||
rootRole: role.id, | ||
}); | ||
req.user = user; |
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.
On this side:
- Get viewer role
- Create a user with Viewer role as root role
- Create a new role with CREATE_PROJECT_API_TOKEN permission
- Add the user to the role created in
default
project - Associate
req.user
to the user created
Later we validate if this user can create an API token in the project where they have the role with that specific permission
async (permissions) => { | ||
const access = db.stores.accessStore as AccessStore; | ||
const result = await access.resolvePermissions(permissions); | ||
expect(result).toStrictEqual(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.
I'd love to say: no query to the DB here
const rows = await this.db | ||
.select('id', 'permission') | ||
.from(T.PERMISSIONS) | ||
.whereIn('permission', permissionNames); |
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.
Same query as here: https://github.com/Unleash/unleash/pull/4689/files#diff-5cb4eca71e6a03ec3d123986d657368a3386f80e986dfef2e3feb0abb0673d87L706-L709 but now it can be used in all scenarios of adding permissions to a role
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.
LGTM, I think with the tests and timers this is good enough to try
This reverts commit 2186e2b.
Reverts #4689 temporarily to figure out what's the problem with the failing test
## About the changes In #4689 I forgot to add backward compatibility for a public method that was being used in Enterprise.
About the changes
This enables us to use names instead of permission ids across all our APIs at the computational cost of searching for the ids in the DB but improving the API user experience
Open topics
We're using methods that are test-only and circumvent our business logic. This makes our test to rely on assumptions that are not always true because these assumptions are not validated frequently.
i.e. We are expecting that after removing a permission it's no longer there, but to test this, the permission has to be there before:
unleash/src/test/e2e/services/access-service.e2e.test.ts
Lines 367 to 375 in 78273e4
But it seems that's not the case.
We'll look into improving this later.