-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Risk engine initialisation, update from legacy risk engine workflow and status change #162400
Changes from 33 commits
34a040e
62b04b6
ef9d3e5
9f2e3d9
347f4ff
ad59803
8423d5c
fdc0084
05f28c5
e7079c9
4ffaa99
1b74331
8518cbb
27e39c2
b4c212d
805d243
34fa0ed
2cce865
189e941
6d7c016
b99c3e1
b4f5955
a835c61
e1ed39e
e6dcad4
e31d85b
8373a58
e72b7d4
38e23bc
9a53d21
450871a
1527f2a
b47ec84
5dffa4d
ca8329b
7aad6cb
dac1f34
6265ac3
7fd2016
b31ab04
a77a838
ba83b7b
9742878
c77a82e
96b6ddc
3b1bb9f
f8cf032
7237b5f
7df7d22
ddbe593
1bc3314
d9b03b0
b8b638e
b44c3b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -9,3 +9,17 @@ export enum RiskScoreEntity { | |||||
host = 'host', | ||||||
user = 'user', | ||||||
} | ||||||
|
||||||
export enum RiskEngineStatus { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I tend to pluralize enums to distinguish them from other types:
Suggested change
|
||||||
NOT_INSTALLED = 'NOT_INSTALLED', | ||||||
DISABLED = 'DISABLED', | ||||||
ENABLED = 'ENABLED', | ||||||
} | ||||||
|
||||||
export interface InitRiskEngineResult { | ||||||
legacyRiskEngineDisabled: boolean; | ||||||
riskEngineResourcesInstalled: boolean; | ||||||
riskEngineConfigurationCreated: boolean; | ||||||
riskEngineEnabled: boolean; | ||||||
errors: string[]; | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,71 +24,75 @@ import { createRule } from '../../tasks/api_calls/rules'; | |
import { updateDateRangeInLocalDatePickers } from '../../tasks/date_picker'; | ||
import { fillLocalSearchBar, submitLocalSearch } from '../../tasks/search_bar'; | ||
|
||
describe('Entity analytics management page', () => { | ||
before(() => { | ||
cleanKibana(); | ||
cy.task('esArchiverLoad', 'all_users'); | ||
}); | ||
|
||
beforeEach(() => { | ||
login(); | ||
visitWithoutDateRange(ALERTS_URL); | ||
createRule(getNewRule({ query: 'user.name:* or host.name:*', risk_score: 70 })); | ||
visit(ENTITY_ANALYTICS_MANAGEMENT_URL); | ||
}); | ||
|
||
after(() => { | ||
cy.task('esArchiverUnload', 'all_users'); | ||
}); | ||
|
||
it('renders page as expected', () => { | ||
cy.get(PAGE_TITLE).should('have.text', 'Entity Risk Score'); | ||
}); | ||
|
||
describe('Risk preview', () => { | ||
it('risk scores reacts on change in datepicker', () => { | ||
const START_DATE = 'Jan 18, 2019 @ 20:33:29.186'; | ||
const END_DATE = 'Jan 19, 2019 @ 20:33:29.186'; | ||
|
||
cy.get(HOST_RISK_PREVIEW_TABLE_ROWS).should('have.length', 5); | ||
cy.get(USER_RISK_PREVIEW_TABLE_ROWS).should('have.length', 5); | ||
|
||
updateDateRangeInLocalDatePickers(LOCAL_QUERY_BAR_SELECTOR, START_DATE, END_DATE); | ||
|
||
cy.get(HOST_RISK_PREVIEW_TABLE).contains('No items found'); | ||
cy.get(USER_RISK_PREVIEW_TABLE).contains('No items found'); | ||
describe( | ||
'Entity analytics management page', | ||
{ env: { ftrConfig: { enableExperimental: ['riskScoringRoutesEnabled'] } } }, | ||
() => { | ||
before(() => { | ||
cleanKibana(); | ||
cy.task('esArchiverLoad', 'all_users'); | ||
}); | ||
|
||
it('risk scores reacts on change in search bar query', () => { | ||
cy.get(HOST_RISK_PREVIEW_TABLE_ROWS).should('have.length', 5); | ||
cy.get(USER_RISK_PREVIEW_TABLE_ROWS).should('have.length', 5); | ||
beforeEach(() => { | ||
login(); | ||
visitWithoutDateRange(ALERTS_URL); | ||
createRule(getNewRule({ query: 'user.name:* or host.name:*', risk_score: 70 })); | ||
visit(ENTITY_ANALYTICS_MANAGEMENT_URL); | ||
}); | ||
|
||
fillLocalSearchBar('host.name: "test-host1"'); | ||
submitLocalSearch(LOCAL_QUERY_BAR_SELECTOR); | ||
after(() => { | ||
cy.task('esArchiverUnload', 'all_users'); | ||
}); | ||
|
||
cy.get(HOST_RISK_PREVIEW_TABLE_ROWS).should('have.length', 1); | ||
cy.get(HOST_RISK_PREVIEW_TABLE_ROWS).contains('test-host1'); | ||
cy.get(USER_RISK_PREVIEW_TABLE_ROWS).should('have.length', 1); | ||
cy.get(USER_RISK_PREVIEW_TABLE_ROWS).contains('test1'); | ||
it('renders page as expected', () => { | ||
cy.get(PAGE_TITLE).should('have.text', 'Entity Risk Score'); | ||
}); | ||
|
||
it('show error panel if API returns error and then try to refetch data', () => { | ||
cy.intercept('POST', '/internal/risk_score/preview', { | ||
statusCode: 500, | ||
describe('Risk preview', () => { | ||
it('risk scores reacts on change in datepicker', () => { | ||
const START_DATE = 'Jan 18, 2019 @ 20:33:29.186'; | ||
const END_DATE = 'Jan 19, 2019 @ 20:33:29.186'; | ||
|
||
cy.get(HOST_RISK_PREVIEW_TABLE_ROWS).should('have.length', 5); | ||
cy.get(USER_RISK_PREVIEW_TABLE_ROWS).should('have.length', 5); | ||
|
||
updateDateRangeInLocalDatePickers(LOCAL_QUERY_BAR_SELECTOR, START_DATE, END_DATE); | ||
|
||
cy.get(HOST_RISK_PREVIEW_TABLE).contains('No items found'); | ||
cy.get(USER_RISK_PREVIEW_TABLE).contains('No items found'); | ||
}); | ||
|
||
cy.get(RISK_PREVIEW_ERROR).contains('Preview failed'); | ||
it('risk scores reacts on change in search bar query', () => { | ||
cy.get(HOST_RISK_PREVIEW_TABLE_ROWS).should('have.length', 5); | ||
cy.get(USER_RISK_PREVIEW_TABLE_ROWS).should('have.length', 5); | ||
|
||
cy.intercept('POST', '/internal/risk_score/preview', { | ||
statusCode: 200, | ||
body: { | ||
scores: { host: [], user: [] }, | ||
}, | ||
fillLocalSearchBar('host.name: "test-host1"'); | ||
submitLocalSearch(LOCAL_QUERY_BAR_SELECTOR); | ||
|
||
cy.get(HOST_RISK_PREVIEW_TABLE_ROWS).should('have.length', 1); | ||
cy.get(HOST_RISK_PREVIEW_TABLE_ROWS).contains('test-host1'); | ||
cy.get(USER_RISK_PREVIEW_TABLE_ROWS).should('have.length', 1); | ||
cy.get(USER_RISK_PREVIEW_TABLE_ROWS).contains('test1'); | ||
}); | ||
|
||
cy.get(RISK_PREVIEW_ERROR_BUTTON).click(); | ||
it('show error panel if API returns error and then try to refetch data', () => { | ||
cy.intercept('POST', '/internal/risk_score/preview', { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: Wrapt these intercepts into a task method making clear what you are doing or just add a simple comment about the stubbing you are doing :) |
||
statusCode: 500, | ||
}); | ||
|
||
cy.get(RISK_PREVIEW_ERROR).contains('Preview failed'); | ||
|
||
cy.intercept('POST', '/internal/risk_score/preview', { | ||
statusCode: 200, | ||
body: { | ||
scores: { host: [], user: [] }, | ||
}, | ||
}); | ||
|
||
cy.get(RISK_PREVIEW_ERROR).should('not.exist'); | ||
cy.get(RISK_PREVIEW_ERROR_BUTTON).click(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: Wrap this into a task method. |
||
|
||
cy.get(RISK_PREVIEW_ERROR).should('not.exist'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
} | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,10 +5,22 @@ | |
* 2.0. | ||
*/ | ||
|
||
import { RISK_SCORE_PREVIEW_URL } from '../../../common/constants'; | ||
import { | ||
RISK_ENGINE_STATUS_URL, | ||
RISK_SCORE_PREVIEW_URL, | ||
RISK_ENGINE_ENABLE_URL, | ||
RISK_ENGINE_DISABLE_URL, | ||
RISK_ENGINE_INIT_URL, | ||
} from '../../../common/constants'; | ||
|
||
import { KibanaServices } from '../../common/lib/kibana'; | ||
import type { CalculateScoresResponse } from '../../../server/lib/risk_engine/types'; | ||
import type { | ||
CalculateScoresResponse, | ||
GetRiskEngineEnableResponse, | ||
GetRiskEngineStatusResponse, | ||
InitRiskEngineResponse, | ||
GetRiskEngineDisableResponse, | ||
} from '../../../server/lib/risk_engine/types'; | ||
import type { RiskScorePreviewRequestSchema } from '../../../common/risk_engine/risk_score_preview/request_schema'; | ||
|
||
/** | ||
|
@@ -27,3 +39,44 @@ export const fetchRiskScorePreview = async ({ | |
signal, | ||
}); | ||
}; | ||
|
||
/** | ||
* Fetches risks engine status | ||
*/ | ||
export const fetchRiskEngineStatus = async ({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I missed this with your previous PR, but: can you explain the logic behind the folder naming here? Explore team originally introduced There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My original idea was to introduce the new public folder, for all things related to EA (watchlist, etc) If you think we should rename/move things please let me know There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That sounds reasonable; thanks for the explanation. Perhaps as we move the client code to pull from the new risk score data, we can move those files/folders under |
||
signal, | ||
}: { | ||
signal?: AbortSignal; | ||
}): Promise<GetRiskEngineStatusResponse> => { | ||
return KibanaServices.get().http.fetch<GetRiskEngineStatusResponse>(RISK_ENGINE_STATUS_URL, { | ||
method: 'GET', | ||
signal, | ||
}); | ||
}; | ||
|
||
/** | ||
* Init risk score engine | ||
*/ | ||
export const initRiskEngine = async (): Promise<InitRiskEngineResponse> => { | ||
return KibanaServices.get().http.fetch<InitRiskEngineResponse>(RISK_ENGINE_INIT_URL, { | ||
method: 'POST', | ||
}); | ||
}; | ||
|
||
/** | ||
* Enable risk score engine | ||
*/ | ||
export const enableRiskEngine = async (): Promise<GetRiskEngineEnableResponse> => { | ||
return KibanaServices.get().http.fetch<GetRiskEngineEnableResponse>(RISK_ENGINE_ENABLE_URL, { | ||
method: 'POST', | ||
}); | ||
}; | ||
|
||
/** | ||
* Disable risk score engine | ||
*/ | ||
export const disableRiskEngine = async (): Promise<GetRiskEngineDisableResponse> => { | ||
return KibanaServices.get().http.fetch<GetRiskEngineDisableResponse>(RISK_ENGINE_DISABLE_URL, { | ||
method: 'POST', | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
import type { UseMutationOptions } from '@tanstack/react-query'; | ||
import { useMutation } from '@tanstack/react-query'; | ||
import { disableRiskEngine } from '../api'; | ||
import { useInvalidateRiskEngineStatusQuery } from './use_risk_engine_status'; | ||
import type { | ||
GetRiskEngineDisableResponse, | ||
EnableDisableRiskEngineResponse, | ||
} from '../../../../server/lib/risk_engine/types'; | ||
|
||
export const DISABLE_RISK_ENGINE_MUTATION_KEY = ['POST', 'DISABLE_RISK_ENGINE']; | ||
rylnd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
export const useDisableRiskEngineMutation = (options?: UseMutationOptions<{}>) => { | ||
const invalidateRiskEngineStatusQuery = useInvalidateRiskEngineStatusQuery(); | ||
|
||
return useMutation<GetRiskEngineDisableResponse, EnableDisableRiskEngineResponse>( | ||
() => disableRiskEngine(), | ||
{ | ||
...options, | ||
mutationKey: DISABLE_RISK_ENGINE_MUTATION_KEY, | ||
onSettled: (...args) => { | ||
invalidateRiskEngineStatusQuery(); | ||
|
||
if (options?.onSettled) { | ||
options.onSettled(...args); | ||
} | ||
}, | ||
} | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
import type { UseMutationOptions } from '@tanstack/react-query'; | ||
import { useMutation } from '@tanstack/react-query'; | ||
import { enableRiskEngine } from '../api'; | ||
import { useInvalidateRiskEngineStatusQuery } from './use_risk_engine_status'; | ||
import type { | ||
GetRiskEngineEnableResponse, | ||
EnableDisableRiskEngineResponse, | ||
} from '../../../../server/lib/risk_engine/types'; | ||
export const ENABLE_RISK_ENGINE_MUTATION_KEY = ['POST', 'ENABLE_RISK_ENGINE']; | ||
|
||
export const useEnableRiskEngineMutation = (options?: UseMutationOptions<{}>) => { | ||
const invalidateRiskEngineStatusQuery = useInvalidateRiskEngineStatusQuery(); | ||
|
||
return useMutation<GetRiskEngineEnableResponse, EnableDisableRiskEngineResponse>( | ||
() => enableRiskEngine(), | ||
{ | ||
...options, | ||
mutationKey: ENABLE_RISK_ENGINE_MUTATION_KEY, | ||
onSettled: (...args) => { | ||
invalidateRiskEngineStatusQuery(); | ||
|
||
if (options?.onSettled) { | ||
options.onSettled(...args); | ||
} | ||
}, | ||
} | ||
); | ||
}; |
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.