-
Notifications
You must be signed in to change notification settings - Fork 894
fix: ensure user admins can always see users table #15226
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
Merged
Merged
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
1ad09fa
refactor: update layout so that sidebar always shows
Parkreiner 620bd3a
refactor: consolidate logic more
Parkreiner 7ee3cf0
fix: add redirect for base users
Parkreiner e889621
fix: update routing logic to not block on disabled queries
Parkreiner 36e0376
fix: update type misalignment
Parkreiner 032a75c
chore: format and tidy up
Parkreiner eea8bbd
fix: make sure you can't navigate directly to bare /deployment page
Parkreiner e6d4201
fix: add more granularity to redirect logic
Parkreiner 14fc68e
fix: prevent infinite redirect
Parkreiner a8fd9e6
fix: update redirects for /organizations routes
Parkreiner 0a36cd1
fix: format files
Parkreiner e6d772b
fix: tighten up types for permissions
Parkreiner 3752af5
Merge branch 'main' into mes/deploy-bug
Parkreiner 2068a4c
fix: update route checks to account for subroutes
Parkreiner 2fe3d53
fix: add e2e check to ensure that redirect hasn't happened
Parkreiner 3c41de0
fix: update stories to account for new dashboard logic
Parkreiner 162642e
fix: update out-of-date comment
Parkreiner 64c6f29
fix: update default value logic for storybook setup
Parkreiner e12a4aa
fix: update individual stories
Parkreiner b9b33c0
fix: finish storybook injection changes
Parkreiner f7df5ff
fix: add back separate empty state to satisfy tests
Parkreiner 6925294
fix: add tests and update code to account for missing cases
Parkreiner 9fc0afa
fix: apply formatting
Parkreiner 498e7ba
break out `DeploymentSettingsProvider`
aslilac 234c606
fix: apply changes from previous PR
Parkreiner 4496a75
fix: apply formatting
Parkreiner 9fcf3e7
Merge branch 'main' into mes/deploy-bug
Parkreiner 19fb6e5
Merge branch 'lilac/deployment-settings-provider' into mes/deploy-bug
Parkreiner 804255e
fix: delete invalid tests
Parkreiner d341175
fix: revert changes not caught in merge
Parkreiner f3e6659
fix: update spellcheck
Parkreiner ce67a66
fix: revert nits
Parkreiner 7e946a7
fix: apply feedback
Parkreiner File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
fix: add tests and update code to account for missing cases
- Loading branch information
commit 6925294dd0576e82f050d21e15e3628103fd1d41
There are no files selected for viewing
188 changes: 188 additions & 0 deletions
188
site/src/modules/management/ManagementSettingsLayout.test.ts
This file contains hidden or 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,188 @@ | ||
import type { Permissions } from "contexts/auth/permissions"; | ||
import { isManagementRoutePermitted } from "./ManagementSettingsLayout"; | ||
import { MockNoPermissions, MockPermissions } from "testHelpers/entities"; | ||
import { Permission } from "api/typesGenerated"; | ||
|
||
describe(isManagementRoutePermitted.name, () => { | ||
describe("General behavior", () => { | ||
it("Rejects malformed routes", () => { | ||
const invalidRoutes: readonly string[] = [ | ||
// It's expected that the hostname will be stripped off | ||
"https://dev.coder.com/deployment/licenses/add", | ||
|
||
// Missing the leading / | ||
"organizations", | ||
]; | ||
|
||
for (const r of invalidRoutes) { | ||
} | ||
|
||
// Currently only checking whether route ends with / | ||
const invalidRoute = "organizations"; | ||
expect( | ||
isManagementRoutePermitted(invalidRoute, MockPermissions, true), | ||
).toBe(false); | ||
}); | ||
}); | ||
|
||
describe("Organization routes", () => { | ||
it("Delegates to showOrganizations value for any /organizations routes", () => { | ||
expect( | ||
isManagementRoutePermitted("/organizations", MockNoPermissions, true), | ||
).toBe(true); | ||
|
||
expect( | ||
isManagementRoutePermitted( | ||
"/organizations/nested/arbitrarily", | ||
MockNoPermissions, | ||
true, | ||
), | ||
).toBe(true); | ||
|
||
expect( | ||
isManagementRoutePermitted( | ||
"/organizations/sample-organization", | ||
MockNoPermissions, | ||
true, | ||
), | ||
).toBe(true); | ||
|
||
expect( | ||
isManagementRoutePermitted("/organizations", MockPermissions, false), | ||
).toBe(false); | ||
}); | ||
}); | ||
|
||
describe("Deployment routes", () => { | ||
it("Will never let the user through if they have no active permissions", () => { | ||
let result = isManagementRoutePermitted( | ||
"/deployment", | ||
MockNoPermissions, | ||
true, | ||
); | ||
expect(result).toBe(false); | ||
|
||
result = isManagementRoutePermitted( | ||
"/deployment/licenses", | ||
MockNoPermissions, | ||
true, | ||
); | ||
expect(result).toBe(false); | ||
|
||
result = isManagementRoutePermitted( | ||
"/deployment/appearance", | ||
MockNoPermissions, | ||
false, | ||
); | ||
expect(result).toBe(false); | ||
}); | ||
|
||
it("Will let users access base /deployment route if they have at least one permission", () => { | ||
const mocks: readonly Permissions[] = [ | ||
MockPermissions, | ||
{ | ||
...MockNoPermissions, | ||
createGroup: true, | ||
}, | ||
{ | ||
...MockNoPermissions, | ||
createOrganization: true, | ||
deleteTemplates: true, | ||
}, | ||
{ | ||
...MockNoPermissions, | ||
editDeploymentValues: true, | ||
viewNotificationTemplate: true, | ||
readWorkspaceProxies: true, | ||
}, | ||
]; | ||
|
||
for (const m of mocks) { | ||
expect(isManagementRoutePermitted("/deployment", m, true)).toBe(true); | ||
expect(isManagementRoutePermitted("/deployment", m, false)).toBe(true); | ||
} | ||
}); | ||
|
||
it("Rejects unknown deployment routes", () => { | ||
const sampleRoutes: readonly string[] = [ | ||
"/deployment/definitely-not-right", | ||
"/deployment/what-is-this", | ||
]; | ||
|
||
for (const r of sampleRoutes) { | ||
const result = isManagementRoutePermitted(r, MockPermissions, true); | ||
expect(result).toBe(false); | ||
} | ||
}); | ||
|
||
it("Supports deployment routes that are nested more than one level", () => { | ||
const routes: readonly string[] = [ | ||
"/deployment/licenses/add", | ||
|
||
// Including oauth2-provider routes, even though they're not | ||
// currently exposed via the UI | ||
"/deployment/oauth2-provider/apps", | ||
"/deployment/oauth2-provider/apps/add", | ||
]; | ||
|
||
for (const r of routes) { | ||
let result = isManagementRoutePermitted(r, MockPermissions, true); | ||
expect(result).toBe(true); | ||
|
||
result = isManagementRoutePermitted(r, MockPermissions, false); | ||
expect(result).toBe(true); | ||
} | ||
}); | ||
|
||
it("Granularly associates individual deployment routes with specific permissions", () => { | ||
type PairTuple = readonly [ | ||
route: `/${string}`, | ||
permissionKey: keyof Permissions, | ||
]; | ||
|
||
const pairs: readonly PairTuple[] = [ | ||
["/general", "viewDeploymentValues"], | ||
["/licenses", "viewAllLicenses"], | ||
["/appearance", "editDeploymentValues"], | ||
["/userauth", "viewDeploymentValues"], | ||
["/external-auth", "viewDeploymentValues"], | ||
["/network", "viewDeploymentValues"], | ||
["/workspace-proxies", "readWorkspaceProxies"], | ||
["/security", "viewDeploymentValues"], | ||
["/observability", "viewDeploymentValues"], | ||
["/users", "viewAllUsers"], | ||
["/notifications", "viewNotificationTemplate"], | ||
["/oauth2-provider", "viewExternalAuthConfig"], | ||
]; | ||
|
||
for (const [route, permName] of pairs) { | ||
// Using NoPermissions version as baseline to make sure that we | ||
// don't get false positives from all permissions being set to | ||
// true at the start | ||
const mutablePermsCopy = { ...MockNoPermissions }; | ||
const fullRoute = `/deployment${route}`; | ||
|
||
mutablePermsCopy[permName] = true; | ||
let result = isManagementRoutePermitted( | ||
fullRoute, | ||
mutablePermsCopy, | ||
true, | ||
); | ||
expect(result).toBe(true); | ||
|
||
result = isManagementRoutePermitted( | ||
`${fullRoute}/example-subpath`, | ||
mutablePermsCopy, | ||
true, | ||
); | ||
expect(result).toBe(true); | ||
|
||
mutablePermsCopy[permName] = false; | ||
result = isManagementRoutePermitted(fullRoute, mutablePermsCopy, true); | ||
expect(result).toBe(false); | ||
} | ||
|
||
expect.hasAssertions(); | ||
}); | ||
}); | ||
}); |
This file contains hidden or 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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
yeah, this feels like total overkill to me, especially for a quick patch this is a huge departure from how we handle this sort of thing everywhere else in the app