Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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 { Filter } from '@kbn/es-query';
import type { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types';

export const euidDslFilterToPageFilters = (dsl: QueryDslQueryContainer | undefined): Filter[] => {
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.

euidDslFilterToPageFilters was moved to explore/helpers.ts, but the original definition still lives in users/pages/details/helpers.ts and it's no longer imported anywhere. Can we remove it?

if (dsl == null) return [];
return [{ meta: { alias: null, negate: false, disabled: false }, query: dsl }];
};
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ export const HostDetailsTabs = React.memo<HostDetailsTabsProps>(
indexNames,
hostDetailsPagePath,
hostDetailsFilter,
hostDetailsIdentityFilterQuery,
identityFields,
entityId,
entityRecord,
}) => {
const { from, to, isInitializing, deleteQuery, setQuery } = useGlobalTime();

Expand All @@ -48,6 +48,8 @@ export const HostDetailsTabs = React.memo<HostDetailsTabsProps>(
indexNames,
identityFields,
entityId,
entityRecord,
hostName: detailName,
};

const tabPath = (tab: HostsTableType) => `${hostDetailsPagePath}/:tabName(${tab})`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { noop } from 'lodash/fp';
import React, { useCallback, useEffect, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import type { Filter } from '@kbn/es-query';
import { buildEsQuery } from '@kbn/es-query';
import { getEsQueryConfig } from '@kbn/data-plugin/common';
import { useUpdateAssetCriticality } from '../../../../entity_analytics/api/hooks/use_update_asset_criticality';
Expand Down Expand Up @@ -64,11 +63,7 @@ import { HostDetailsTabs } from './details_tabs';
import { navTabsHostDetails } from './nav_tabs';
import type { HostDetailsProps } from './types';
import { HostsType } from '../../store/model';
import { getHostDetailsPageFilters, getIdentityFieldsPageFilters } from './helpers';
import {
identityFieldsHaveUsableValues,
mergeLegacyIdentityWhenStoreEntityMissing,
} from '../../../../flyout/document_details/shared/utils';
import { getHostDetailsPageFilters } from './helpers';
import { useGlobalFullScreen } from '../../../../common/containers/use_full_screen';
import { Display } from '../display';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
Expand Down Expand Up @@ -96,6 +91,7 @@ import { NO_CORRESPONDING_ENTITY_EXISTS } from '../../../../flyout/entity_detail
import { useSecurityDefaultPatterns } from '../../../../data_view_manager/hooks/use_security_default_patterns';
import { sourcererSelectors } from '../../../../sourcerer/store';
import type { Entity } from '../../../../../common/api/entity_analytics';
import { euidDslFilterToPageFilters } from '../../../helpers';

const ES_HOST_FIELD = 'host.name';
const HostOverviewManage = manageQuery(HostOverview);
Expand Down Expand Up @@ -186,11 +182,6 @@ const HostDetailsComponent: React.FC<HostDetailsProps> = ({
[identityFields, detailName]
);

const hostDetailsPageFilters: Filter[] = useMemo(
() => getHostDetailsPageFilters(detailName),
[detailName]
);

const isEnterprisePlus = useLicense().isEnterprise();

const narrowDateRange = useCallback<NarrowDateRange>(
Expand Down Expand Up @@ -247,24 +238,23 @@ const HostDetailsComponent: React.FC<HostDetailsProps> = ({
entityStoreV2Enabled && !entityFromStoreResult.isLoading && !entityFromStoreResult.entityRecord;

const hostDetailsEventsPageFilters = useMemo(() => {
// Builds Kibana (not ES DSL) filters
// Fallback to host.name filter if EUID-based filter cannot be built for any reason
const legacyFilters = getHostDetailsPageFilters(detailName);
if (!entityStoreV2Enabled || noEntityInStore) {
return getHostDetailsPageFilters(detailName);
return legacyFilters;
}
const fromStore =
euidApi?.euid?.getEntityIdentifiersFromDocument('host', entityFromStoreResult.entityRecord) ??
{};
const merged = mergeLegacyIdentityWhenStoreEntityMissing(fromStore, resolvedIdentityFields);
if (identityFieldsHaveUsableValues(merged)) {
return getIdentityFieldsPageFilters(merged);
}
return getHostDetailsPageFilters(detailName);
const entityDslFilter = euidApi?.euid?.dsl.getEuidFilterBasedOnDocument(
EntityType.host,
entityFromStoreResult.entityRecord
);
return entityDslFilter ? euidDslFilterToPageFilters(entityDslFilter) : legacyFilters;
}, [
detailName,
entityFromStoreResult.entityRecord,
entityStoreV2Enabled,
noEntityInStore,
euidApi?.euid,
resolvedIdentityFields,
]);

const oldSecurityDefaultPatterns =
Expand All @@ -274,6 +264,7 @@ const HostDetailsComponent: React.FC<HostDetailsProps> = ({
? experimentalSecurityDefaultIndexPatterns
: oldSecurityDefaultPatterns;

// observedHost.entityRecord returns entityStoreFromResult.entityRecord when entityStoreV2Enabled
const observedHost = useObservedHost(
detailName,
PageScope.explore,
Expand Down Expand Up @@ -316,46 +307,21 @@ const HostDetailsComponent: React.FC<HostDetailsProps> = ({
[entityId, entityStoreV2Enabled, observedHost.entityRecord?.entity?.id]
);

const [rawFilteredQuery, kqlError] = useMemo(() => {
const [rawFilteredQueryForHostDetailsIdentity, kqlError] = useMemo(() => {
try {
return [
buildEsQuery(
newDataViewPickerEnabled
? experimentalDataView
: dataViewSpecToViewBase(oldSourcererDataView),
[query],
[...hostDetailsPageFilters, ...globalFilters],
[...hostDetailsEventsPageFilters, ...globalFilters],
getEsQueryConfig(uiSettings)
),
];
} catch (e) {
return [undefined, e];
}
}, [
newDataViewPickerEnabled,
experimentalDataView,
oldSourcererDataView,
query,
hostDetailsPageFilters,
globalFilters,
uiSettings,
]);

const [rawFilteredQueryForHostDetailsIdentity] = useMemo(() => {
try {
return [
buildEsQuery(
newDataViewPickerEnabled
? experimentalDataView
: dataViewSpecToViewBase(oldSourcererDataView),
[query],
[...hostDetailsEventsPageFilters, ...globalFilters],
getEsQueryConfig(uiSettings)
),
];
} catch {
return [undefined];
}
}, [
newDataViewPickerEnabled,
experimentalDataView,
Expand All @@ -374,10 +340,9 @@ const HostDetailsComponent: React.FC<HostDetailsProps> = ({
[rawFilteredQueryForHostDetailsIdentity]
);

const stringifiedAdditionalFilters = JSON.stringify(rawFilteredQuery);
useInvalidFilterQuery({
id: ID,
filterQuery: stringifiedAdditionalFilters,
filterQuery: stringifiedHostDetailsIdentityFilterQuery,
kqlError,
query,
startDate: from,
Expand All @@ -391,17 +356,9 @@ const HostDetailsComponent: React.FC<HostDetailsProps> = ({
const { hasAlertsRead, hasIndexRead } = useAlertsPrivileges();
const canReadAlerts = hasAlertsRead && hasIndexRead;

const entityFilter = useMemo(
() => ({
field: ES_HOST_FIELD,
value: detailName,
}),
[detailName]
);

const additionalFilters = useMemo(
() => (rawFilteredQuery ? [rawFilteredQuery] : []),
[rawFilteredQuery]
() => (rawFilteredQueryForHostDetailsIdentity ? [rawFilteredQueryForHostDetailsIdentity] : []),
[rawFilteredQueryForHostDetailsIdentity]
);

const entity = useMemo(
Expand Down Expand Up @@ -581,14 +538,14 @@ const HostDetailsComponent: React.FC<HostDetailsProps> = ({
<EuiFlexItem>
<AlertsByStatus
signalIndexName={signalIndexName}
entityFilter={entityFilter}
entityType={EntityType.host}
entityRecord={entityStoreV2Enabled ? observedHost.entityRecord : 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.

small suggestion: I see that entityType and entityRecord props were introduced in #267728, but I think it could be useful to have a comment on AlertsByStatusProps saying when entityType + entityRecord is preferred over entityFilter, or not sure if entityFilter will be deprecated afterwards

identityFields={resolvedIdentityFields}
additionalFilters={additionalFilters}
/>
</EuiFlexItem>
<EuiFlexItem>
<AlertCountByRuleByStatus
entityFilter={entityFilter}
identityFields={resolvedIdentityFields}
signalIndexName={signalIndexName}
additionalFilters={additionalFilters}
Expand Down Expand Up @@ -620,16 +577,18 @@ const HostDetailsComponent: React.FC<HostDetailsProps> = ({
isInitializing={isInitializing}
deleteQuery={deleteQuery}
hostDetailsFilter={hostDetailsEventsPageFilters}
hostDetailsIdentityFilterQuery={stringifiedHostDetailsIdentityFilterQuery}
to={to}
from={from}
detailName={detailName}
type={HostsType.details}
setQuery={setQuery}
filterQuery={stringifiedAdditionalFilters}
entityRecord={
entityStoreV2Enabled ? observedHost.entityRecord ?? undefined : undefined
}
filterQuery={stringifiedHostDetailsIdentityFilterQuery}
hostDetailsPagePath={hostDetailsPagePath}
identityFields={resolvedIdentityFields}
entityId={entityId}
entityId={displayEntityId}
/>
</SecuritySolutionPageWrapper>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import type { Filter } from '@kbn/es-query';
import type { DataViewSpec } from '@kbn/data-plugin/common';
import type { EntityStoreRecord } from '../../../../flyout/entity_details/shared/hooks/use_entity_from_store';
import type { HostsTableType } from '../../store/model';
import type { HostsQueryProps } from '../types';
import type { NavTab } from '../../../../common/components/navigation/types';
Expand Down Expand Up @@ -43,16 +44,18 @@ export type HostDetailsNavTab = Record<KeyHostDetailsNavTab, NavTab>;
export type HostDetailsTabsProps = HostBodyComponentDispatchProps &
HostsQueryProps & {
indexNames: string[];
/**
* Filter for host identity (either generated from euidApi or fallback host.name filter)
*/
hostDetailsFilter: Filter[];
/**
* Serialized ES query built with {@link HostDetailsTabsProps.hostDetailsFilter} (identity fields
* when Entity Store v2). Used for the Events histogram, Authentications tab, and Risk tab;
* other tabs use {@link HostDetailsTabsProps.filterQuery} only.
* Stringified filter query that includes the host identity filter
* (either generated from euidApi or fallback host.name filter) and any global filters applied on the page.
*/
hostDetailsIdentityFilterQuery?: string;
filterQuery?: string;
dataViewSpec?: DataViewSpec;
type: hostsModel.HostsType;
identityFields?: Record<string, string>;
entityId?: string;
entityRecord?: EntityStoreRecord | null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
* 2.0.
*/

import React from 'react';
import React, { useMemo } from 'react';

import { AuthStackByField } from '../../../../../common/api/search_strategy/users/authentications';
import { MatrixHistogram } from '../../../../common/components/matrix_histogram';
import { AuthenticationsHostTable } from '../../../components/authentication/authentications_host_table';
import { histogramConfigs } from '../../../components/authentication/helpers';
Expand All @@ -18,28 +19,40 @@ const AuthenticationsQueryTabBodyComponent: React.FC<HostsComponentsQueryProps>
deleteQuery,
endDate,
filterQuery,
identityScopedFilterQuery,
indexNames,
skip,
setQuery,
startDate,
type,
}) => {
const effectiveFilterQuery = identityScopedFilterQuery ?? filterQuery;

const histogramFilterQuery = useMemo(() => {
const existsClause = {
exists: { field: AuthStackByField.userName },
};
if (!filterQuery) {
return JSON.stringify(existsClause);
}
try {
const parsed = typeof filterQuery === 'string' ? JSON.parse(filterQuery) : filterQuery;
return JSON.stringify({ bool: { filter: [parsed, existsClause] } });
} catch {
return JSON.stringify(existsClause);
}
}, [filterQuery]);
return (
<>
<MatrixHistogram
endDate={endDate}
filterQuery={effectiveFilterQuery}
filterQuery={histogramFilterQuery}
id={HISTOGRAM_QUERY_ID}
startDate={startDate}
{...histogramConfigs}
applyPageAndTabsFilters={false}
/>

<AuthenticationsHostTable
endDate={endDate}
filterQuery={effectiveFilterQuery}
filterQuery={filterQuery}
indexNames={indexNames}
setQuery={setQuery}
deleteQuery={deleteQuery}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ export type HostsComponentsQueryProps = QueryTabBodyProps & {
pageFilters?: Filter[];
skip: boolean;
setQuery: GlobalTimeArgs['setQuery'];
/**
* Host details: serialized ES query built with entity identity filters (Entity Store v2).
* Used by {@link AuthenticationsQueryTabBody} and {@link RiskDetailsTabBody} when set.
*/
identityScopedFilterQuery?: string;
};

export type AlertsComponentQueryProps = HostsComponentsQueryProps & {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import { UsersDetailsTabs } from './details_tabs';
import { navTabsUsersDetails } from './nav_tabs';
import type { UsersDetailsProps } from './types';
import { UsersType } from '../../store/model';
import { getUsersDetailsPageFilters, euidDslFilterToPageFilters } from './helpers';
import { getUsersDetailsPageFilters } from './helpers';
import { useGlobalFullScreen } from '../../../../common/containers/use_full_screen';
import { Display } from '../../../hosts/pages/display';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
Expand All @@ -90,6 +90,7 @@ import { useSecurityDefaultPatterns } from '../../../../data_view_manager/hooks/
import { sourcererSelectors } from '../../../../sourcerer/store';
import type { UserItem } from '../../../../../common/search_strategy';
import type { Entity } from '../../../../../common/api/entity_analytics';
import { euidDslFilterToPageFilters } from '../../../helpers';

const USERS_DETAILS_OVERVIEW_QUERY_ID = 'UsersDetailsQueryId';
const ES_USER_FIELD = 'user.name';
Expand Down
Loading