Skip to content

Commit

Permalink
[Cloud Security] Contextual flyout table sorting (elastic#203950)
Browse files Browse the repository at this point in the history
## Summary

This PR adds sorting capability to Alerts, Misconfiguration and
Vulnerabilities table


https://github.com/user-attachments/assets/12cc203e-470c-4166-bb8a-e2b64f4141e3
  • Loading branch information
animehart authored Jan 3, 2025
1 parent fe988fa commit 9933cc6
Show file tree
Hide file tree
Showing 9 changed files with 337 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,18 @@ describe('test helper methods', () => {
});

describe('buildEntityAlertsQuery', () => {
const getExpectedAlertsQuery = (size?: number, severity?: string) => {
const field: 'host.name' | 'user.name' = 'host.name';
const query = 'exampleHost';
const to = 'Tomorrow';
const from = 'Today';
const getExpectedAlertsQuery = (
size?: number,
severity?: string,
sortField?: string,
sortDirection?: 'asc' | 'desc'
) => {
return {
sort: sortField ? [{ [sortField]: sortDirection }] : [],
size: size || 0,
_source: false,
fields: [
Expand Down Expand Up @@ -379,37 +389,64 @@ describe('test helper methods', () => {
};

it('should return the correct query when given all params', () => {
const field = 'host.name';
const query = 'exampleHost';
const to = 'Tomorrow';
const from = 'Today';
const size = 100;
const testObjectParams = {
field,
to,
from,
queryValue: query,
size,
};

expect(buildEntityAlertsQuery(field, to, from, query, size)).toEqual(
getExpectedAlertsQuery(size)
);
expect(buildEntityAlertsQuery(testObjectParams)).toEqual(getExpectedAlertsQuery(size));
});

it('should return the correct query when not given size', () => {
const field = 'host.name';
const query = 'exampleHost';
const to = 'Tomorrow';
const from = 'Today';
const size = undefined;
const testObjectParams = {
field,
to,
from,
queryValue: query,
size,
};

expect(buildEntityAlertsQuery(field, to, from, query)).toEqual(getExpectedAlertsQuery(size));
expect(buildEntityAlertsQuery(testObjectParams)).toEqual(getExpectedAlertsQuery(size));
});

it('should return the correct query when given severity query', () => {
const field = 'host.name';
const query = 'exampleHost';
const to = 'Tomorrow';
const from = 'Today';
const size = undefined;
const severity = 'low';
const testObjectParams = {
field,
to,
from,
queryValue: query,
size,
severity,
};

expect(buildEntityAlertsQuery(testObjectParams)).toEqual(getExpectedAlertsQuery(size, 'low'));
});

it('should return the correct query when given sort parameter', () => {
const size = undefined;
const severity = 'low';
const sortField = 'sort.field';
const sortDirection = 'asc';
const testObjectParams = {
field,
to,
from,
queryValue: query,
size,
severity,
sortField,
sortDirection,
};

expect(buildEntityAlertsQuery(field, to, from, query, size, severity)).toEqual(
getExpectedAlertsQuery(size, 'low')
expect(buildEntityAlertsQuery(testObjectParams)).toEqual(
getExpectedAlertsQuery(size, 'low', sortField, sortDirection)
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ import { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types';
import { i18n } from '@kbn/i18n';
import type { CspBenchmarkRulesStates } from '../schema/rules/latest';

interface BuildEntityAlertsQueryParams {
field: 'user.name' | 'host.name';
to: string;
from: string;
queryValue?: string;
size?: number;
severity?: string;
sortField?: string;
sortDirection?: string;
}

export const defaultErrorMessage = i18n.translate(
'sharedPlatformPackages.csp.common.utils.helpers.unknownError',
{
Expand Down Expand Up @@ -106,17 +117,20 @@ export const buildVulnerabilityEntityFlyoutPreviewQuery = (
return buildGenericEntityFlyoutPreviewQuery(field, queryValue, status, queryField);
};

export const buildEntityAlertsQuery = (
field: string,
to: string,
from: string,
queryValue?: string,
size?: number,
severity?: string
) => {
export const buildEntityAlertsQuery = ({
field,
to,
from,
queryValue = '',
size = 0,
severity,
sortField,
sortDirection,
}: BuildEntityAlertsQueryParams) => {
return {
size: size || 0,
_source: false,
sort: sortField ? [{ [sortField]: sortDirection }] : [],
fields: [
'_id',
'_index',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ import {
getMisconfigurationAggregationCount,
} from '../utils/hooks_utils';

export enum MISCONFIGURATION {
RESULT_EVALUATION = 'result.evaluation',
RULE_NAME = 'rule.name',
}
export interface MisconfigurationFindingTableDetailsFields {
[MISCONFIGURATION.RESULT_EVALUATION]: string;
[MISCONFIGURATION.RULE_NAME]: string;
}

export type MisconfigurationFindingDetailFields = Pick<CspFinding, 'rule' | 'resource'> &
MisconfigurationFindingTableDetailsFields;

export const useMisconfigurationFindings = (options: UseCspOptions) => {
const {
data,
Expand Down Expand Up @@ -50,10 +62,11 @@ export const useMisconfigurationFindings = (options: UseCspOptions) => {
return {
count: getMisconfigurationAggregationCount(aggregations?.count.buckets),
rows: hits.hits.map((finding) => ({
result: finding._source?.result,
rule: finding?._source?.rule,
resource: finding?._source?.resource,
})) as Array<Pick<CspFinding, 'result' | 'rule' | 'resource'>>,
[MISCONFIGURATION.RULE_NAME]: finding?._source?.rule?.name,
[MISCONFIGURATION.RESULT_EVALUATION]: finding._source?.result?.evaluation,
})) as MisconfigurationFindingDetailFields[],
};
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,43 @@ import {
AggregationsMultiBucketAggregateBase,
AggregationsStringRareTermsBucketKeys,
} from '@elastic/elasticsearch/lib/api/types';
import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest';
import type {
CspVulnerabilityFinding,
Vulnerability,
} from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest';
import type { CoreStart } from '@kbn/core/public';
import type { CspClientPluginStartDeps, UseCspOptions } from '../types';
import { showErrorToast } from '../..';
import { getVulnerabilitiesAggregationCount, getVulnerabilitiesQuery } from '../utils/hooks_utils';

export enum VULNERABILITY {
ID = 'vulnerability.id',
SEVERITY = 'vulnerability.severity',
PACKAGE_NAME = 'vulnerability.package.name',
}

type LatestFindingsRequest = IKibanaSearchRequest<SearchRequest>;
type LatestFindingsResponse = IKibanaSearchResponse<
SearchResponse<CspVulnerabilityFinding, FindingsAggs>
>;

export interface VulnerabilitiesPackage extends Vulnerability {
package: {
name: string;
version: string;
};
}

export interface VulnerabilitiesFindingTableDetailsFields {
[VULNERABILITY.ID]: string;
[VULNERABILITY.SEVERITY]: string;
[VULNERABILITY.PACKAGE_NAME]: string;
}

export type VulnerabilitiesFindingDetailFields = Pick<Vulnerability, 'score'> &
Pick<CspVulnerabilityFinding, 'vulnerability' | 'resource'> &
VulnerabilitiesFindingTableDetailsFields;

interface FindingsAggs {
count: AggregationsMultiBucketAggregateBase<AggregationsStringRareTermsBucketKeys>;
}
Expand Down Expand Up @@ -56,7 +82,11 @@ export const useVulnerabilitiesFindings = (options: UseCspOptions) => {
rows: hits.hits.map((finding) => ({
vulnerability: finding._source?.vulnerability,
resource: finding._source?.resource,
})) as Array<Pick<CspVulnerabilityFinding, 'vulnerability' | 'resource'>>,
score: finding._source?.vulnerability?.score,
[VULNERABILITY.ID]: finding._source?.vulnerability?.id,
[VULNERABILITY.SEVERITY]: finding._source?.vulnerability?.severity,
[VULNERABILITY.PACKAGE_NAME]: finding._source?.package?.name,
})) as VulnerabilitiesFindingDetailFields[],
};
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ export interface CspBaseEsQuery {
}

export interface UseCspOptions extends CspBaseEsQuery {
sort: string[][];
sort: Array<{
[key: string]: string;
}>;
enabled: boolean;
pageSize: number;
ignore_unavailable?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,19 @@ export const getMisconfigurationAggregationCount = (
};

export const buildMisconfigurationsFindingsQuery = (
{ query }: UseCspOptions,
{ query, sort }: UseCspOptions,
rulesStates: CspBenchmarkRulesStates,
isPreview = false
) => {
const mutedRulesFilterQuery = buildMutedRulesFilter(rulesStates);

return {
index: CDR_MISCONFIGURATIONS_INDEX_PATTERN,
size: isPreview ? 0 : 500,
aggs: getFindingsCountAggQueryMisconfiguration(),
ignore_unavailable: true,
query: buildMisconfigurationsFindingsQueryWithFilters(query, mutedRulesFilterQuery),
_source: MISCONFIGURATIONS_SOURCE_FIELDS,
sort,
};
};

Expand Down Expand Up @@ -163,12 +163,13 @@ export const getFindingsCountAggQueryVulnerabilities = () => ({
},
});

export const getVulnerabilitiesQuery = ({ query }: UseCspOptions, isPreview = false) => ({
export const getVulnerabilitiesQuery = ({ query, sort }: UseCspOptions, isPreview = false) => ({
index: CDR_VULNERABILITIES_INDEX_PATTERN,
size: isPreview ? 0 : 500,
aggs: getFindingsCountAggQueryVulnerabilities(),
ignore_unavailable: true,
query: buildVulnerabilityFindingsQueryWithFilters(query),
sort,
});

const buildVulnerabilityFindingsQueryWithFilters = (query: UseCspOptions['query']) => {
Expand Down
Loading

0 comments on commit 9933cc6

Please sign in to comment.