[EDR Workflows] Limit Live Query look back (#171207)

closes https://github.com/elastic/kibana/issues/169666

Add additional filtering of action results by specifying time range.
This commit is contained in:
Konrad Szwarc 2023-11-15 15:47:47 +01:00 committed by GitHub
parent 362ef64751
commit 12a09b8aba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 54 additions and 12 deletions

View file

@ -82,4 +82,5 @@ export interface ActionResultsStrategyResponse
export interface ActionResultsRequestOptions extends RequestOptionsPaginated {
actionId: string;
startDate?: string;
}

View file

@ -21,5 +21,6 @@ export interface ResultsStrategyResponse extends IEsSearchResponse {
export interface ResultsRequestOptions extends Omit<RequestOptionsPaginated, 'sort'> {
actionId: string;
agentId?: string;
startDate?: string;
sort: SortField[];
}

View file

@ -16,6 +16,7 @@ import { useActionResultsPrivileges } from './use_action_privileges';
interface ActionResultsSummaryProps {
actionId: string;
startDate?: string;
expirationDate?: string;
agentIds?: string[];
error?: string;
@ -32,6 +33,7 @@ const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
expirationDate,
agentIds,
error,
startDate,
}) => {
const [pageIndex] = useState(0);
const [pageSize] = useState(50);
@ -46,6 +48,7 @@ const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
data: { aggregations, edges },
} = useActionResults({
actionId,
startDate,
activePage: pageIndex,
agentIds,
limit: pageSize,
@ -158,7 +161,7 @@ const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
setIsLive(() => {
if (!agentIds?.length || expired || error) return false;
return !!(aggregations.totalResponded !== agentIds?.length);
return aggregations.totalResponded !== agentIds?.length;
});
}, [agentIds?.length, aggregations.totalResponded, error, expired]);

View file

@ -34,6 +34,7 @@ export interface ResultsArgs {
export interface UseActionResults {
actionId: string;
activePage: number;
startDate?: string;
agentIds?: string[];
direction: Direction;
limit: number;
@ -51,6 +52,7 @@ export const useActionResults = ({
limit,
sortField,
kuery,
startDate,
skip = false,
isLive = false,
}: UseActionResults) => {
@ -64,6 +66,7 @@ export const useActionResults = ({
data.search.search<ActionResultsRequestOptions, ActionResultsStrategyResponse>(
{
actionId,
startDate,
factoryQueryType: OsqueryQueries.actionResults,
kuery,
pagination: generateTablePaginationOptions(activePage, limit),

View file

@ -222,6 +222,7 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
singleQueryDetails?.action_id ? (
<ResultTabs
actionId={singleQueryDetails?.action_id}
startDate={liveQueryDetails?.['@timestamp']}
ecsMapping={serializedData.ecs_mapping}
endDate={singleQueryDetails?.expiration}
agentIds={singleQueryDetails?.agents}
@ -232,6 +233,7 @@ const LiveQueryFormComponent: React.FC<LiveQueryFormProps> = ({
singleQueryDetails?.action_id,
singleQueryDetails?.expiration,
singleQueryDetails?.agents,
liveQueryDetails,
serializedData.ecs_mapping,
liveQueryActionId,
]

View file

@ -92,6 +92,7 @@ const ResultsTableComponent: React.FC<ResultsTableComponentProps> = ({
data: { aggregations },
} = useActionResults({
actionId,
startDate,
activePage: 0,
agentIds,
limit: 0,
@ -140,6 +141,7 @@ const ResultsTableComponent: React.FC<ResultsTableComponentProps> = ({
const { data: allResultsData, isLoading } = useAllResults({
actionId,
startDate,
activePage: pagination.pageIndex,
limit: pagination.pageSize,
isLive,

View file

@ -33,6 +33,7 @@ export interface ResultsArgs {
interface UseAllResults {
actionId: string;
activePage: number;
startDate?: string;
limit: number;
sort: Array<{ field: string; direction: Direction }>;
kuery?: string;
@ -43,6 +44,7 @@ interface UseAllResults {
export const useAllResults = ({
actionId,
activePage,
startDate,
limit,
sort,
kuery,
@ -59,6 +61,7 @@ export const useAllResults = ({
data.search.search<ResultsRequestOptions, ResultsStrategyResponse>(
{
actionId,
startDate,
factoryQueryType: OsqueryQueries.results,
kuery,
pagination: generateTablePaginationOptions(activePage, limit),

View file

@ -63,6 +63,7 @@ const ResultTabsComponent: React.FC<ResultTabsProps> = ({
'data-test-subj': 'osquery-status-tab',
content: (
<ActionResultsSummary
startDate={startDate}
actionId={actionId}
agentIds={agentIds}
expirationDate={endDate}

View file

@ -8,6 +8,7 @@
import type { ISearchRequestParams } from '@kbn/data-plugin/common';
import { AGENT_ACTIONS_RESULTS_INDEX } from '@kbn/fleet-plugin/common';
import { isEmpty } from 'lodash';
import moment from 'moment';
import { ACTION_RESPONSES_INDEX } from '../../../../../../common/constants';
import type { ActionResultsRequestOptions } from '../../../../../../common/search_strategy';
import { getQueryFilter } from '../../../../../utils/build_query';
@ -15,19 +16,32 @@ import { getQueryFilter } from '../../../../../utils/build_query';
export const buildActionResultsQuery = ({
actionId,
kuery,
// pagination: { activePage, querySize },
startDate,
sort,
componentTemplateExists,
}: ActionResultsRequestOptions): ISearchRequestParams => {
const actionIdQuery = `action_id: ${actionId}`;
let filter = actionIdQuery;
let filter = `action_id: ${actionId}`;
if (!isEmpty(kuery)) {
filter = filter + ` AND ${kuery}`;
}
const filterQuery = getQueryFilter({ filter });
const timeRangeFilter =
startDate && !isEmpty(startDate)
? [
{
range: {
started_at: {
gte: startDate,
lte: moment(startDate).clone().add(30, 'minutes').toISOString(),
},
},
},
]
: [];
const dslQuery = {
const filterQuery = [...timeRangeFilter, getQueryFilter({ filter })];
return {
allow_no_indices: true,
index: componentTemplateExists
? `${ACTION_RESPONSES_INDEX}-default*`
@ -84,6 +98,4 @@ export const buildActionResultsQuery = ({
],
},
};
return dslQuery;
};

View file

@ -7,6 +7,7 @@
import type { ISearchRequestParams } from '@kbn/data-plugin/common';
import { isEmpty } from 'lodash';
import moment from 'moment/moment';
import { getQueryFilter } from '../../../../utils/build_query';
import { OSQUERY_INTEGRATION_NAME } from '../../../../../common';
import type { ResultsRequestOptions } from '../../../../../common/search_strategy';
@ -16,6 +17,7 @@ export const buildResultsQuery = ({
agentId,
kuery,
sort,
startDate,
pagination: { activePage, querySize },
}: ResultsRequestOptions): ISearchRequestParams => {
const actionIdQuery = `action_id: ${actionId}`;
@ -25,9 +27,22 @@ export const buildResultsQuery = ({
filter = filter + ` AND ${kuery}`;
}
const filterQuery = getQueryFilter({ filter });
const timeRangeFilter =
startDate && !isEmpty(startDate)
? [
{
range: {
'@timestamp': {
gte: startDate,
lte: moment(startDate).clone().add(30, 'minutes').toISOString(),
},
},
},
]
: [];
const filterQuery = [...timeRangeFilter, getQueryFilter({ filter })];
const dslQuery = {
return {
allow_no_indices: true,
index: `logs-${OSQUERY_INTEGRATION_NAME}.result*`,
ignore_unavailable: true,
@ -58,6 +73,4 @@ export const buildResultsQuery = ({
})) ?? [],
},
};
return dslQuery;
};

View file

@ -45,6 +45,7 @@ export const osquerySearchStrategyProvider = <T extends FactoryQueryTypes>(
...('pagination' in request ? { pagination: request.pagination } : {}),
...('sort' in request ? { sort: request.sort } : {}),
...('actionId' in request ? { actionId: request.actionId } : {}),
...('startDate' in request ? { startDate: request.startDate } : {}),
...('agentId' in request ? { agentId: request.agentId } : {}),
} as StrategyRequestType<T>;