Skip to content

Route tags#37344

Merged
mshustov merged 16 commits intoelastic:masterfrom
mshustov:issue-33775-route-tags
Jun 6, 2019
Merged

Route tags#37344
mshustov merged 16 commits intoelastic:masterfrom
mshustov:issue-33775-route-tags

Conversation

@mshustov
Copy link
Copy Markdown
Contributor

@mshustov mshustov commented May 29, 2019

Summary

Related discussion that may require changing the whole approach to authorization: #38009

2 main changes

  • http route can be marked with tags. Tags are used as a part of authorization rules declaration.
const router = new Router('');
router.get({
  path: '/',
  options: {
    tags:  ['access:console'],
  }
}, ...)
  • KibanaRequest exposes route config
const router = new Router('');
router.get({
  path: '/',
  options: {
    tags:  ['access:my-app']
  }
}, (request, responseToolkit) => {
   const { tags } = request.route.options
   if(tags.includes('access:my-app'){ 
   ...
})

there are tons of changes in docs after I merged master and run yarn core:acceptApiChanges. looks like the reason for this is@microsoft/api-documenter update #37759

Probably it's easier to review commit by commit

Checklist

Use strikethroughs to remove checklist items you don't feel are applicable to this PR.

For maintainers

authRequired?: boolean;

/**
* Additional meta-data information to attach fot the route.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: fot --> to

@azasypkin azasypkin self-requested a review May 29, 2019 16:08
@azasypkin
Copy link
Copy Markdown
Contributor

ACK: will take a look on Friday or Monday at the latest.

@elasticmachine
Copy link
Copy Markdown
Contributor

💔 Build Failed

Copy link
Copy Markdown
Contributor

@azasypkin azasypkin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approach looks good to me, but can you please add a usage example into PR description? Just to have a better idea how it's going to be used.

/**
* Additional meta-data information to attach fot the route.
*/
tags?: string[];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: do you think using ReadonlySet<string> would introduce too much unnecessary friction? I usually prefer Map and Set where uniqueness is implied unless it really reduces API ergonomics.

Copy link
Copy Markdown
Contributor Author

@mshustov mshustov Jun 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using Set could be error-prone because strings are iterable in js

new Set('my:tag')   // wrong declaration, don't throw
new Set(['my:tag']) // correct declaration, but not intuitive

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's arguable and may not be the best choice in some cases, don't have a strong opinion on that, feel free to pick whatever you think is better.

P.S. We decided to move with Set for a similar thing in EcnrytpedSavedObjects to signify uniqueness of the setting. It's not super important, just slowly transforming my coding habits towards string[] ---> Set<string> and Record<string, string> ---> Map<string, string> where appropriate 🙂

import { Request, ResponseToolkit } from 'hapi';
import { merge } from 'lodash';

type DeepPartial<T> = T extends any[]
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elastic/kibana-platform would be useful to declare some type helpers on project level or add a ready toolkit.

@elasticmachine
Copy link
Copy Markdown
Contributor

💔 Build Failed

@mshustov mshustov added Feature:New Platform Team:Core Platform Core services: plugins, logging, config, saved objects, http, ES client, i18n, etc t// Team:Security Platform Security: Auth, Users, Roles, Spaces, Audit Logging, etc t// release_note:skip Skip the PR/issue when compiling release notes v7.3.0 labels Jun 3, 2019
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/kibana-platform

@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/kibana-security

@mshustov mshustov added the review label Jun 3, 2019
@mshustov mshustov marked this pull request as ready for review June 3, 2019 14:52
@mshustov mshustov requested a review from a team as a code owner June 3, 2019 14:52
@elasticmachine
Copy link
Copy Markdown
Contributor

💔 Build Failed

@mshustov
Copy link
Copy Markdown
Contributor Author

mshustov commented Jun 3, 2019

retest

@elasticmachine
Copy link
Copy Markdown
Contributor

💔 Build Failed

*/
import { CapabilitiesService, CapabilitiesStart } from './capabilities_service';
import { deepFreeze } from '../../utils/deep_freeze';
import { deepFreeze } from '../../../utils/';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove trailing slash for import consistency.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's introduce linter rule explicitly if it's important. imo it doesn't make sense to perform manual check on every PR
related #36829 (comment)

import { DiscoveredPlugin, PluginName } from '../../server';
import { UiSettingsState } from '../ui_settings';
import { deepFreeze } from '../utils/deep_freeze';
import { deepFreeze } from '../../utils/';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove trailing slash for import consistency.

*/

import { deepFreeze } from '../../../deep_freeze';
import { deepFreeze } from '../../../../../utils/deep_freeze';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other imports for deepFreeze pull this directly off of utils instead of utils/deep_freeze; did you want to do that here as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this integration test compiles TS and declares its own tsconfig https://github.com/restrry/kibana/blob/5128c9bf3d2fc508d95d27414b912e1d12be5a55/src/core/public/utils/integration_tests/deep_freeze.test.ts
if I import ../../../../../utils/ TS compilation fails due to different setup for the Kibana project and test. I don't think we should keep both in sync, so I just narrowed import to the specific file.


function createRawRequestMock(customization: DeepPartial<Request> = {}) {
return merge(
{},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using 2 anonymous objects here is redundant, so you can remove the first one:

return merge(
  {
    headers: {},
    path: '/',
    route: { settings: {} },
    raw: {
      req: {
        url: '/',
      },
    },
  },
  customization
) as Request;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge mutates the destination object https://lodash.com/docs/3.10.1#merge
if we mutate default value, the next test could be affected by the result of the previous createRawRequestMock call

} as any,
undefined
);
return KibanaRequest.from(httpServerMock.createRawRequest(), undefined);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically, passing undefined to a function is redundant, can this just be:

return KibanaRequest.from(httpServerMock.createRawRequest());

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KibanaRequest.from declaration marks the second parameter as required
https://github.com/restrry/kibana/blob/5128c9bf3d2fc508d95d27414b912e1d12be5a55/src/core/server/http/router/request.ts#L49
I suspect it was done to force the caller to specify route schema. Although this method is used only by Kibana, so probably we can make it optional. @azasypkin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although this method is used only by Kibana, so probably we can make it optional.

Yeah, it seems we should do that. And probably mark it as @internal?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no way to make a method as truly @internal on @public class. instead we can declare from method as an internal function, not a class static method

path: this.request.path,
method: this.request.method,
options: {
authRequired: this.request.route.settings.auth !== false,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If auth is always a boolean, could this instead be:

authRequired: this.request.route.settings.auth,

Copy link
Copy Markdown
Contributor Author

@mshustov mshustov Jun 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • it's not boolean. false | string | RouteOptionsAccess;
  • we invert the logic. authRequired always true if not specified false explicitly

* The set of common HTTP methods supported by Kibana routing.
* @public
* */
export type RouteMethod = 'get' | 'post' | 'put' | 'delete';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple questions:

  • Why should these now be lower case? It looks like it would lead to less diff changes in this patch.
  • Why not add 'patch' | 'options' to this list since they are also used in: method: RouteMethod | 'patch' | 'options';

Copy link
Copy Markdown
Contributor Author

@mshustov mshustov Jun 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • current codebase relays on method names in lower case, because it's a default in hapi. changing to the upper case would lead to bugs during migration.
  • the router doesn't support PATCH and OPTIONS methods as of now and typing should reflect this fact

@elasticmachine
Copy link
Copy Markdown
Contributor

💔 Build Failed

@elasticmachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

@mshustov mshustov requested a review from eliperelman June 4, 2019 12:37
@kobelb
Copy link
Copy Markdown
Contributor

kobelb commented Jun 4, 2019

Do we feel that sticking to the way that "tags" are implemented currently and replicating them in the new platform is strategically advantageous? At the time the access:identifier tags were implemented, it was truly all we had because we were stuck declaring these routes directly with HapiJS. If we had a different mechanism of uniquely identifying routes, I could envision a different solution which was prone to issues like #35881

I don't want to completely derail this effort though, if the legacy and new platform's interaction makes using the same approach across both strategically advantageous in the short-term.

@mshustov
Copy link
Copy Markdown
Contributor Author

mshustov commented Jun 5, 2019

retest

@elasticmachine
Copy link
Copy Markdown
Contributor

💔 Build Failed

@mshustov mshustov requested a review from a team June 6, 2019 08:14
@mshustov
Copy link
Copy Markdown
Contributor Author

mshustov commented Jun 6, 2019

@elastic/kibana-platform could someone review, please? @eliperelman is on vacation

Copy link
Copy Markdown
Contributor

@rudolf rudolf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I made a docs language suggestion, but if you accept it you'll need to re-generate the docs.

@mshustov
Copy link
Copy Markdown
Contributor Author

mshustov commented Jun 6, 2019

@skaapgif ok, then I will update wording manually. thanks ❤️

@elasticmachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

@mshustov
Copy link
Copy Markdown
Contributor Author

mshustov commented Jun 6, 2019

@kobelb let's merge the current PR, even if we decide on other approach in #38009 we can re-use some work from this PR.
also tags can be used for other purposes.

@mshustov mshustov dismissed eliperelman’s stale review June 6, 2019 13:49

reviewer is on vacation

@mshustov mshustov merged commit 53b133d into elastic:master Jun 6, 2019
@mshustov mshustov deleted the issue-33775-route-tags branch June 6, 2019 13:49
mshustov added a commit to mshustov/kibana that referenced this pull request Jun 7, 2019
* expose route info in KibanaRequest

* update mocks in test

* make tags readonly, getRouteInfo is private method

* add mocks for hapi internals

* mode deepFreeze to core utils level as it env agnostic

* freeze route props

* fix typo

* add tests for route options

* fix integration tests. deep_freeze was moved under core utils

* add comments, expose public types and regenerate docs

* address comment. remove unnecessary async in route handlers

* make routeSchema optional instead of union with undefined

* @skaapgif improvements

* update docs
mshustov added a commit that referenced this pull request Jun 7, 2019
* expose route info in KibanaRequest

* update mocks in test

* make tags readonly, getRouteInfo is private method

* add mocks for hapi internals

* mode deepFreeze to core utils level as it env agnostic

* freeze route props

* fix typo

* add tests for route options

* fix integration tests. deep_freeze was moved under core utils

* add comments, expose public types and regenerate docs

* address comment. remove unnecessary async in route handlers

* make routeSchema optional instead of union with undefined

* @skaapgif improvements

* update docs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature:New Platform release_note:skip Skip the PR/issue when compiling release notes review Team:Core Platform Core services: plugins, logging, config, saved objects, http, ES client, i18n, etc t// Team:Security Platform Security: Auth, Users, Roles, Spaces, Audit Logging, etc t// v7.3.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants