Skip to content

Commit

Permalink
Merge branch 'securitySolution/noteLimitAdvancedSetting' of https://g…
Browse files Browse the repository at this point in the history
…ithub.com/janmonschke/kibana into securitySolution/noteLimitAdvancedSetting
  • Loading branch information
janmonschke committed Oct 9, 2024
2 parents 52de3b8 + 46bd9a7 commit d6ba97a
Show file tree
Hide file tree
Showing 57 changed files with 1,494 additions and 480 deletions.
5 changes: 4 additions & 1 deletion x-pack/packages/kbn-cloud-security-posture-common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ export type {
CspSetupStatus,
} from './types/status';
export type { CspFinding, CspFindingResult } from './types/findings';
export type { CspVulnerabilityFinding } from './schema/vulnerabilities/csp_vulnerability_finding';
export type {
CspVulnerabilityFinding,
Vulnerability,
} from './schema/vulnerabilities/csp_vulnerability_finding';
export type { BenchmarksCisId } from './types/benchmark';
export type { VulnSeverity } from './types/vulnerabilities';
export * from './constants';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const VULNERABILITIES_FLYOUT_VISITS = 'vulnerabilities-flyout-visits';
export const OPEN_FINDINGS_FLYOUT = 'open-findings-flyout';
export const GROUP_BY_CLICK = 'group-by-click';
export const CHANGE_RULE_STATE = 'change-rule-state';
export const ENTITY_FLYOUT_VULNERABILITY_VIEW_VISITS = 'entity-flyout-vulnerability-view-visits';

type CloudSecurityUiCounters =
| typeof ENTITY_FLYOUT_MISCONFIGURATION_VIEW_VISITS
Expand All @@ -32,6 +33,7 @@ type CloudSecurityUiCounters =
| typeof CREATE_DETECTION_RULE_FROM_FLYOUT
| typeof CREATE_DETECTION_FROM_TABLE_ROW_ACTION
| typeof GROUP_BY_CLICK
| typeof ENTITY_FLYOUT_VULNERABILITY_VIEW_VISITS
| typeof CHANGE_RULE_STATE;

export class UiMetricService {
Expand Down
4 changes: 3 additions & 1 deletion x-pack/packages/kbn-cloud-security-posture/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ export type { NavFilter } from './src/hooks/use_navigate_findings';
export { showErrorToast } from './src/utils/show_error_toast';
export { encodeQuery, decodeQuery } from './src/utils/query_utils';
export { CspEvaluationBadge } from './src/components/csp_evaluation_badge';
export { getSeverityStatusColor } from './src/utils/get_vulnerability_colors';
export { getSeverityStatusColor, getCvsScoreColor } from './src/utils/get_vulnerability_colors';
export { getSeverityText } from './src/utils/get_vulnerability_text';
export { getVulnerabilityStats, hasVulnerabilitiesData } from './src/utils/vulnerability_helpers';
export { CVSScoreBadge, SeverityStatusBadge } from './src/components/vulnerability_badges';
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import React from 'react';
import { css } from '@emotion/react';
import { float } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import type { VulnSeverity } from '@kbn/cloud-security-posture-common';
import { getSeverityStatusColor } from '@kbn/cloud-security-posture';
import { getCvsScoreColor } from '../common/utils/get_vulnerability_colors';
import { VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ } from './test_subjects';
import { getCvsScoreColor, getSeverityStatusColor } from '../utils/get_vulnerability_colors';

const VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ = 'vulnerabilities_cvss_score_badge';

interface CVSScoreBadgeProps {
score?: float;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const useMisconfigurationPreview = (options: UseCspOptions) => {
params: buildMisconfigurationsFindingsQuery(options, rulesStates!),
})
);
if (!aggregations && !options.ignore_unavailable)
if (!aggregations && options.ignore_unavailable === false)
throw new Error('expected aggregations to be defined');
return {
count: getMisconfigurationAggregationCount(aggregations?.count?.buckets),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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 { useQuery } from '@tanstack/react-query';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { lastValueFrom } from 'rxjs';
import type { IKibanaSearchResponse, IKibanaSearchRequest } from '@kbn/search-types';
import {
SearchRequest,
SearchResponse,
AggregationsMultiBucketAggregateBase,
AggregationsStringRareTermsBucketKeys,
} from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest';
import type { CoreStart } from '@kbn/core/public';
import type { CspClientPluginStartDeps, UseCspOptions } from '../../type';
import { showErrorToast } from '../..';
import { getVulnerabilitiesAggregationCount, getVulnerabilitiesQuery } from '../utils/hooks_utils';

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

interface FindingsAggs {
count: AggregationsMultiBucketAggregateBase<AggregationsStringRareTermsBucketKeys>;
}

export const useVulnerabilitiesFindings = (options: UseCspOptions) => {
const {
data,
notifications: { toasts },
} = useKibana<CoreStart & CspClientPluginStartDeps>().services;
/**
* We're using useInfiniteQuery in this case to allow the user to fetch more data (if available and up to 10k)
* useInfiniteQuery differs from useQuery because it accumulates and caches a chunk of data from the previous fetches into an array
* it uses the getNextPageParam to know if there are more pages to load and retrieve the position of
* the last loaded record to be used as a from parameter to fetch the next chunk of data.
*/
return useQuery(
['csp_vulnerabilities_findings', { params: options }],
async ({ pageParam }) => {
const {
rawResponse: { aggregations, hits },
} = await lastValueFrom(
data.search.search<LatestFindingsRequest, LatestFindingsResponse>({
params: getVulnerabilitiesQuery(options, pageParam),
})
);

return {
count: getVulnerabilitiesAggregationCount(aggregations?.count?.buckets),
rows: hits.hits.map((finding) => ({
vulnerability: finding._source?.vulnerability,
resource: finding._source?.resource,
})) as Array<Pick<CspVulnerabilityFinding, 'vulnerability' | 'resource'>>,
};
},
{
keepPreviousData: true,
enabled: options.enabled,
onError: (err: Error) => showErrorToast(toasts, err),
}
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,11 @@ import {
AggregationsMultiBucketAggregateBase,
AggregationsStringRareTermsBucketKeys,
} from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import {
CDR_VULNERABILITIES_INDEX_PATTERN,
LATEST_VULNERABILITIES_RETENTION_POLICY,
} from '@kbn/cloud-security-posture-common';
import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest';
import type { CoreStart } from '@kbn/core/public';
import type { CspClientPluginStartDeps, UseCspOptions } from '../../type';
import { showErrorToast } from '../..';
import {
getFindingsCountAggQueryVulnerabilities,
getVulnerabilitiesAggregationCount,
} from '../utils/hooks_utils';
import { getVulnerabilitiesAggregationCount, getVulnerabilitiesQuery } from '../utils/hooks_utils';

type LatestFindingsRequest = IKibanaSearchRequest<SearchRequest>;
type LatestFindingsResponse = IKibanaSearchResponse<
Expand All @@ -36,30 +29,6 @@ interface FindingsAggs {
count: AggregationsMultiBucketAggregateBase<AggregationsStringRareTermsBucketKeys>;
}

const getVulnerabilitiesQuery = ({ query }: UseCspOptions, isPreview = false) => ({
index: CDR_VULNERABILITIES_INDEX_PATTERN,
size: 0,
aggs: getFindingsCountAggQueryVulnerabilities(),
ignore_unavailable: true,
query: {
...query,
bool: {
...query?.bool,
filter: [
...(query?.bool?.filter ?? []),
{
range: {
'@timestamp': {
gte: `now-${LATEST_VULNERABILITIES_RETENTION_POLICY}`,
lte: 'now',
},
},
},
],
},
},
});

export const useVulnerabilitiesPreview = (options: UseCspOptions) => {
const {
data,
Expand All @@ -73,7 +42,7 @@ export const useVulnerabilitiesPreview = (options: UseCspOptions) => {
rawResponse: { aggregations },
} = await lastValueFrom(
data.search.search<LatestFindingsRequest, LatestFindingsResponse>({
params: getVulnerabilitiesQuery(options),
params: getVulnerabilitiesQuery(options, true),
})
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { euiThemeVars } from '@kbn/ui-theme';
import { getSeverityStatusColor } from './get_vulnerability_colors';
import { getCvsScoreColor, getSeverityStatusColor } from './get_vulnerability_colors';
describe('getSeverityStatusColor', () => {
it('should return the correct color for LOW severity', () => {
expect(getSeverityStatusColor('LOW')).toBe(euiThemeVars.euiColorVis0);
Expand All @@ -28,3 +28,25 @@ describe('getSeverityStatusColor', () => {
expect(getSeverityStatusColor('UNKNOWN')).toBe('#aaa');
});
});

describe('getCvsScoreColor', () => {
it('returns correct color for low severity score', () => {
expect(getCvsScoreColor(1.5)).toBe(euiThemeVars.euiColorVis0);
});

it('returns correct color for medium severity score', () => {
expect(getCvsScoreColor(5.5)).toBe(euiThemeVars.euiColorVis7);
});

it('returns correct color for high severity score', () => {
expect(getCvsScoreColor(7.9)).toBe(euiThemeVars.euiColorVis9);
});

it('returns correct color for critical severity score', () => {
expect(getCvsScoreColor(10.0)).toBe(euiThemeVars.euiColorDanger);
});

it('returns correct color for low severity score for undefined value', () => {
expect(getCvsScoreColor(-0.2)).toBe(euiThemeVars.euiColorVis0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ import { euiThemeVars } from '@kbn/ui-theme';
import type { VulnSeverity } from '@kbn/cloud-security-posture-common';
import { VULNERABILITIES_SEVERITY } from '@kbn/cloud-security-posture-common';

export const getCvsScoreColor = (score: number): string | undefined => {
if (score <= 4) {
return euiThemeVars.euiColorVis0; // low severity
} else if (score >= 4 && score <= 7) {
return euiThemeVars.euiColorVis7; // medium severity
} else if (score >= 7 && score <= 9) {
return euiThemeVars.euiColorVis9; // high severity
} else if (score >= 9) {
return euiThemeVars.euiColorDanger; // critical severity
}
};

export const getSeverityStatusColor = (severity: VulnSeverity): string => {
switch (severity) {
case VULNERABILITIES_SEVERITY.LOW:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import {
CDR_MISCONFIGURATIONS_INDEX_PATTERN,
CDR_VULNERABILITIES_INDEX_PATTERN,
LATEST_FINDINGS_RETENTION_POLICY,
LATEST_VULNERABILITIES_RETENTION_POLICY,
} from '@kbn/cloud-security-posture-common';
import type { CspBenchmarkRulesStates } from '@kbn/cloud-security-posture-common/schema/rules/latest';
import { buildMutedRulesFilter } from '@kbn/cloud-security-posture-common';
Expand Down Expand Up @@ -161,3 +163,31 @@ export const getFindingsCountAggQueryVulnerabilities = () => ({
},
},
});

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

const buildVulnerabilityFindingsQueryWithFilters = (query: UseCspOptions['query']) => {
return {
...query,
bool: {
...query?.bool,
filter: [
...(query?.bool?.filter ?? []),
{
range: {
'@timestamp': {
gte: `now-${LATEST_VULNERABILITIES_RETENTION_POLICY}`,
lte: 'now',
},
},
},
],
},
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* 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 { euiThemeVars } from '@kbn/ui-theme';
import { getVulnerabilityStats } from './vulnerability_helpers';
import { i18n } from '@kbn/i18n';

describe('getVulnerabilitiesAggregationCount', () => {
it('should return empty array when all severity count is 0', () => {
const result = getVulnerabilityStats({ critical: 0, high: 0, medium: 0, low: 0, none: 0 });
expect(result).toEqual([]);
});

it('should return stats for low, medium, high, and critical vulnerabilities', () => {
const result = getVulnerabilityStats({ critical: 1, high: 2, medium: 3, low: 4, none: 5 });

expect(result).toEqual([
{
key: i18n.translate(
'xpack.securitySolution.flyout.right.insights.vulnerabilities.noneVulnerabilitiesText',
{
defaultMessage: 'None',
}
),
count: 5,
color: '#aaa',
},
{
key: i18n.translate(
'xpack.securitySolution.flyout.right.insights.vulnerabilities.lowVulnerabilitiesText',
{
defaultMessage: 'Low',
}
),
count: 4,
color: euiThemeVars.euiColorVis0,
},
{
key: i18n.translate(
'xpack.securitySolution.flyout.right.insights.vulnerabilities.mediumVulnerabilitiesText',
{
defaultMessage: 'Medium',
}
),
count: 3,
color: euiThemeVars.euiColorVis5_behindText,
},
{
key: i18n.translate(
'xpack.securitySolution.flyout.right.insights.vulnerabilities.highVulnerabilitiesText',
{
defaultMessage: 'High',
}
),
count: 2,
color: euiThemeVars.euiColorVis9_behindText,
},
{
key: i18n.translate(
'xpack.securitySolution.flyout.right.insights.vulnerabilities.CriticalVulnerabilitiesText',
{
defaultMessage: 'Critical',
}
),
count: 1,
color: euiThemeVars.euiColorDanger,
},
]);
});
});
Loading

0 comments on commit d6ba97a

Please sign in to comment.