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

[Security Solution] [Cases] Cases UI Plugin for RAC #97646

Merged
merged 87 commits into from
Apr 29, 2021
Merged

Conversation

stephmilovic
Copy link
Contributor

@stephmilovic stephmilovic commented Apr 20, 2021

Summary

Cases UI plugin for RAC by @michaelolo24 && @stephmilovic
Feature branch, all code has been reviewed in subsequent PRs (see label Feature:Cases-RAC-UI)

Testing

Considering the size of this PR, those who may not be intimately familiar with cases may not be able to go through and review the lines of code. With that said no new functionality has been introduced, so everything should work as it earlier versions of cases. To help with testing we ask that you pull down the code at physically test the following paths/actions

1. Creating a case from the cases path
2. Creating a case from the flyout in detections. 
3. Configuring a case with an external connector
4. Syncing alerts with a case
5. Attaching an alert to a case and accessing that alert from the case
6. Attaching a timeline to the case and accessing the timeline from that case
7. Adding comments to the case
8. Changing the status of a case
9. Sharing cases via comment hyperlinks
10. Navigating using any provided breadcrumbs
11. Navigating and accessing cases from the recent_cases panel in the overview page
12. Deleting a case

This PR adds the following UI plugin to x-pack/cases:

Cases UI

Embed Cases UI components in any Kibana plugin

  • Add CasesUiStart to Kibana plugin StartServices dependencies:
cases: CasesUiStart;

Cases UI Methods

  • From the UI component, get the component from the useKibana hook start services
  const { cases } = useKibana().services;
  // call in the return as you would any component
  cases.getCreateCase({
    onCancel: handleSetIsCancel,
    onSuccess,
    timelineIntegration?: {
      plugins: {
        parsingPlugin,
        processingPluginRenderer,
        uiPlugin,
      },
      hooks: {
        useInsertTimeline,
      },
    },
  })
Methods:

getAllCases

Arguments:

Property Description
caseDetailsNavigation CasesNavigation<CaseDetailsHrefSchema, 'configurable'> route configuration to generate the case details url for the case details page
configureCasesNavigation CasesNavigation route configuration for configure cases page
createCaseNavigation CasesNavigation route configuration for create cases page
userCanCrud boolean; user permissions to crud

UI component:
All Cases Component

getAllCasesSelectorModal

Arguments:

Property Description
alertData? Omit<CommentRequestAlertType, 'type'>; alert data to post to case
createCaseNavigation CasesNavigation route configuration for create cases page
disabledStatuses? CaseStatuses[]; array of disabled statuses
onRowClick (theCase?: Case | SubCase) => void; callback for row click, passing case in row
updateCase? (theCase: Case | SubCase) => void; callback after case has been updated
userCanCrud boolean; user permissions to crud

UI component:
All Cases Selector Modal Component

getCaseView

Arguments:

Property Description
caseDetailsNavigation CasesNavigation<CaseDetailsHrefSchema, 'configurable'> route configuration to generate the case details url for the case details page
caseId string; ID of the case
configureCasesNavigation CasesNavigation route configuration for configure cases page
createCaseNavigation CasesNavigation route configuration for create cases page
getCaseDetailHrefWithCommentId (commentId: string) => string; callback to generate the case details url with a comment id reference from the case id and comment id
onComponentInitialized? () => void; callback when component has initialized
onCaseDataSuccess? (data: Case) => void; optional callback to handle case data in consuming application
ruleDetailsNavigation CasesNavigation<string | null | undefined, 'configurable'>
showAlertDetails (alertId: string, index: string) => void; callback to show alert details
subCaseId? string; subcase id
timelineIntegration?.editor_plugins Plugins needed for integrating timeline into markdown editor.
timelineIntegration?.editor_plugins.parsingPlugin Plugin;
timelineIntegration?.editor_plugins.processingPluginRenderer React.FC<TimelineProcessingPluginRendererProps & { position: EuiMarkdownAstNodePosition }>
timelineIntegration?.editor_plugins.uiPlugin? EuiMarkdownEditorUiPlugin
timelineIntegration?.hooks.useInsertTimeline (value: string, onChange: (newValue: string) => void): UseInsertTimelineReturn
timelineIntegration?.ui?.renderInvestigateInTimelineActionComponent? (alertIds: string[]) => JSX.Element; space to render InvestigateInTimelineActionComponent
timelineIntegration?.ui?renderTimelineDetailsPanel? () => JSX.Element; space to render TimelineDetailsPanel
useFetchAlertData (alertIds: string[]) => [boolean, Record<string, Ecs>]; fetch alerts
userCanCrud boolean; user permissions to crud

UI component:
Case View Component

getCreateCase

Arguments:

Property Description
afterCaseCreated? (theCase: Case) => Promise<void>; callback passing newly created case before pushCaseToExternalService is called
onCancel () => void; callback when create case is canceled
onSuccess (theCase: Case) => Promise<void>; callback passing newly created case after pushCaseToExternalService is called
timelineIntegration?.editor_plugins Plugins needed for integrating timeline into markdown editor.
timelineIntegration?.editor_plugins.parsingPlugin Plugin;
timelineIntegration?.editor_plugins.processingPluginRenderer React.FC<TimelineProcessingPluginRendererProps & { position: EuiMarkdownAstNodePosition }>
timelineIntegration?.editor_plugins.uiPlugin? EuiMarkdownEditorUiPlugin
timelineIntegration?.hooks.useInsertTimeline (value: string, onChange: (newValue: string) => void): UseInsertTimelineReturn

UI component:
Create Component

getConfigureCases

Arguments:

Property Description
userCanCrud boolean; user permissions to crud

UI component:
Configure Component

getRecentCases

Arguments:

Property Description
allCasesNavigation CasesNavigation route configuration for configure cases page
caseDetailsNavigation CasesNavigation<CaseDetailsHrefSchema, 'configurable'> route configuration to generate the case details url for the case details page
createCaseNavigation CasesNavigation route configuration for create case page
maxCasesToShow number; number of cases to show in widget

UI component:
Recent Cases Component

Copy link
Member

@jbudz jbudz left a comment

Choose a reason for hiding this comment

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

limits.yml LGTM

* 2.0.
*/

export * from './test_providers';
Copy link
Member

Choose a reason for hiding this comment

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

What about match_media and kibana_react.mock.ts (if needed. See my comment below)

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's no modules exported from match_media. it is a window mock, all you need to do is import like import '../../common/mock/match_media';

@@ -73,6 +73,7 @@ export const addDescriptionToTimeline = (description: string) => {

export const addNameToTimeline = (name: string) => {
cy.get(TIMELINE_EDIT_MODAL_OPEN_BUTTON).first().click();
// cy.log('HERE:', cy.get(TIMELINE_TITLE_INPUT));
Copy link
Member

Choose a reason for hiding this comment

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

Why is commented out?

getDefaultEuiMarkdownParsingPlugins,
getDefaultEuiMarkdownProcessingPlugins,
getDefaultEuiMarkdownUiPlugins,
} from '@elastic/eui';

// Remove after this issue is resolved: https://github.com/elastic/eui/issues/4688
Copy link
Member

Choose a reason for hiding this comment

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

The issue seems to be resolved.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

its not merged into kibana yet i dont think

Copy link
Contributor Author

Choose a reason for hiding this comment

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

jk it is there now, ill remove it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

jk there was a different error:
Screen Shot 2021-04-26 at 8 42 02 AM

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@chandlerprall says:

we'll cut a release tomorrow with that change, and depending on Greg's availability we'll get a Kibana upgrade started this week or next

Copy link
Member

Choose a reason for hiding this comment

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

I see. No worries!

export const { uiPlugins, parsingPlugins, processingPlugins } = {
uiPlugins: getDefaultEuiMarkdownUiPlugins(),
parsingPlugins: getDefaultEuiMarkdownParsingPlugins(),
processingPlugins: getDefaultEuiMarkdownProcessingPlugins() as [
Copy link
Member

Choose a reason for hiding this comment

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

Why we need to cast it?

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 was this but removing now elastic/eui#4688

Copy link
Contributor Author

Choose a reason for hiding this comment

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


import { FunctionComponent } from 'react';
import { Plugin, PluggableList } from 'unified';
// Remove after this issue is resolved: https://github.com/elastic/eui/issues/4688
Copy link
Member

Choose a reason for hiding this comment

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

The issue seems to be resolved.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

@cnasikas cnasikas left a comment

Choose a reason for hiding this comment

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

Amazing PR! Thank you both for your hard work 🚀 . Code LTGM!

I manually tested the PR and I found the following:

  • Some API calls are being done twice. This probably means that an unnecessary render is being made somewhere. Specifically:

Single case view:

Screenshot 2021-04-26 at 11 40 38 AM

Creation / Single case view (?):

Screenshot 2021-04-26 at 1 21 21 PM

All cases view:

Screenshot 2021-04-26 at 11 40 02 AM

  • I attach an alert to a case but I cannot see the investigate in timeline action

Screenshot 2021-04-26 at 1 26 17 PM

  • If I open the timeline the title of the case in the breadcrumb is not displayed (Mike)

Screenshot 2021-04-26 at 1 34 18 PM

  • All cases modal bug when attaching a timeline to a case. This is happening if I am in the all pages view. If I am in the single case view it is not happening. (this is @stephmilovic commenting -> cant reproduce this either?!)
timeline_bug.mp4
  • Attach to an existing case is not working (this is @stephmilovic commenting -> i cannot reproduce this?!)
attach_to_case.mp4
attach_to_new_case.mp4

@stephmilovic
Copy link
Contributor Author

This commit fixes the below issue: b5d3932

  • Some API calls are being done twice. This probably means that an unnecessary render is being made somewhere. Specifically:

Single case view:

Screenshot 2021-04-26 at 11 40 38 AM

Creation / Single case view (?):

Screenshot 2021-04-26 at 1 21 21 PM

All cases view:

Screenshot 2021-04-26 at 11 40 02 AM

@michaelolo24
Copy link
Contributor

This commit: f5fa7f1

fixes:

attach_to_case.mp4

attach_to_new_case.mp4

@michaelolo24
Copy link
Contributor

This commit: df7097e (#97646) fixed an issue where attaching an alert to a new case from detections was not working

@@ -38,6 +38,18 @@ interface AddToCaseActionProps {
ecsRowData: Ecs;
}

interface PostCommentArg {
caseId: string;
data: {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if it's worth it or not (or if it causes a circular dependency) but we might be able to pull the data type from the case common types:

https://github.com/elastic/kibana/blob/master/x-pack/plugins/cases/common/api/cases/comment.ts#L125

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea, was trying to avoid a circular dependency when I tossed this together, but thinking about it more, since cases doesn't depend on Security Solution, it shouldn't be

Copy link
Contributor

@jonathan-buttner jonathan-buttner left a comment

Choose a reason for hiding this comment

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

🚀

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
cases - 252 +252
securitySolution 2174 2005 -169
total +83

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
cases 2 337 +335
securitySolution 90 89 -1
total +334

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
cases - 494.0KB ⚠️ +494.0KB
securitySolution 7.0MB 6.5MB -468.0KB
total +26.0KB

Public APIs missing exports

Total count of every type that is part of your API that should be exported but is not. This will cause broken links in the API documentation system. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats exports for more detailed information.

id before after diff
cases 1 7 +6
security 10 12 +2
securitySolution 7 8 +1
total +9

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
cases - 126.7KB +126.7KB
securitySolution 206.1KB 160.0KB -46.1KB
total +80.6KB
Unknown metric groups

API count

id before after diff
cases 2 349 +347
securitySolution 99 98 -1
total +346

async chunk count

id before after diff
cases - 14 +14
securitySolution 25 19 -6
total +8

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Cases Cases feature release_note:feature Makes this part of the condensed release notes Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. Team:Threat Hunting Security Solution Threat Hunting Team v7.14.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants