Skip to content
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

Merged
merged 3 commits into from
Dec 9, 2024
Merged

Add admin rule tab to the role editor #49764

merged 3 commits into from
Dec 9, 2024

Conversation

bl-nero
Copy link
Contributor

@bl-nero bl-nero commented Dec 4, 2024

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 to true. This will be lifted once UI is good to be released.

Screenshot 2024-12-06 at 10 30 33

Figma

Requires #49546
Contributes to #46612

@bl-nero bl-nero added no-changelog Indicates that a PR does not require a changelog entry backport/branch/v17 labels Dec 4, 2024
@github-actions github-actions bot requested review from gzdunek and ravicious December 4, 2024 14:31
@bl-nero bl-nero force-pushed the bl-nero/role-editor-8 branch from 5e10c55 to 17771a2 Compare December 4, 2024 14:59
Base automatically changed from bl-nero/role-editor-7 to master December 5, 2024 13:22
@bl-nero
Copy link
Contributor Author

bl-nero commented Dec 6, 2024

@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.
@bl-nero bl-nero force-pushed the bl-nero/role-editor-8 branch from 4d4eaa6 to 0bacc2f Compare December 6, 2024 12:22
Copy link
Member

@ravicious ravicious left a 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.


describe('ServerAccessSpecSection', () => {
const setup = () => {
const onChange = jest.fn();
let validator: Validator;
render(
<StatefulSection<ServerAccessSpec>
<StatefulSection<ServerAccessSpec, AccessSpecValidationResult>
component={ServerAccessSpecSection}
defaultValue={newAccessSpec('node')}
Copy link
Member

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.

Copy link
Contributor Author

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());
Copy link
Member

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?

Copy link
Contributor Author

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?

Copy link
Member

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.

Comment on lines 978 to 979
title="Admin Rule"
tooltip="A rule that gives users administrative access to certain kinds of resources"
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.)

Copy link
Contributor Author

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}
Copy link
Member

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

Copy link
Contributor Author

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),
Copy link
Member

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.

Copy link
Contributor Author

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`.
Copy link
Member

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.

Copy link
Contributor Author

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.

Comment on lines +250 to +251
resources: readonly ResourceKindOption[];
verbs: readonly VerbOption[];
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Comment on lines 978 to 979
title="Admin Rule"
tooltip="A rule that gives users administrative access to certain kinds of resources"
Copy link
Contributor

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

@bl-nero bl-nero requested a review from gzdunek December 9, 2024 13:16
@bl-nero bl-nero added this pull request to the merge queue Dec 9, 2024
Merged via the queue into master with commit 02141ca Dec 9, 2024
45 checks passed
@bl-nero bl-nero deleted the bl-nero/role-editor-8 branch December 9, 2024 18:07
@public-teleport-github-review-bot

@bl-nero See the table below for backport results.

Branch Result
branch/v17 Failed

bl-nero added a commit that referenced this pull request Dec 9, 2024
* 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
bl-nero added a commit that referenced this pull request Dec 9, 2024
* 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
github-merge-queue bot pushed a commit that referenced this pull request Dec 10, 2024
* 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport/branch/v17 no-changelog Indicates that a PR does not require a changelog entry size/lg ui
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants