diff --git a/x-pack/packages/kbn-cloud-security-posture-common/index.ts b/x-pack/packages/kbn-cloud-security-posture-common/index.ts
index e01401f37ef23..d5ee781c39b20 100644
--- a/x-pack/packages/kbn-cloud-security-posture-common/index.ts
+++ b/x-pack/packages/kbn-cloud-security-posture-common/index.ts
@@ -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';
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx
index 09c2989c1eb23..e8dde902a9f46 100644
--- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx
@@ -108,11 +108,11 @@ export const LatestVulnerabilitiesTable = ({
});
const createVulnerabilityRuleFn = (rowIndex: number) => {
- const finding = getCspVulnerabilityFinding(rows[rowIndex].raw._source);
- if (!finding) return;
+ const vulnerabilityFinding = getCspVulnerabilityFinding(rows[rowIndex].raw._source);
+ if (!vulnerabilityFinding) return;
return async (http: HttpSetup) =>
- createDetectionRuleFromVulnerabilityFinding(http, finding.vulnerability);
+ createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityFinding);
};
return (
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.test.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.test.ts
new file mode 100644
index 0000000000000..209ec81168271
--- /dev/null
+++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.test.ts
@@ -0,0 +1,98 @@
+/*
+ * 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 {
+ getVulnerabilityTags,
+ getVulnerabilityRuleName,
+ generateVulnerabilitiesRuleQuery,
+} from './create_detection_rule_from_vulnerability';
+import { CspVulnerabilityFinding, Vulnerability } from '@kbn/cloud-security-posture-common';
+import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding';
+
+// Mocking the isNativeCspFinding function
+jest.mock('../../../common/utils/is_native_csp_finding', () => ({
+ isNativeCspFinding: jest.fn(),
+}));
+
+describe('CreateDetectionRuleFromVulnerability', () => {
+ describe('getVulnerabilityTags', () => {
+ it('should return tags with CSP_RULE_TAG and vulnerability id', () => {
+ const mockVulnerability = {
+ vulnerability: { id: 'CVE-2024-00001' },
+ observer: undefined,
+ data_stream: undefined,
+ } as unknown as CspVulnerabilityFinding;
+
+ (isNativeCspFinding as jest.Mock).mockReturnValue(false);
+
+ const tags = getVulnerabilityTags(mockVulnerability);
+ expect(tags).toEqual(['Cloud Security', 'CVE-2024-00001']);
+ });
+
+ it('should include vendor tag if available', () => {
+ const mockVulnerability = {
+ vulnerability: { id: 'CVE-2024-00002' },
+ observer: { vendor: 'Wiz' },
+ data_stream: undefined,
+ } as unknown as CspVulnerabilityFinding;
+
+ (isNativeCspFinding as jest.Mock).mockReturnValue(false);
+
+ const tags = getVulnerabilityTags(mockVulnerability);
+ expect(tags).toEqual(['Cloud Security', 'CVE-2024-00002', 'Wiz']);
+ });
+
+ it('should include CNVM tags for native findings', () => {
+ const mockVulnerability = {
+ vulnerability: { id: 'CVE-2024-00003' },
+ observer: undefined,
+ data_stream: undefined,
+ } as unknown as CspVulnerabilityFinding;
+
+ (isNativeCspFinding as jest.Mock).mockReturnValue(true);
+
+ const tags = getVulnerabilityTags(mockVulnerability);
+ expect(tags).toEqual([
+ 'Cloud Security',
+ 'CNVM',
+ 'Data Source: Cloud Native Vulnerability Management',
+ 'Use Case: Vulnerability',
+ 'OS: Linux',
+ 'CVE-2024-00003',
+ ]);
+ });
+ });
+
+ describe('getVulnerabilityRuleName', () => {
+ it('should return correct rule name for a vulnerability', () => {
+ const mockVulnerability = {
+ id: 'CVE-2024-00004',
+ description: '',
+ reference: '',
+ } as Vulnerability;
+
+ const ruleName = getVulnerabilityRuleName(mockVulnerability);
+ expect(ruleName).toEqual('Vulnerability: CVE-2024-00004');
+ });
+ });
+
+ describe('generateVulnerabilitiesRuleQuery', () => {
+ it('should generate correct query for a vulnerability', () => {
+ const mockVulnerability = {
+ id: 'CVE-2024-00005',
+ description: '',
+ reference: '',
+ } as Vulnerability;
+ const currentTimestamp = new Date().toISOString();
+
+ const query = generateVulnerabilitiesRuleQuery(mockVulnerability);
+ expect(query).toEqual(
+ `vulnerability.id: "CVE-2024-00005" AND event.ingested >= "${currentTimestamp}"`
+ );
+ });
+ });
+});
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts
index a09f9130836b2..b723c60f9ee3d 100644
--- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts
+++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/create_detection_rule_from_vulnerability.ts
@@ -8,10 +8,12 @@
import { HttpSetup } from '@kbn/core/public';
import { i18n } from '@kbn/i18n';
import {
+ CspVulnerabilityFinding,
LATEST_VULNERABILITIES_RETENTION_POLICY,
VULNERABILITIES_SEVERITY,
} from '@kbn/cloud-security-posture-common';
import type { Vulnerability } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest';
+import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding';
import { VULNERABILITIES_INDEX_PATTERN } from '../../../../common/constants';
import { createDetectionRule } from '../../../common/api/create_detection_rule';
@@ -42,15 +44,7 @@ enum AlertSuppressionMissingFieldsStrategy {
Suppress = 'suppress',
}
-const CSP_RULE_TAG = 'Cloud Security';
-
-const STATIC_RULE_TAGS = [CSP_RULE_TAG];
-
-const generateVulnerabilitiesTags = (tags?: string[]) => {
- return [...STATIC_RULE_TAGS, ...(!!tags?.length ? tags : [])];
-};
-
-const getVulnerabilityRuleName = (vulnerability: Vulnerability) => {
+export const getVulnerabilityRuleName = (vulnerability: Vulnerability) => {
return i18n.translate('xpack.csp.vulnerabilities.detectionRuleNamePrefix', {
defaultMessage: 'Vulnerability: {vulnerabilityId}',
values: {
@@ -59,20 +53,42 @@ const getVulnerabilityRuleName = (vulnerability: Vulnerability) => {
});
};
-const generateVulnerabilitiesRuleQuery = (vulnerability: Vulnerability) => {
+export const generateVulnerabilitiesRuleQuery = (vulnerability: Vulnerability) => {
const currentTimestamp = new Date().toISOString();
return `vulnerability.id: "${vulnerability.id}" AND event.ingested >= "${currentTimestamp}"`;
};
+const CSP_RULE_TAG = 'Cloud Security';
+const CNVM_TAG = 'CNVM';
+const CNVM_RULE_TAG_DATA_SOURCE = 'Data Source: Cloud Native Vulnerability Management';
+const CNVM_RULE_TAG_USE_CASE = 'Use Case: Vulnerability';
+const CNVM_RULE_TAG_OS = 'OS: Linux';
+
+export const getVulnerabilityTags = (vulnerabilityFinding: CspVulnerabilityFinding) => {
+ let tags = [vulnerabilityFinding.vulnerability.id];
+ const vendor =
+ vulnerabilityFinding.observer?.vendor || vulnerabilityFinding?.data_stream?.dataset;
+
+ if (isNativeCspFinding(vulnerabilityFinding)) {
+ tags = [CNVM_TAG, CNVM_RULE_TAG_DATA_SOURCE, CNVM_RULE_TAG_USE_CASE, CNVM_RULE_TAG_OS, ...tags];
+ } else if (!!vendor) {
+ tags.push(vendor);
+ }
+
+ return [CSP_RULE_TAG, ...tags];
+};
+
/*
* Creates a detection rule from a Vulnerability
*/
export const createDetectionRuleFromVulnerabilityFinding = async (
http: HttpSetup,
- vulnerability: Vulnerability,
- tags?: string[]
+ vulnerabilityFinding: CspVulnerabilityFinding
) => {
+ const tags = getVulnerabilityTags(vulnerabilityFinding);
+ const vulnerability = vulnerabilityFinding.vulnerability;
+
return await createDetectionRule({
http,
rule: {
@@ -135,7 +151,7 @@ export const createDetectionRuleFromVulnerabilityFinding = async (
references: vulnerability.reference ? [vulnerability.reference] : [],
name: getVulnerabilityRuleName(vulnerability),
description: vulnerability.description,
- tags: generateVulnerabilitiesTags(tags),
+ tags,
investigation_fields: DEFAULT_INVESTIGATION_FIELDS,
},
});
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx
index 1c726a450655b..c4680177f72c0 100644
--- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx
@@ -8,40 +8,21 @@
import React from 'react';
import type { HttpSetup } from '@kbn/core/public';
import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest';
-import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding';
import { DetectionRuleCounter } from '../../../components/detection_rule_counter';
-import { createDetectionRuleFromVulnerabilityFinding } from '../utils/create_detection_rule_from_vulnerability';
-
-const CNVM_TAG = 'CNVM';
-const CNVM_RULE_TAG_DATA_SOURCE = 'Data Source: Cloud Native Vulnerability Management';
-const CNVM_RULE_TAG_USE_CASE = 'Use Case: Vulnerability';
-const CNVM_RULE_TAG_OS = 'OS: Linux';
-
-const getTags = (vulnerabilityRecord: CspVulnerabilityFinding) => {
- let tags = [vulnerabilityRecord.vulnerability.id];
- const vendor = vulnerabilityRecord.observer?.vendor || vulnerabilityRecord?.data_stream?.dataset;
-
- if (isNativeCspFinding(vulnerabilityRecord)) {
- tags = [CNVM_TAG, CNVM_RULE_TAG_DATA_SOURCE, CNVM_RULE_TAG_USE_CASE, CNVM_RULE_TAG_OS, ...tags];
- } else if (!!vendor) {
- tags.push(vendor);
- }
-
- return tags;
-};
+import {
+ createDetectionRuleFromVulnerabilityFinding,
+ getVulnerabilityTags,
+} from '../utils/create_detection_rule_from_vulnerability';
export const VulnerabilityDetectionRuleCounter = ({
vulnerabilityRecord,
}: {
vulnerabilityRecord: CspVulnerabilityFinding;
}) => {
- const tags = getTags(vulnerabilityRecord);
+ const tags = getVulnerabilityTags(vulnerabilityRecord);
+
const createVulnerabilityRuleFn = async (http: HttpSetup) =>
- await createDetectionRuleFromVulnerabilityFinding(
- http,
- vulnerabilityRecord.vulnerability,
- tags
- );
+ await createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityRecord);
return ;
};
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx
index 8c7e3341424d9..1fe61e97506ef 100644
--- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx
@@ -162,7 +162,7 @@ export const VulnerabilityFindingFlyout = ({
const vulnerabilityReference = vulnerability?.reference;
const createVulnerabilityRuleFn = async (http: HttpSetup) =>
- await createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityRecord.vulnerability);
+ await createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityRecord);
return (