[7.x] [Security Solution] [Bugfix] Fix analyzer missing from alert table (#109183) (#109727)

* resolve conflicts

* rm whoops

* actually fix whoops

* fix type

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Steph Milovic 2021-08-24 20:05:33 -06:00 committed by GitHub
parent 764690d9b2
commit e028409a98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 249 additions and 60 deletions

View file

@ -116,7 +116,7 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
selectedPatterns,
loading: isLoadingIndexPattern,
} = useSourcererScope(scopeId);
const { globalFullScreen, setGlobalFullScreen } = useGlobalFullScreen();
const { globalFullScreen } = useGlobalFullScreen();
// TODO: Once we are past experimental phase this code should be removed
const tGridEnabled = useIsExperimentalFeatureEnabled('tGridEnabled');
const tGridEventRenderedViewEnabled = useIsExperimentalFeatureEnabled(
@ -180,7 +180,6 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
onRuleChange,
renderCellValue,
rowRenderers,
setGlobalFullScreen,
start,
sort,
additionalFilters,

View file

@ -0,0 +1,67 @@
/*
* 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 React from 'react';
import { render, screen } from '@testing-library/react';
import { TGridIntegrated, TGridIntegratedProps } from './index';
import { TestProviders, tGridIntegratedProps } from '../../../mock';
const mockId = tGridIntegratedProps.id;
jest.mock('../../../container', () => ({
useTimelineEvents: () => [
false,
{
id: mockId,
inspect: {
dsl: [],
response: [],
},
totalCount: -1,
pageInfo: {
activePage: 0,
querySize: 0,
},
events: [],
updatedAt: 0,
},
],
}));
jest.mock('../helpers', () => {
const original = jest.requireActual('../helpers');
return {
...original,
getCombinedFilterQuery: () => ({
bool: {
must: [],
filter: [],
},
}),
buildCombinedQuery: () => ({
filterQuery: '{"bool":{"must":[],"filter":[]}}',
}),
};
});
const defaultProps: TGridIntegratedProps = tGridIntegratedProps;
describe('integrated t_grid', () => {
const dataTestSubj = 'right-here-dawg';
it('does not render graphOverlay if graphOverlay=null', () => {
render(
<TestProviders>
<TGridIntegrated {...defaultProps} />
</TestProviders>
);
expect(screen.queryByTestId(dataTestSubj)).toBeNull();
});
it('does render graphOverlay if graphOverlay=React.ReactNode', () => {
render(
<TestProviders>
<TGridIntegrated {...defaultProps} graphOverlay={<span data-test-subj={dataTestSubj} />} />
</TestProviders>
);
expect(screen.queryByTestId(dataTestSubj)).not.toBeNull();
});
});

View file

@ -56,8 +56,6 @@ import { SummaryViewSelector, ViewSelection } from '../event_rendered_view/selec
const AlertConsumers: typeof AlertConsumersTyped = AlertConsumersNonTyped;
export const EVENTS_VIEWER_HEADER_HEIGHT = 90; // px
const TitleText = styled.span`
margin-right: 12px;
`;
@ -101,8 +99,10 @@ const ScrollableFlexItem = styled(EuiFlexItem)`
const SECURITY_ALERTS_CONSUMERS = [AlertConsumers.SIEM];
export interface TGridIntegratedProps {
additionalFilters: React.ReactNode;
browserFields: BrowserFields;
columns: ColumnHeaderOptions[];
data?: DataPublicPluginStart;
dataProviders: DataProvider[];
defaultCellActions?: TGridCellAction[];
deletedEventIds: Readonly<string[]>;
@ -110,9 +110,12 @@ export interface TGridIntegratedProps {
end: string;
entityType: EntityType;
filters: Filter[];
globalFullScreen: boolean;
graphOverlay?: React.ReactNode;
filterStatus?: AlertStatus;
globalFullScreen: boolean;
// If truthy, the graph viewer (Resolver) is showing
graphEventId: string | undefined;
graphOverlay?: React.ReactNode;
hasAlertsCrud: boolean;
height?: number;
id: TimelineId;
indexNames: string[];
@ -122,36 +125,35 @@ export interface TGridIntegratedProps {
itemsPerPage: number;
itemsPerPageOptions: number[];
kqlMode: 'filter' | 'search';
query: Query;
leadingControlColumns?: ControlColumnProps[];
onRuleChange?: () => void;
query: Query;
renderCellValue: (props: CellValueElementProps) => React.ReactNode;
rowRenderers: RowRenderer[];
setGlobalFullScreen: (fullscreen: boolean) => void;
start: string;
sort: Sort[];
additionalFilters: React.ReactNode;
// If truthy, the graph viewer (Resolver) is showing
graphEventId: string | undefined;
leadingControlColumns?: ControlColumnProps[];
trailingControlColumns?: ControlColumnProps[];
data?: DataPublicPluginStart;
start: string;
tGridEventRenderedViewEnabled: boolean;
hasAlertsCrud: boolean;
trailingControlColumns?: ControlColumnProps[];
unit?: (n: number) => string;
}
const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
additionalFilters,
browserFields,
columns,
defaultCellActions,
data,
dataProviders,
defaultCellActions,
deletedEventIds,
docValueFields,
end,
entityType,
filters,
globalFullScreen,
filterStatus,
globalFullScreen,
graphEventId,
graphOverlay = null,
hasAlertsCrud,
id,
indexNames,
indexPattern,
@ -160,21 +162,15 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
itemsPerPage,
itemsPerPageOptions,
kqlMode,
leadingControlColumns,
onRuleChange,
query,
renderCellValue,
rowRenderers,
setGlobalFullScreen,
start,
sort,
additionalFilters,
graphOverlay = null,
graphEventId,
leadingControlColumns,
trailingControlColumns,
start,
tGridEventRenderedViewEnabled,
data,
hasAlertsCrud,
trailingControlColumns,
unit,
}) => {
const dispatch = useDispatch();
@ -236,34 +232,36 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
] = useTimelineEvents({
// We rely on entityType to determine Events vs Alerts
alertConsumers: SECURITY_ALERTS_CONSUMERS,
data,
docValueFields,
endDate: end,
entityType,
fields,
filterQuery: combinedQueries!.filterQuery,
id,
indexNames,
limit: itemsPerPage,
skip: !canQueryTimeline,
sort: sortField,
startDate: start,
endDate: end,
skip: !canQueryTimeline,
data,
});
const filterQuery = useMemo(() => {
return getCombinedFilterQuery({
config: esQuery.getEsQueryConfig(uiSettings),
dataProviders,
indexPattern,
browserFields,
filters,
kqlQuery: query,
kqlMode,
isEventViewer: true,
from: start,
to: end,
});
}, [uiSettings, dataProviders, indexPattern, browserFields, filters, start, end, query, kqlMode]);
const filterQuery = useMemo(
() =>
getCombinedFilterQuery({
config: esQuery.getEsQueryConfig(uiSettings),
browserFields,
dataProviders,
filters,
from: start,
indexPattern,
isEventViewer: true,
kqlMode,
kqlQuery: query,
to: end,
}),
[uiSettings, dataProviders, indexPattern, browserFields, filters, start, end, query, kqlMode]
);
const totalCountMinusDeleted = useMemo(
() => (totalCount > 0 ? totalCount - deletedEventIds.length : 0),
@ -292,6 +290,7 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
>
{loading && <EuiProgress size="xs" position="absolute" color="accent" />}
{graphOverlay}
{canQueryTimeline ? (
<>
<EventsContainerLoading
@ -299,14 +298,14 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
data-test-subj={`events-container-loading-${loading}`}
>
<UpdatedFlexGroup gutterSize="m" justifyContent="flexEnd" alignItems={alignItems}>
<UpdatedFlexItem grow={false} show={!loading}>
<UpdatedFlexItem grow={false} $show={!loading}>
<InspectButton title={justTitle} inspect={inspect} loading={loading} />
</UpdatedFlexItem>
<UpdatedFlexItem grow={false} show={!loading}>
<UpdatedFlexItem grow={false} $show={!loading}>
{!resolverIsShowing(graphEventId) && additionalFilters}
</UpdatedFlexItem>
{tGridEventRenderedViewEnabled && entityType === 'alerts' && (
<UpdatedFlexItem grow={false} show={!loading}>
<UpdatedFlexItem grow={false} $show={!loading}>
<SummaryViewSelector viewSelected={tableView} onViewChange={setTableView} />
</UpdatedFlexItem>
)}
@ -340,33 +339,33 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
) : (
<>
<StatefulBody
hasAlertsCrud={hasAlertsCrud}
activePage={pageInfo.activePage}
browserFields={browserFields}
filterQuery={filterQuery}
data={nonDeletedEvents}
defaultCellActions={defaultCellActions}
filterQuery={filterQuery}
filterStatus={filterStatus}
hasAlertsCrud={hasAlertsCrud}
id={id}
indexNames={indexNames}
isEventViewer={true}
itemsPerPageOptions={itemsPerPageOptions}
leadingControlColumns={leadingControlColumns}
loadPage={loadPage}
onRuleChange={onRuleChange}
querySize={pageInfo.querySize}
refetch={refetch}
renderCellValue={renderCellValue}
rowRenderers={rowRenderers}
tabType={TimelineTabs.query}
tableView={tableView}
tabType={TimelineTabs.query}
totalItems={totalCountMinusDeleted}
totalPages={calculateTotalPages({
itemsCount: totalCountMinusDeleted,
itemsPerPage,
})}
totalItems={totalCountMinusDeleted}
unit={unit}
filterStatus={filterStatus}
leadingControlColumns={leadingControlColumns}
trailingControlColumns={trailingControlColumns}
refetch={refetch}
indexNames={indexNames}
unit={unit}
/>
{tableView === 'gridView' && (
<Footer

View file

@ -306,10 +306,10 @@ const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
data-test-subj={`events-container-loading-${loading}`}
>
<UpdatedFlexGroup gutterSize="s" justifyContent="flexEnd" alignItems="baseline">
<UpdatedFlexItem grow={false} show={!loading}>
<UpdatedFlexItem grow={false} $show={!loading}>
<InspectButton title={justTitle} inspect={inspect} loading={loading} />
</UpdatedFlexItem>
<UpdatedFlexItem grow={false} show={!loading}>
<UpdatedFlexItem grow={false} $show={!loading}>
<LastUpdatedAt updatedAt={updatedAt} />
</UpdatedFlexItem>
</UpdatedFlexGroup>

View file

@ -465,8 +465,8 @@ export const UpdatedFlexGroup = styled(EuiFlexGroup)`
right: 0px;
`;
export const UpdatedFlexItem = styled(EuiFlexItem)<{ show: boolean }>`
${({ show }) => (show ? '' : 'visibility: hidden;')}
export const UpdatedFlexItem = styled(EuiFlexItem)<{ $show: boolean }>`
${({ $show }) => ($show ? '' : 'visibility: hidden;')}
`;
export const AlertCount = styled.span`

View file

@ -15,3 +15,4 @@ export * from './mock_timeline_control_columns';
export * from './mock_timeline_data';
export * from './test_providers';
export * from './plugin_mock';
export * from './t_grid';

View file

@ -0,0 +1,123 @@
/*
* 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 { ALERT_START, ALERT_STATUS } from '@kbn/rule-data-utils';
import { TGridIntegratedProps } from '../components/t_grid/integrated';
import { mockBrowserFields, mockDocValueFields } from './browser_fields';
import { mockDataProviders } from './mock_data_providers';
import { ColumnHeaderOptions, TimelineId } from '../../common';
import { mockIndexNames, mockIndexPattern } from './index_pattern';
const columnHeaders: ColumnHeaderOptions[] = [
{
columnHeaderType: 'not-filtered',
displayAsText: 'Status',
id: ALERT_STATUS,
initialWidth: 79,
category: 'kibana',
type: 'string',
aggregatable: true,
actions: {
showSortAsc: {
label: 'Sort A-Z',
},
showSortDesc: {
label: 'Sort Z-A',
},
},
defaultSortDirection: 'desc',
display: {
key: null,
ref: null,
props: {
children: {
key: null,
ref: null,
props: {
children: 'Status',
},
_owner: null,
},
},
_owner: null,
},
isSortable: true,
},
{
columnHeaderType: 'not-filtered',
displayAsText: 'Triggered',
id: ALERT_START,
initialWidth: 176,
category: 'kibana',
type: 'date',
aggregatable: true,
actions: {
showSortAsc: {
label: 'Sort A-Z',
},
showSortDesc: {
label: 'Sort Z-A',
},
},
defaultSortDirection: 'desc',
display: {
key: null,
ref: null,
props: {
children: {
key: null,
ref: null,
props: {
children: 'Triggered',
},
_owner: null,
},
},
_owner: null,
},
isSortable: true,
},
];
export const tGridIntegratedProps: TGridIntegratedProps = {
additionalFilters: null,
browserFields: mockBrowserFields,
columns: columnHeaders,
dataProviders: mockDataProviders,
deletedEventIds: [],
docValueFields: mockDocValueFields,
end: '2021-08-19T00:30:00.000Z',
entityType: 'alerts',
filterStatus: 'open',
filters: [],
globalFullScreen: false,
graphEventId: undefined,
hasAlertsCrud: true,
id: TimelineId.active,
indexNames: mockIndexNames,
indexPattern: mockIndexPattern,
isLive: false,
isLoadingIndexPattern: false,
itemsPerPage: 25,
itemsPerPageOptions: [10, 25, 50, 100],
kqlMode: 'filter',
query: {
query: '_id: "28bf94ad5d16b5fded1b258127aa88792f119d7e018c35869121613385619e1e"',
language: 'kuery',
},
renderCellValue: () => null,
rowRenderers: [],
sort: [
{
columnId: '@timestamp',
columnType: 'date',
sortDirection: 'desc',
},
],
start: '2021-05-01T18:14:07.522Z',
tGridEventRenderedViewEnabled: true,
trailingControlColumns: [],
};