-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Add admin rule tab to the role editor #49764
Conversation
5e10c55
to
17771a2
Compare
@gzdunek @ravicious I have just realized that the design didn't include a remove button, and I followed it too literally. I added a capability to remove admin rules, will update the screenshot in a sec. |
Also tightens some constraints about standard role editor conformance.
4d4eaa6
to
0bacc2f
Compare
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 included a bunch of suggestions, but the admin rule tab seems to work fine.
web/packages/teleport/src/Roles/RoleEditor/StandardEditor.test.tsx
Outdated
Show resolved
Hide resolved
|
||
describe('ServerAccessSpecSection', () => { | ||
const setup = () => { | ||
const onChange = jest.fn(); | ||
let validator: Validator; | ||
render( | ||
<StatefulSection<ServerAccessSpec> | ||
<StatefulSection<ServerAccessSpec, AccessSpecValidationResult> | ||
component={ServerAccessSpecSection} | ||
defaultValue={newAccessSpec('node')} |
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.
Nit for the future, as it's not directly related to what's in this PR and changing this at this point could require a lot of not-strictly-necessary work: I noticed that those overloads on newAccessSpec
don't seem to provide a lot of type safety. For example, this doesn't raise a type error about the implementation of newAccessSpec
:
-export function newAccessSpec(kind: 'db'): DatabaseAccessSpec;
+export function newAccessSpec(kind: 'db'): AppAccessSpec;
https://www.typescriptlang.org/docs/handbook/2/functions.html#writing-good-overloads
Always prefer parameters with union types instead of overloads when possible.
There's a couple of other solutions we could consider. If it's important for us to be able to call a function and get a specific variant of AccessSpec
back, we could have a separate function for each variant (e.g. newDatabaseAccessSpec
) that then get called from newAccessSpec
. If that's not important, then we could have just a single export function newAccessSpec(kind: AccessSpecKind): AccessSpec
definition without the overloads.
As a side note on overloads, TypeScript has a ton of features for expressing things that are legal in JavaScript, as TypeScript has to account for the fact that JavaScript is a dynamic language and that there are libraries which weren't written with JS in mind. But when authoring code, I found that usually I'm better off pretending that TypeScript is a static language with a type system akin to that found in Rust, F#, Haskell, or Elm. That is, I let go of the constructs like overloads which are supposed to help with typing JS code and make use mostly of product and sum types.
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.
Thanks, I'll keep it in mind.
test('validation', async () => { | ||
const { user, validator } = setup(); | ||
await user.click(screen.getByRole('button', { name: 'Add New' })); | ||
act(() => validator.validate()); |
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 there a way to trigger validation by interacting with the UI rather than depending on validator
being available?
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.
There would, of course, be a way if I wrapped the component with a button as a part of our test case. I just thought it's unnecessary, since the component under test in this case doesn't have that capability built-in, so it doesn't matter whether we add UI around it just for the testing purposes or not. Why do you think it would be beneficial?
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.
We often depend on some internal deps within our tests which then leads to brittle or flaky tests, see #49870. But I suppose using validator
here makes sense, as you're not testing a complete UI that's surfaced to the user, but rather a utility for building such UIs.
title="Admin Rule" | ||
tooltip="A rule that gives users administrative access to certain kinds of resources" |
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.
Feedback for the design choice, I don't think it's blocking for this PR: as a Teleport user, I'm kind of surprised this is called "admin rules". I don't think our documentation uses such concept and I wouldn't really consider them to be exclusively about administrative access: certain verbs such as read or list are needed just to use resources, not administer them.
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.
@ravicious @zmb3 Any better ideas, then?
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.
My 2c: here we use a term "access rules" (and "access controls") https://goteleport.com/docs/reference/access-controls/roles
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.
@gzdunek Yes, but this is an umbrella term for all of the data in this form.
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.
(Sorry, misread your comment. Yes, you're right.)
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.
Since Zac and Grzegorz agree, I preemptively changed it to "access rules" to be consistent with existing terminology.
tooltip="A rule that gives users administrative access to certain kinds of resources" | ||
removable | ||
isProcessing={isProcessing} | ||
validation={validation} |
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.
It's a minor issue, but when I click "Create role" while there's an invalid admin rule in the form, any other new role that I add gets automatically validated and highlighted as invalid, since I'm yet to fill out any fields.
I don't think it's a blocker, personally I just don't like forms that tell me that a field is invalid before I had a chance to even touch it. ;)
validating-new-rules.mov
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.
@ravicious Unfortunately, our validation library doesn't support a notion of a touched input. It only supports a global "validating" state. I may try to extend it in future, but to be honest, I think that we'd better off just migrating to a third-party library instead.
requiresReset: !isEmpty(rest), | ||
rules: rulesModel, | ||
requiresReset: | ||
kubernetesResourcesRequireReset || rulesRequireReset || !isEmpty(rest), |
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.
It might be a good idea to explain here why !isEmpty(rest)
means that a reset is required and perhaps rename rest
to conditionsUnsupportedByEditor
or something.
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.
Changed to unsupportedConditions
. Also changed in other places where this pattern was used.
// The `Kind*` constants in this const block identify resource kinds used for | ||
// storage an/or and access control. Please keep these in sync with the | ||
// `ResourceKind` enum in | ||
// `web/packages/teleport/src/services/resources/types.ts`. |
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 feel like this comment block is almost guaranteed to be ignored, but I don't really have a better idea how to solve this. If I was ever adding a new kind, I'd do "Go to definition" on an existing, similar kind and never see this comment.
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 feel the same, but that's the least I could do. The ultimatlely correct solution for this one would probably be consuming a protobuf enum, but that would be a much bigger undertaking.
resources: readonly ResourceKindOption[]; | ||
verbs: readonly VerbOption[]; |
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.
Just curious: do we need to store Option<ResourceKind, string>
in the model? Isn't the label needed only for visual purposes and could be created dynamically?
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.
It would most probably work, as long as ReactSelect
uses values, instead of option objects, for telling options apart. It just seemed arbitrary which way should be chosen: we either have to map names to options on the model conversion level, or on the data editing level, so I picked the first way, especially that from my quick look at the codebase, this seemed like the dominant approach. Let me know if you thing there's any significant drawback of one versus another.
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 the model should be kept as lean as possible; values that can be derived shouldn't be part of state https://react.dev/learn/choosing-the-state-structure#avoid-redundant-state.
Are there any significant drawbacks of the current approach? I’d say one potential downside is the inconvenience of accessing values like verb.value
instead of just verb
at higher levels in the component tree, that don't care about the labels.
But I think we can move forward with the current implementation. I’m aware that ReactSelect
can be inconvenient to work with when using plain values, as it only accepts objects. Also I'm not sure if this is worth spending time on it at this point.
title="Admin Rule" | ||
tooltip="A rule that gives users administrative access to certain kinds of resources" |
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.
My 2c: here we use a term "access rules" (and "access controls") https://goteleport.com/docs/reference/access-controls/roles
* Add admin rule tab to the role editor Also tightens some constraints about standard role editor conformance. * Add a way to delete an admin rule * Review
* Add admin rule tab to the role editor Also tightens some constraints about standard role editor conformance. * Add a way to delete an admin rule * Review
Also tightens some constraints about standard role editor conformance.
To turn on the new UI, go to developer tools -> Application -> Local storage and add a
grv_teleport_use_new_role_editor
key set totrue
. This will be lifted once UI is good to be released.Figma
Requires #49546
Contributes to #46612