From 2b6e8f027df0367c4bec8ea85c890148a3bdf11e Mon Sep 17 00:00:00 2001 From: jbiset Date: Wed, 6 Mar 2024 19:11:49 -0300 Subject: [PATCH 01/15] Migrated visualizations to embeddables --- .../common/modules/modules-defaults.js | 8 +- .../threat-hunting/dashboard/dashboard.tsx | 80 ++++ .../dashboard/dashboard_panels.ts | 447 ++++++++++++++++++ .../dashboard/dashboard_panels_kpis.ts | 424 +++++++++++++++++ .../threat-hunting/dashboard/index.tsx | 1 + 5 files changed, 959 insertions(+), 1 deletion(-) create mode 100644 plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx create mode 100644 plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts create mode 100644 plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts create mode 100644 plugins/main/public/components/overview/threat-hunting/dashboard/index.tsx diff --git a/plugins/main/public/components/common/modules/modules-defaults.js b/plugins/main/public/components/common/modules/modules-defaults.js index 7b1705b0e4..0ed1eb992f 100644 --- a/plugins/main/public/components/common/modules/modules-defaults.js +++ b/plugins/main/public/components/common/modules/modules-defaults.js @@ -24,6 +24,7 @@ import { WazuhDiscover } from '../wazuh-discover/wz-discover'; import { threatHuntingColumns } from '../wazuh-discover/config/data-grid-columns'; import { vulnerabilitiesColumns } from '../../overview/vulnerabilities/events/vulnerabilities-columns'; import { DashboardFim } from '../../overview/fim/dashboard/dashboard'; +import { DashboardThreatHunting } from '../../overview/threat-hunting/dashboard/dashboard'; import { InventoryFim } from '../../overview/fim/inventory/inventory'; import React from 'react'; import { dockerColumns } from '../../overview/docker/events/docker-columns'; @@ -79,7 +80,12 @@ export const ModulesDefaults = { general: { init: 'events', tabs: [ - DashboardTab, + { + id: 'dashboard', + name: 'Dashboard', + buttons: [ButtonModuleExploreAgent, ButtonModuleGenerateReport], + component: DashboardThreatHunting, + }, renderDiscoverTab(DEFAULT_INDEX_PATTERN, threatHuntingColumns), ], availableFor: ['manager', 'agent'], diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx new file mode 100644 index 0000000000..278d188908 --- /dev/null +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import { getPlugins } from '../../../../kibana-services'; +import { ViewMode } from '../../../../../../../src/plugins/embeddable/public'; +import { getDashboardPanels } from './dashboard_panels'; +import { I18nProvider } from '@osd/i18n/react'; +import useSearchBar from '../../../common/search-bar/use-search-bar'; +import { WAZUH_ALERTS_PATTERN } from '../../../../../common/constants'; +import { getKPIsPanel } from './dashboard_panels_kpis'; + +const plugins = getPlugins(); + +const SearchBar = getPlugins().data.ui.SearchBar; + +const DashboardByRenderer = plugins.dashboard.DashboardContainerByValueRenderer; + +export const DashboardThreatHunting: React.FC = () => { + const TH_INDEX_PATTERN_ID = WAZUH_ALERTS_PATTERN; + + const { searchBarProps } = useSearchBar({ + defaultIndexPatternID: TH_INDEX_PATTERN_ID, + }); + + return ( + <> + + + + + + + ); +}; diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts new file mode 100644 index 0000000000..c245842301 --- /dev/null +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts @@ -0,0 +1,447 @@ +import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; +import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; + +const getVisStateTop10AlertLevelEvolution = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Overview-General-Alert-level-evolution', + title: 'Top 10 Alert level evolution', + type: 'area', + params: { + type: 'area', + grid: { + categoryLines: true, + style: { + color: '#eee', + }, + valueAxis: 'ValueAxis-1', + }, + categoryAxes: [ + { + id: 'CategoryAxis-1', + type: 'category', + position: 'bottom', + show: true, + style: {}, + scale: { + type: 'linear', + }, + labels: { + show: true, + filter: true, + truncate: 100, + }, + title: {}, + }, + ], + valueAxes: [ + { + id: 'ValueAxis-1', + name: 'LeftAxis-1', + type: 'value', + position: 'left', + show: true, + style: {}, + scale: { + type: 'linear', + mode: 'normal', + }, + labels: { + show: true, + rotate: 0, + filter: false, + truncate: 100, + }, + title: { + text: 'Count', + }, + }, + ], + seriesParams: [ + { + show: 'true', + type: 'area', + mode: 'stacked', + data: { + label: 'Count', + id: '1', + }, + drawLinesBetweenPoints: true, + showCircles: true, + interpolate: 'cardinal', + valueAxis: 'ValueAxis-1', + }, + ], + addTooltip: true, + addLegend: true, + legendPosition: 'right', + times: [], + addTimeMarker: false, + thresholdLine: { + show: false, + value: 10, + width: 1, + style: 'full', + color: '#E7664C', + }, + labels: {}, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + params: {}, + schema: 'metric', + }, + { + id: '3', + enabled: true, + type: 'terms', + params: { + field: 'rule.level', + orderBy: '1', + order: 'desc', + size: 10, + otherBucket: false, + otherBucketLabel: 'Other', + missingBucket: false, + missingBucketLabel: 'Missing', + }, + schema: 'group', + }, + { + id: '2', + enabled: true, + type: 'date_histogram', + params: { + field: 'timestamp', + timeRange: { + from: 'now-24h', + to: 'now', + }, + useNormalizedOpenSearchInterval: true, + scaleMetricValues: false, + interval: 'auto', + drop_partials: false, + min_doc_count: 1, + extended_bounds: {}, + }, + schema: 'segment', + }, + ], + }, + }; +}; + +const getVisStateTop10MITREATTACKS = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Overview-General-Alerts-Top-Mitre', + title: 'Top 10 MITRE ATT&CKS', + type: 'pie', + params: { + type: 'pie', + addTooltip: true, + addLegend: true, + legendPosition: 'right', + isDonut: true, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, + { + id: '2', + enabled: true, + type: 'terms', + schema: 'segment', + params: { + field: 'rule.mitre.technique', + orderBy: '1', + order: 'desc', + size: 10, + otherBucket: false, + otherBucketLabel: 'Other', + missingBucket: false, + missingBucketLabel: 'Missing', + }, + }, + ], + }, + }; +}; + +const getVisStateTop5Agents = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Overview-General-Top-5-agents', + title: 'Top 5 agents', + type: 'pie', + params: { + type: 'pie', + addTooltip: true, + addLegend: true, + legendPosition: 'right', + isDonut: true, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, + { + id: '2', + enabled: true, + type: 'terms', + schema: 'segment', + params: { + field: 'agent.name', + size: 5, + order: 'desc', + orderBy: '1', + otherBucket: false, + otherBucketLabel: 'Other', + missingBucket: false, + missingBucketLabel: 'Missing', + }, + }, + ], + }, + }; +}; + +const getVisStateAlertEvolutionTop5Agents = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Overview-General-Alerts-evolution-Top-5-agents', + title: 'Alerts evolution - Top 5 agents', + type: 'histogram', + params: { + type: 'histogram', + grid: { categoryLines: false, style: { color: '#eee' } }, + categoryAxes: [ + { + id: 'CategoryAxis-1', + type: 'category', + position: 'bottom', + show: true, + style: {}, + scale: { type: 'linear' }, + labels: { show: true, filter: true, truncate: 100 }, + title: {}, + }, + ], + valueAxes: [ + { + id: 'ValueAxis-1', + name: 'LeftAxis-1', + type: 'value', + position: 'left', + show: true, + style: {}, + scale: { type: 'linear', mode: 'normal' }, + labels: { show: true, rotate: 0, filter: false, truncate: 100 }, + title: { text: 'Count' }, + }, + ], + seriesParams: [ + { + show: 'true', + type: 'histogram', + mode: 'stacked', + data: { label: 'Count', id: '1' }, + valueAxis: 'ValueAxis-1', + drawLinesBetweenPoints: true, + showCircles: true, + }, + ], + addTooltip: true, + addLegend: true, + legendPosition: 'right', + times: [], + addTimeMarker: false, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, + { + id: '3', + enabled: true, + type: 'terms', + schema: 'group', + params: { + field: 'agent.name', + size: 5, + order: 'desc', + orderBy: '1', + }, + }, + { + id: '2', + enabled: true, + type: 'date_histogram', + schema: 'segment', + params: { + field: 'timestamp', + interval: 'auto', + customInterval: '2h', + min_doc_count: 1, + extended_bounds: {}, + }, + }, + ], + }, + }; +}; + +export const getDashboardPanels = ( + indexPatternId: string, +): { + [panelId: string]: DashboardPanelState< + EmbeddableInput & { [k: string]: unknown } + >; +} => { + return { + '1': { + gridData: { + w: 28, + h: 13, + x: 0, + y: 0, + i: '1', + }, + type: 'visualization', + explicitInput: { + id: '1', + savedVis: getVisStateTop10AlertLevelEvolution(indexPatternId), + }, + }, + '2': { + gridData: { + w: 20, + h: 13, + x: 28, + y: 0, + i: '2', + }, + type: 'visualization', + explicitInput: { + id: '2', + savedVis: getVisStateTop10MITREATTACKS(indexPatternId), + }, + }, + '3': { + gridData: { + w: 15, + h: 12, + x: 0, + y: 13, + i: '3', + }, + type: 'visualization', + explicitInput: { + id: '3', + savedVis: getVisStateTop5Agents(indexPatternId), + }, + }, + '4': { + gridData: { + w: 33, + h: 12, + x: 15, + y: 13, + i: '4', + }, + type: 'visualization', + explicitInput: { + id: '4', + savedVis: getVisStateAlertEvolutionTop5Agents(indexPatternId), + }, + }, + }; +}; diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts new file mode 100644 index 0000000000..bbd2f81b78 --- /dev/null +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts @@ -0,0 +1,424 @@ +import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; +import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; + +const getVisStateTotal = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Overview-General-Metric-alerts', + title: 'Total', + type: 'metric', + params: { + addTooltip: true, + addLegend: false, + type: 'gauge', + gauge: { + verticalSplit: false, + autoExtend: false, + percentageMode: false, + gaugeType: 'Metric', + gaugeStyle: 'Full', + backStyle: 'Full', + orientation: 'vertical', + colorSchema: 'Green to Red', + gaugeColorMode: 'None', + useRange: false, + colorsRange: [{ from: 0, to: 100 }], + invertColors: false, + labels: { show: true, color: 'black' }, + scale: { show: false, labels: false, color: '#333', width: 2 }, + type: 'simple', + style: { + fontSize: 20, + bgColor: false, + labelColor: false, + subText: '', + }, + }, + }, + uiState: { + vis: { defaultColors: { '0 - 100': 'rgb(0,104,55)' } }, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: { customLabel: 'Alerts' }, + }, + ], + }, + }; +}; + +const getVisStateLevel12Alerts = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Overview-General-Level-12-alerts', + title: 'Level 12 or above alerts', + type: 'metric', + params: { + addTooltip: true, + addLegend: false, + type: 'gauge', + gauge: { + verticalSplit: false, + autoExtend: false, + percentageMode: false, + gaugeType: 'Metric', + gaugeStyle: 'Full', + backStyle: 'Full', + orientation: 'vertical', + colorSchema: 'Green to Red', + gaugeColorMode: 'None', + useRange: false, + colorsRange: [{ from: 0, to: 100 }], + invertColors: false, + labels: { show: true, color: 'black' }, + scale: { show: false, labels: false, color: '#333', width: 2 }, + type: 'simple', + style: { + fontSize: 20, + bgColor: false, + labelColor: false, + subText: '', + }, + }, + }, + uiState: { + vis: { defaultColors: { '0 - 100': 'rgb(0,104,55)' } }, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [ + { + $state: { + store: 'appState', + }, + meta: { + alias: null, + disabled: false, + index: 'wazuh-alerts', + key: 'rule.level', + negate: false, + params: { + gte: 12, + lt: null, + }, + type: 'range', + value: '12 to +∞', + }, + range: { + 'rule.level': { + gte: 12, + lt: null, + }, + }, + }, + ], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: { customLabel: 'Level 12 or above alerts' }, + }, + ], + }, + }; +}; + +const getVisStateAuthenticationFailure = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Overview-General-Authentication-failure', + title: 'Authentication failure', + type: 'metric', + params: { + addTooltip: true, + addLegend: false, + type: 'gauge', + gauge: { + verticalSplit: false, + autoExtend: false, + percentageMode: false, + gaugeType: 'Metric', + gaugeStyle: 'Full', + backStyle: 'Full', + orientation: 'vertical', + colorSchema: 'Green to Red', + gaugeColorMode: 'None', + useRange: false, + colorsRange: [{ from: 0, to: 100 }], + invertColors: false, + labels: { show: true, color: 'black' }, + scale: { show: false, labels: false, color: '#333', width: 2 }, + type: 'simple', + style: { + fontSize: 20, + bgColor: false, + labelColor: false, + subText: '', + }, + }, + }, + uiState: { + vis: { defaultColors: { '0 - 100': 'rgb(0,104,55)' } }, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [ + { + meta: { + index: 'wazuh-alerts', + type: 'phrases', + key: 'rule.groups', + value: + 'win_authentication_failed, authentication_failed, authentication_failures', + params: [ + 'win_authentication_failed', + 'authentication_failed', + 'authentication_failures', + ], + negate: false, + disabled: false, + alias: null, + }, + query: { + bool: { + should: [ + { + match_phrase: { + 'rule.groups': 'win_authentication_failed', + }, + }, + { + match_phrase: { + 'rule.groups': 'authentication_failed', + }, + }, + { + match_phrase: { + 'rule.groups': 'authentication_failures', + }, + }, + ], + minimum_should_match: 1, + }, + }, + $state: { + store: 'appState', + }, + }, + ], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: { customLabel: 'Authentication failure' }, + }, + ], + }, + }; +}; + +const getVisStateSeverityLow = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Overview-General-Authentication-success', + title: 'Authentication success', + type: 'metric', + params: { + addTooltip: true, + addLegend: false, + type: 'gauge', + gauge: { + verticalSplit: false, + autoExtend: false, + percentageMode: false, + gaugeType: 'Metric', + gaugeStyle: 'Full', + backStyle: 'Full', + orientation: 'vertical', + colorSchema: 'Green to Red', + gaugeColorMode: 'None', + useRange: false, + colorsRange: [{ from: 0, to: 100 }], + invertColors: false, + labels: { show: true, color: 'black' }, + scale: { show: false, labels: false, color: '#333', width: 2 }, + type: 'simple', + style: { + fontSize: 20, + bgColor: false, + labelColor: false, + subText: '', + }, + }, + }, + uiState: { + vis: { defaultColors: { '0 - 100': 'rgb(0,104,55)' } }, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [ + { + meta: { + index: 'wazuh-alerts', + negate: false, + disabled: false, + alias: null, + type: 'phrase', + key: 'rule.groups', + value: 'authentication_success', + params: { + query: 'authentication_success', + type: 'phrase', + }, + }, + query: { + match: { + 'rule.groups': { + query: 'authentication_success', + type: 'phrase', + }, + }, + }, + $state: { + store: 'appState', + }, + }, + ], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: { customLabel: 'Authentication success' }, + }, + ], + }, + }; +}; + +export const getKPIsPanel = ( + indexPatternId: string, +): { + [panelId: string]: DashboardPanelState< + EmbeddableInput & { [k: string]: unknown } + >; +} => { + return { + '1': { + gridData: { + w: 12, + h: 6, + x: 0, + y: 0, + i: '1', + }, + type: 'visualization', + explicitInput: { + id: '1', + savedVis: getVisStateTotal(indexPatternId), + }, + }, + '2': { + gridData: { + w: 12, + h: 6, + x: 12, + y: 0, + i: '2', + }, + type: 'visualization', + explicitInput: { + id: '2', + savedVis: getVisStateLevel12Alerts(indexPatternId), + }, + }, + '3': { + gridData: { + w: 12, + h: 6, + x: 24, + y: 0, + i: '3', + }, + type: 'visualization', + explicitInput: { + id: '3', + savedVis: getVisStateAuthenticationFailure(indexPatternId), + }, + }, + '4': { + gridData: { + w: 12, + h: 6, + x: 36, + y: 0, + i: '4', + }, + type: 'visualization', + explicitInput: { + id: '4', + savedVis: getVisStateSeverityLow(indexPatternId), + }, + }, + }; +}; diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/index.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/index.tsx new file mode 100644 index 0000000000..b58b6c9229 --- /dev/null +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/index.tsx @@ -0,0 +1 @@ +export * from './dashboard'; From 07776d3af41b5e27a3f93242b189349dd2416c23 Mon Sep 17 00:00:00 2001 From: jbiset Date: Thu, 7 Mar 2024 17:22:20 -0300 Subject: [PATCH 02/15] Added withPinnedAgent HOC --- .../common/hocs/withPinnedAgent.tsx | 19 +++++++ .../common/modules/modules-defaults.js | 3 +- .../common/modules/modules-helper.js | 57 +++++++++++++++++++ .../threat-hunting/dashboard/dashboard.tsx | 9 ++- 4 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 plugins/main/public/components/common/hocs/withPinnedAgent.tsx diff --git a/plugins/main/public/components/common/hocs/withPinnedAgent.tsx b/plugins/main/public/components/common/hocs/withPinnedAgent.tsx new file mode 100644 index 0000000000..0a8decaf56 --- /dev/null +++ b/plugins/main/public/components/common/hocs/withPinnedAgent.tsx @@ -0,0 +1,19 @@ +/* + * Wazuh app - React HOCs to manage allowed agents + * Copyright (C) 2015-2022 Wazuh, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Find more information about this on the LICENSE file. + */ + +import React from 'react'; +import { ModulesHelper } from '../modules/modules-helper'; + +export const withPinnedAgent = WrappedComponent => props => { + const pinnedAgent = ModulesHelper.getImplicitPinnedAgent('wazuh-alerts-*'); + return ; +}; diff --git a/plugins/main/public/components/common/modules/modules-defaults.js b/plugins/main/public/components/common/modules/modules-defaults.js index 0ed1eb992f..97cf52433a 100644 --- a/plugins/main/public/components/common/modules/modules-defaults.js +++ b/plugins/main/public/components/common/modules/modules-defaults.js @@ -44,6 +44,7 @@ import { virustotalColumns } from '../../overview/virustotal/events/virustotal-c import { malwareDetectionColumns } from '../../overview/malware-detection/events/malware-detection-columns'; import { WAZUH_VULNERABILITIES_PATTERN } from '../../../../common/constants'; import { withVulnerabilitiesStateDataSource } from '../../overview/vulnerabilities/common/hocs/validate-vulnerabilities-states-index-pattern'; +import { withPinnedAgent } from '../hocs/withPinnedAgent'; const DashboardTab = { id: 'dashboard', @@ -84,7 +85,7 @@ export const ModulesDefaults = { id: 'dashboard', name: 'Dashboard', buttons: [ButtonModuleExploreAgent, ButtonModuleGenerateReport], - component: DashboardThreatHunting, + component: withPinnedAgent(DashboardThreatHunting), }, renderDiscoverTab(DEFAULT_INDEX_PATTERN, threatHuntingColumns), ], diff --git a/plugins/main/public/components/common/modules/modules-helper.js b/plugins/main/public/components/common/modules/modules-helper.js index 0443f4a40b..55fa313905 100644 --- a/plugins/main/public/components/common/modules/modules-helper.js +++ b/plugins/main/public/components/common/modules/modules-helper.js @@ -2,6 +2,8 @@ import { getAngularModule, getDataPlugin } from '../../../kibana-services'; import { AppState } from '../../../react-services/app-state'; import { FilterHandler } from '../../../utils/filter-handler'; import { VULNERABILITY_IMPLICIT_CLUSTER_MODE_FILTER } from '../../../../common/constants'; +import { useFilterManager } from '../hooks'; +import { FilterStateStore } from '../../../../../../src/plugins/data/common'; export class ModulesHelper { static async getDiscoverScope() { @@ -182,4 +184,59 @@ If this case happens, the implicit filters are regenerated and the function is c return filters; } + + /** + * + * @param {string} indexPattern - Index pattern id being used + * @param {Filter[] | undefined} filters - (Optional) Filter Array in which to search if a pinned agent exists + * @returns + */ + static getImplicitPinnedAgent(indexPattern, filters = []) { + const filterManager = useFilterManager().filterManager; + const initialFilters = + filters?.length > 0 ? filters : filterManager.getFilters(); + const pinnedAgentByFilterManager = initialFilters.find( + filter => + filter?.meta?.key === 'agent.id' && !!filter?.$state?.isImplicit, + ); + const url = window.location.href; + const regex = new RegExp('agentId=' + '[^&]*'); + const match = url.match(regex); + const isPinnedAgentByUrl = match && match[0]; + if (pinnedAgentByFilterManager && isPinnedAgentByUrl) { + return { + ...pinnedAgentByFilterManager, + meta: { + ...pinnedAgentByFilterManager.meta, + index: indexPattern, + }, + $state: { store: FilterStateStore.APP_STATE, isImplicit: true }, + }; + } + + if (isPinnedAgentByUrl) { + const agentId = match[0].split('=')[1]; + return { + meta: { + alias: null, + disabled: false, + key: 'agent.id', + negate: false, + params: { query: agentId }, + type: 'phrase', + index: indexPattern, + }, + query: { + match: { + 'agent.id': { + query: agentId, + type: 'phrase', + }, + }, + }, + $state: { store: 'appState', isImplicit: true }, + }; + } + return undefined; + } } diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index 278d188908..fa3665430a 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -6,6 +6,7 @@ import { I18nProvider } from '@osd/i18n/react'; import useSearchBar from '../../../common/search-bar/use-search-bar'; import { WAZUH_ALERTS_PATTERN } from '../../../../../common/constants'; import { getKPIsPanel } from './dashboard_panels_kpis'; +import { Filter } from '../../../../../../../src/plugins/data/common'; const plugins = getPlugins(); @@ -13,7 +14,13 @@ const SearchBar = getPlugins().data.ui.SearchBar; const DashboardByRenderer = plugins.dashboard.DashboardContainerByValueRenderer; -export const DashboardThreatHunting: React.FC = () => { +interface DashboardThreatHuntingProps { + pinnedAgent: Filter; +} + +export const DashboardThreatHunting: React.FC< + DashboardThreatHuntingProps +> = props => { const TH_INDEX_PATTERN_ID = WAZUH_ALERTS_PATTERN; const { searchBarProps } = useSearchBar({ From ba0e78a79550feca83601f822a2d34163da50dac Mon Sep 17 00:00:00 2001 From: jbiset Date: Thu, 7 Mar 2024 18:41:04 -0300 Subject: [PATCH 03/15] Added dashboard update mechanism depending on whether or not an agent has been pinned --- .../threat-hunting/dashboard/dashboard.tsx | 8 +- .../dashboard/dashboard_panels.ts | 363 +++++++++++++++++- 2 files changed, 366 insertions(+), 5 deletions(-) diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index fa3665430a..461a897c1f 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -18,9 +18,9 @@ interface DashboardThreatHuntingProps { pinnedAgent: Filter; } -export const DashboardThreatHunting: React.FC< - DashboardThreatHuntingProps -> = props => { +export const DashboardThreatHunting: React.FC = ({ + pinnedAgent, +}) => { const TH_INDEX_PATTERN_ID = WAZUH_ALERTS_PATTERN; const { searchBarProps } = useSearchBar({ @@ -63,7 +63,7 @@ export const DashboardThreatHunting: React.FC< { }; }; +const getVisStatePinnedAgentTop10AlertGroupsEvolution = ( + indexPatternId: string, +) => { + return { + id: 'Wazuh-App-Agents-General-Alert-groups-evolution', + title: 'Top 10 Alert groups evolution', + type: 'area', + params: { + type: 'area', + grid: { + categoryLines: true, + style: { + color: '#eee', + }, + valueAxis: 'ValueAxis-1', + }, + categoryAxes: [ + { + id: 'CategoryAxis-1', + type: 'category', + position: 'bottom', + show: true, + style: {}, + scale: { + type: 'linear', + }, + labels: { + show: true, + filter: true, + truncate: 100, + }, + title: {}, + }, + ], + valueAxes: [ + { + id: 'ValueAxis-1', + name: 'LeftAxis-1', + type: 'value', + position: 'left', + show: true, + style: {}, + scale: { + type: 'linear', + mode: 'normal', + }, + labels: { + show: true, + rotate: 0, + filter: false, + truncate: 100, + }, + title: { + text: 'Count', + }, + }, + ], + seriesParams: [ + { + show: 'true', + type: 'area', + mode: 'stacked', + data: { + label: 'Count', + id: '1', + }, + drawLinesBetweenPoints: true, + showCircles: true, + interpolate: 'cardinal', + valueAxis: 'ValueAxis-1', + }, + ], + addTooltip: true, + addLegend: true, + legendPosition: 'right', + times: [], + addTimeMarker: false, + thresholdLine: { + show: false, + value: 10, + width: 1, + style: 'full', + color: '#E7664C', + }, + labels: {}, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + params: {}, + schema: 'metric', + }, + { + id: '3', + enabled: true, + type: 'terms', + params: { + field: 'rule.groups', + orderBy: '1', + order: 'desc', + size: 10, + otherBucket: false, + otherBucketLabel: 'Other', + missingBucket: false, + missingBucketLabel: 'Missing', + }, + schema: 'group', + }, + { + id: '2', + enabled: true, + type: 'date_histogram', + params: { + field: 'timestamp', + timeRange: { + from: 'now-1M', + to: 'now', + }, + useNormalizedOpenSearchInterval: true, + scaleMetricValues: false, + interval: 'auto', + drop_partials: false, + min_doc_count: 1, + extended_bounds: {}, + }, + schema: 'segment', + }, + ], + }, + }; +}; + +const getVisStateTop5Alerts = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Agents-General-Alerts', + title: 'Top 10 Alerts', + type: 'area', + params: { + type: 'area', + grid: { + categoryLines: true, + style: { + color: '#eee', + }, + valueAxis: 'ValueAxis-1', + }, + categoryAxes: [ + { + id: 'CategoryAxis-1', + type: 'category', + position: 'bottom', + show: true, + style: {}, + scale: { + type: 'linear', + }, + labels: { + show: true, + filter: true, + truncate: 100, + }, + title: {}, + }, + ], + valueAxes: [ + { + id: 'ValueAxis-1', + name: 'LeftAxis-1', + type: 'value', + position: 'left', + show: true, + style: {}, + scale: { + type: 'linear', + mode: 'normal', + }, + labels: { + show: true, + rotate: 0, + filter: false, + truncate: 100, + }, + title: { + text: 'Count', + }, + }, + ], + seriesParams: [ + { + show: 'true', + type: 'area', + mode: 'stacked', + data: { + label: 'Count', + id: '1', + }, + drawLinesBetweenPoints: true, + showCircles: true, + interpolate: 'cardinal', + valueAxis: 'ValueAxis-1', + }, + ], + addTooltip: true, + addLegend: true, + legendPosition: 'right', + times: [], + addTimeMarker: false, + thresholdLine: { + show: false, + value: 10, + width: 1, + style: 'full', + color: '#E7664C', + }, + labels: {}, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + params: {}, + schema: 'metric', + }, + { + id: '3', + enabled: true, + type: 'terms', + params: { + field: 'rule.level', + orderBy: '1', + order: 'desc', + size: 10, + otherBucket: false, + otherBucketLabel: 'Other', + missingBucket: false, + missingBucketLabel: 'Missing', + }, + schema: 'group', + }, + { + id: '2', + enabled: true, + type: 'date_histogram', + params: { + field: 'timestamp', + timeRange: { + from: 'now-1M', + to: 'now', + }, + useNormalizedOpenSearchInterval: true, + scaleMetricValues: false, + interval: 'auto', + drop_partials: false, + min_doc_count: 1, + extended_bounds: {}, + }, + schema: 'segment', + }, + ], + }, + }; +}; + const getVisStateTop10MITREATTACKS = (indexPatternId: string) => { return { id: 'Wazuh-App-Overview-General-Alerts-Top-Mitre', @@ -381,12 +679,73 @@ const getVisStateAlertEvolutionTop5Agents = (indexPatternId: string) => { export const getDashboardPanels = ( indexPatternId: string, + pinnedAgent?: boolean, ): { [panelId: string]: DashboardPanelState< EmbeddableInput & { [k: string]: unknown } >; } => { - return { + const pinnedAgentPanels = { + '5': { + gridData: { + w: 24, + h: 13, + x: 0, + y: 0, + i: '5', + }, + type: 'visualization', + explicitInput: { + id: '5', + savedVis: + getVisStatePinnedAgentTop10AlertGroupsEvolution(indexPatternId), + }, + }, + '6': { + gridData: { + w: 24, + h: 13, + x: 24, + y: 0, + i: '6', + }, + type: 'visualization', + explicitInput: { + id: '6', + savedVis: getVisStateTop5Alerts(indexPatternId), + }, + }, + '3': { + gridData: { + w: 15, + h: 12, + x: 0, + y: 13, + i: '3', + }, + type: 'visualization', + explicitInput: { + id: '3', + savedVis: getVisStateTop5Agents(indexPatternId), + }, + }, + '4': { + gridData: { + w: 33, + h: 12, + x: 15, + y: 13, + i: '4', + }, + type: 'visualization', + explicitInput: { + id: '4', + savedVis: getVisStateAlertEvolutionTop5Agents(indexPatternId), + }, + }, + }; + + const panels = { '1': { gridData: { w: 28, @@ -444,4 +803,6 @@ export const getDashboardPanels = ( }, }, }; + + return pinnedAgent ? pinnedAgentPanels : panels; }; From 978d3a516e00f4a77727b389caa122cca49cb992 Mon Sep 17 00:00:00 2001 From: jbiset Date: Fri, 8 Mar 2024 18:11:38 -0300 Subject: [PATCH 04/15] Pinned agent visualization definitions are migrated and aesthetic adjustments are made --- .../threat-hunting/dashboard/dashboard.tsx | 1 + .../dashboard/dashboard_panels.ts | 393 ++++++++++++++---- .../dashboard/dashboard_panels_kpis.ts | 159 +++---- 3 files changed, 391 insertions(+), 162 deletions(-) diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index 461a897c1f..3872a57ea2 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -21,6 +21,7 @@ interface DashboardThreatHuntingProps { export const DashboardThreatHunting: React.FC = ({ pinnedAgent, }) => { + /* TODO: Analyze whether to use the new index pattern handler https://github.com/wazuh/wazuh-dashboard-plugins/issues/6434 */ const TH_INDEX_PATTERN_ID = WAZUH_ALERTS_PATTERN; const { searchBarProps } = useSearchBar({ diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts index c412ac5fbe..a095aa5a47 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts @@ -1,6 +1,8 @@ import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; +/* Overview visualizations */ + const getVisStateTop10AlertLevelEvolution = (indexPatternId: string) => { return { id: 'Wazuh-App-Overview-General-Alert-level-evolution', @@ -149,6 +151,241 @@ const getVisStateTop10AlertLevelEvolution = (indexPatternId: string) => { }; }; +const getVisStateTop5Agents = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Overview-General-Top-5-agents', + title: 'Top 5 agents', + type: 'pie', + params: { + type: 'pie', + addTooltip: true, + addLegend: true, + legendPosition: 'right', + isDonut: true, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, + }, + uiState: { + vis: { legendOpen: true }, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, + { + id: '2', + enabled: true, + type: 'terms', + schema: 'segment', + params: { + field: 'agent.name', + size: 5, + order: 'desc', + orderBy: '1', + otherBucket: false, + otherBucketLabel: 'Other', + missingBucket: false, + missingBucketLabel: 'Missing', + }, + }, + ], + }, + }; +}; + +const getVisStateTop10MITREATTACKS = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Overview-General-Alerts-Top-Mitre', + title: 'Top 10 MITRE ATT&CKS', + type: 'pie', + params: { + type: 'pie', + addTooltip: true, + addLegend: true, + legendPosition: 'right', + isDonut: true, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, + { + id: '2', + enabled: true, + type: 'terms', + schema: 'segment', + params: { + field: 'rule.mitre.technique', + orderBy: '1', + order: 'desc', + size: 10, + otherBucket: false, + otherBucketLabel: 'Other', + missingBucket: false, + missingBucketLabel: 'Missing', + }, + }, + ], + }, + }; +}; + +const getVisStateAlertEvolutionTop5Agents = (indexPatternId: string) => { + return { + id: 'Wazuh-App-Overview-General-Alerts-evolution-Top-5-agents', + title: 'Alerts evolution - Top 5 agents', + type: 'histogram', + params: { + type: 'histogram', + grid: { categoryLines: false, style: { color: '#eee' } }, + categoryAxes: [ + { + id: 'CategoryAxis-1', + type: 'category', + position: 'bottom', + show: true, + style: {}, + scale: { type: 'linear' }, + labels: { show: true, filter: true, truncate: 100 }, + title: {}, + }, + ], + valueAxes: [ + { + id: 'ValueAxis-1', + name: 'LeftAxis-1', + type: 'value', + position: 'left', + show: true, + style: {}, + scale: { type: 'linear', mode: 'normal' }, + labels: { show: true, rotate: 0, filter: false, truncate: 100 }, + title: { text: 'Count' }, + }, + ], + seriesParams: [ + { + show: 'true', + type: 'histogram', + mode: 'stacked', + data: { label: 'Count', id: '1' }, + valueAxis: 'ValueAxis-1', + drawLinesBetweenPoints: true, + showCircles: true, + }, + ], + addTooltip: true, + addLegend: true, + legendPosition: 'right', + times: [], + addTimeMarker: false, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + filter: [], + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, + { + id: '3', + enabled: true, + type: 'terms', + schema: 'group', + params: { + field: 'agent.name', + size: 5, + order: 'desc', + orderBy: '1', + }, + }, + { + id: '2', + enabled: true, + type: 'date_histogram', + schema: 'segment', + params: { + field: 'timestamp', + interval: 'auto', + customInterval: '2h', + min_doc_count: 1, + extended_bounds: {}, + }, + }, + ], + }, + }; +}; + +/* Agent visualizations */ + const getVisStatePinnedAgentTop10AlertGroupsEvolution = ( indexPatternId: string, ) => { @@ -299,10 +536,10 @@ const getVisStatePinnedAgentTop10AlertGroupsEvolution = ( }; }; -const getVisStateTop5Alerts = (indexPatternId: string) => { +const getVisStateAlertsAgents = (indexPatternId: string) => { return { id: 'Wazuh-App-Agents-General-Alerts', - title: 'Top 10 Alerts', + title: 'Alerts', type: 'area', params: { type: 'area', @@ -447,10 +684,10 @@ const getVisStateTop5Alerts = (indexPatternId: string) => { }; }; -const getVisStateTop10MITREATTACKS = (indexPatternId: string) => { +const getVisStateTop5AlertsAgents = (indexPatternId: string) => { return { - id: 'Wazuh-App-Overview-General-Alerts-Top-Mitre', - title: 'Top 10 MITRE ATT&CKS', + id: 'Wazuh-App-Agents-General-Top-5-alerts', + title: 'Top 5 alerts', type: 'pie', params: { type: 'pie', @@ -465,6 +702,9 @@ const getVisStateTop10MITREATTACKS = (indexPatternId: string) => { truncate: 100, }, }, + uiState: { + vis: { legendOpen: true }, + }, data: { searchSource: { query: { @@ -495,10 +735,10 @@ const getVisStateTop10MITREATTACKS = (indexPatternId: string) => { type: 'terms', schema: 'segment', params: { - field: 'rule.mitre.technique', - orderBy: '1', + field: 'rule.description', + size: 5, order: 'desc', - size: 10, + orderBy: '1', otherBucket: false, otherBucketLabel: 'Other', missingBucket: false, @@ -510,10 +750,10 @@ const getVisStateTop10MITREATTACKS = (indexPatternId: string) => { }; }; -const getVisStateTop5Agents = (indexPatternId: string) => { +const getVisStateTop5RuleGroupsAgents = (indexPatternId: string) => { return { - id: 'Wazuh-App-Overview-General-Top-5-agents', - title: 'Top 5 agents', + id: 'Wazuh-App-Agents-General-Top-10-groups', + title: 'Top 5 rule groups', type: 'pie', params: { type: 'pie', @@ -528,6 +768,9 @@ const getVisStateTop5Agents = (indexPatternId: string) => { truncate: 100, }, }, + uiState: { + vis: { legendOpen: true }, + }, data: { searchSource: { query: { @@ -558,7 +801,7 @@ const getVisStateTop5Agents = (indexPatternId: string) => { type: 'terms', schema: 'segment', params: { - field: 'agent.name', + field: 'rule.groups', size: 5, order: 'desc', orderBy: '1', @@ -573,55 +816,26 @@ const getVisStateTop5Agents = (indexPatternId: string) => { }; }; -const getVisStateAlertEvolutionTop5Agents = (indexPatternId: string) => { +const getVisStateTop5PCIDSSRequirementsAgents = (indexPatternId: string) => { return { - id: 'Wazuh-App-Overview-General-Alerts-evolution-Top-5-agents', - title: 'Alerts evolution - Top 5 agents', - type: 'histogram', + id: 'Wazuh-App-Agents-General-Top-5-PCI-DSS-Requirements', + title: 'Top 5 PCI DSS Requirements', + type: 'pie', params: { - type: 'histogram', - grid: { categoryLines: false, style: { color: '#eee' } }, - categoryAxes: [ - { - id: 'CategoryAxis-1', - type: 'category', - position: 'bottom', - show: true, - style: {}, - scale: { type: 'linear' }, - labels: { show: true, filter: true, truncate: 100 }, - title: {}, - }, - ], - valueAxes: [ - { - id: 'ValueAxis-1', - name: 'LeftAxis-1', - type: 'value', - position: 'left', - show: true, - style: {}, - scale: { type: 'linear', mode: 'normal' }, - labels: { show: true, rotate: 0, filter: false, truncate: 100 }, - title: { text: 'Count' }, - }, - ], - seriesParams: [ - { - show: 'true', - type: 'histogram', - mode: 'stacked', - data: { label: 'Count', id: '1' }, - valueAxis: 'ValueAxis-1', - drawLinesBetweenPoints: true, - showCircles: true, - }, - ], + type: 'pie', addTooltip: true, addLegend: true, legendPosition: 'right', - times: [], - addTimeMarker: false, + isDonut: true, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, + }, + uiState: { + vis: { legendOpen: true }, }, data: { searchSource: { @@ -648,28 +862,19 @@ const getVisStateAlertEvolutionTop5Agents = (indexPatternId: string) => { params: {}, }, { - id: '3', + id: '2', enabled: true, type: 'terms', - schema: 'group', + schema: 'segment', params: { - field: 'agent.name', + field: 'rule.pci_dss', size: 5, order: 'desc', orderBy: '1', - }, - }, - { - id: '2', - enabled: true, - type: 'date_histogram', - schema: 'segment', - params: { - field: 'timestamp', - interval: 'auto', - customInterval: '2h', - min_doc_count: 1, - extended_bounds: {}, + otherBucket: false, + otherBucketLabel: 'Other', + missingBucket: false, + missingBucketLabel: 'Missing', }, }, ], @@ -677,6 +882,8 @@ const getVisStateAlertEvolutionTop5Agents = (indexPatternId: string) => { }; }; +/* Definitiion of panels */ + export const getDashboardPanels = ( indexPatternId: string, pinnedAgent?: boolean, @@ -712,35 +919,49 @@ export const getDashboardPanels = ( type: 'visualization', explicitInput: { id: '6', - savedVis: getVisStateTop5Alerts(indexPatternId), + savedVis: getVisStateAlertsAgents(indexPatternId), }, }, - '3': { + '7': { gridData: { - w: 15, - h: 12, + w: 16, + h: 13, x: 0, y: 13, - i: '3', + i: '7', }, type: 'visualization', explicitInput: { - id: '3', - savedVis: getVisStateTop5Agents(indexPatternId), + id: '7', + savedVis: getVisStateTop5AlertsAgents(indexPatternId), }, }, - '4': { + '8': { gridData: { - w: 33, - h: 12, - x: 15, + w: 16, + h: 13, + x: 16, y: 13, - i: '4', + i: '8', }, type: 'visualization', explicitInput: { - id: '4', - savedVis: getVisStateAlertEvolutionTop5Agents(indexPatternId), + id: '8', + savedVis: getVisStateTop5RuleGroupsAgents(indexPatternId), + }, + }, + '9': { + gridData: { + w: 16, + h: 13, + x: 32, + y: 13, + i: '9', + }, + type: 'visualization', + explicitInput: { + id: '9', + savedVis: getVisStateTop5PCIDSSRequirementsAgents(indexPatternId), }, }, }; diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts index bbd2f81b78..c19a87a527 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts @@ -9,34 +9,35 @@ const getVisStateTotal = (indexPatternId: string) => { params: { addTooltip: true, addLegend: false, - type: 'gauge', - gauge: { - verticalSplit: false, - autoExtend: false, + type: 'metric', + metric: { percentageMode: false, - gaugeType: 'Metric', - gaugeStyle: 'Full', - backStyle: 'Full', - orientation: 'vertical', - colorSchema: 'Green to Red', - gaugeColorMode: 'None', - useRange: false, - colorsRange: [{ from: 0, to: 100 }], + useRanges: false, + colorSchema: 'Greens', + metricColorMode: 'Labels', + colorsRange: [ + { + from: 0, + to: 0, + }, + { + from: 0, + to: 0, + }, + ], + labels: { + show: true, + }, invertColors: false, - labels: { show: true, color: 'black' }, - scale: { show: false, labels: false, color: '#333', width: 2 }, - type: 'simple', style: { - fontSize: 20, + bgFill: '#000', bgColor: false, labelColor: false, subText: '', + fontSize: 40, }, }, }, - uiState: { - vis: { defaultColors: { '0 - 100': 'rgb(0,104,55)' } }, - }, data: { searchSource: { query: { @@ -59,7 +60,7 @@ const getVisStateTotal = (indexPatternId: string) => { enabled: true, type: 'count', schema: 'metric', - params: { customLabel: 'Alerts' }, + params: { customLabel: 'Total' }, }, ], }, @@ -74,34 +75,35 @@ const getVisStateLevel12Alerts = (indexPatternId: string) => { params: { addTooltip: true, addLegend: false, - type: 'gauge', - gauge: { - verticalSplit: false, - autoExtend: false, + type: 'metric', + metric: { percentageMode: false, - gaugeType: 'Metric', - gaugeStyle: 'Full', - backStyle: 'Full', - orientation: 'vertical', - colorSchema: 'Green to Red', - gaugeColorMode: 'None', - useRange: false, - colorsRange: [{ from: 0, to: 100 }], + useRanges: false, + colorSchema: 'Reds', + metricColorMode: 'Labels', + colorsRange: [ + { + from: 0, + to: 0, + }, + { + from: 0, + to: 0, + }, + ], + labels: { + show: true, + }, invertColors: false, - labels: { show: true, color: 'black' }, - scale: { show: false, labels: false, color: '#333', width: 2 }, - type: 'simple', style: { - fontSize: 20, + bgFill: '#000', bgColor: false, labelColor: false, subText: '', + fontSize: 40, }, }, }, - uiState: { - vis: { defaultColors: { '0 - 100': 'rgb(0,104,55)' } }, - }, data: { searchSource: { query: { @@ -164,34 +166,35 @@ const getVisStateAuthenticationFailure = (indexPatternId: string) => { params: { addTooltip: true, addLegend: false, - type: 'gauge', - gauge: { - verticalSplit: false, - autoExtend: false, + type: 'metric', + metric: { percentageMode: false, - gaugeType: 'Metric', - gaugeStyle: 'Full', - backStyle: 'Full', - orientation: 'vertical', - colorSchema: 'Green to Red', - gaugeColorMode: 'None', - useRange: false, - colorsRange: [{ from: 0, to: 100 }], + useRanges: false, + colorSchema: 'Reds', + metricColorMode: 'Labels', + colorsRange: [ + { + from: 0, + to: 0, + }, + { + from: 0, + to: 0, + }, + ], + labels: { + show: true, + }, invertColors: false, - labels: { show: true, color: 'black' }, - scale: { show: false, labels: false, color: '#333', width: 2 }, - type: 'simple', style: { - fontSize: 20, + bgFill: '#000', bgColor: false, labelColor: false, subText: '', + fontSize: 40, }, }, }, - uiState: { - vis: { defaultColors: { '0 - 100': 'rgb(0,104,55)' } }, - }, data: { searchSource: { query: { @@ -264,7 +267,7 @@ const getVisStateAuthenticationFailure = (indexPatternId: string) => { }; }; -const getVisStateSeverityLow = (indexPatternId: string) => { +const getVisStateAuthenticationSuccess = (indexPatternId: string) => { return { id: 'Wazuh-App-Overview-General-Authentication-success', title: 'Authentication success', @@ -272,28 +275,32 @@ const getVisStateSeverityLow = (indexPatternId: string) => { params: { addTooltip: true, addLegend: false, - type: 'gauge', - gauge: { - verticalSplit: false, - autoExtend: false, + type: 'metric', + metric: { percentageMode: false, - gaugeType: 'Metric', - gaugeStyle: 'Full', - backStyle: 'Full', - orientation: 'vertical', - colorSchema: 'Green to Red', - gaugeColorMode: 'None', - useRange: false, - colorsRange: [{ from: 0, to: 100 }], + useRanges: false, + colorSchema: 'Greens', + metricColorMode: 'Labels', + colorsRange: [ + { + from: 0, + to: 0, + }, + { + from: 0, + to: 0, + }, + ], + labels: { + show: true, + }, invertColors: false, - labels: { show: true, color: 'black' }, - scale: { show: false, labels: false, color: '#333', width: 2 }, - type: 'simple', style: { - fontSize: 20, + bgFill: '#000', bgColor: false, labelColor: false, subText: '', + fontSize: 40, }, }, }, @@ -417,7 +424,7 @@ export const getKPIsPanel = ( type: 'visualization', explicitInput: { id: '4', - savedVis: getVisStateSeverityLow(indexPatternId), + savedVis: getVisStateAuthenticationSuccess(indexPatternId), }, }, }; From 871352c295226bcbcb639b3f8491626d7c179c0a Mon Sep 17 00:00:00 2001 From: jbiset Date: Wed, 13 Mar 2024 17:20:40 -0300 Subject: [PATCH 05/15] The interaction was added to the KPIs, the links to the lower table were added, as well as the change of columns when an agent is set --- .../threat-hunting/components/no_results.tsx | 60 ++++ .../overview/threat-hunting/config/index.tsx | 121 +++++++ .../threat-hunting/dashboard/dashboard.tsx | 334 +++++++++++++++--- .../dashboard/dashboard_panels.ts | 2 + .../dashboard/dashboard_panels_kpis.ts | 161 ++++----- .../dashboard/threat_hunting_dashboard.scss | 10 + .../components/visualize/wz-visualize.js | 2 +- 7 files changed, 532 insertions(+), 158 deletions(-) create mode 100644 plugins/main/public/components/overview/threat-hunting/components/no_results.tsx create mode 100644 plugins/main/public/components/overview/threat-hunting/config/index.tsx create mode 100644 plugins/main/public/components/overview/threat-hunting/dashboard/threat_hunting_dashboard.scss diff --git a/plugins/main/public/components/overview/threat-hunting/components/no_results.tsx b/plugins/main/public/components/overview/threat-hunting/components/no_results.tsx new file mode 100644 index 0000000000..babfd51d32 --- /dev/null +++ b/plugins/main/public/components/overview/threat-hunting/components/no_results.tsx @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; + +import { EuiCallOut, EuiPanel } from '@elastic/eui'; + +interface Props { + message?: string; +} + +export const DiscoverNoResults = ({ message }: Props) => { + return ( + + + + ) + } + color='warning' + iconType='help' + data-test-subj='discoverNoResults' + /> + + + ); +}; diff --git a/plugins/main/public/components/overview/threat-hunting/config/index.tsx b/plugins/main/public/components/overview/threat-hunting/config/index.tsx new file mode 100644 index 0000000000..3da4573673 --- /dev/null +++ b/plugins/main/public/components/overview/threat-hunting/config/index.tsx @@ -0,0 +1,121 @@ +import { EuiDataGridColumn, EuiLink } from '@elastic/eui'; +import { tDataGridColumn } from '../../../common/data-grid'; +import { getCore } from '../../../../kibana-services'; +import React from 'react'; +import { RedirectAppLinks } from '../../../../../../../src/plugins/opensearch_dashboards_react/public'; + +export const MAX_ENTRIES_PER_QUERY = 10000; + +export const threatHuntingTableDefaultColumns: tDataGridColumn[] = [ + { + id: 'icon', + }, + { + id: 'timestamp', + }, + { + id: 'agent.id', + render: (value: any) => { + const destURL = getCore().application.getUrlForApp('endpoints-summary', { + path: `#/agents?tab=welcome&agent=${value}`, + }); + return ( + + + {value} + + + ); + }, + }, + { + id: 'agent.name', + }, + { + id: 'rule.mitre.id', + render: (value: any) => { + const destURL = getCore().application.getUrlForApp('mitre-attack', { + path: `#/overview/?tab=mitre&tabView=intelligence&tabRedirect=techniques&idToRedirect=${value}`, + }); + return ( + + + {value} + + + ); + }, + }, + { + id: 'rule.mitre.tactic', + }, + { + id: 'rule.description', + }, + { + id: 'rule.level', + }, + { + id: 'rule.id', + render: (value: any) => { + const destURL = getCore().application.getUrlForApp('rules', { + path: `manager/?tab=ruleset&redirectRule=${value}`, + }); + return ( + + + {value} + + + ); + }, + }, +]; + +export const threatHuntingTableAgentColumns: EuiDataGridColumn[] = [ + { + id: 'icon', + }, + { + id: 'timestamp', + }, + { + id: 'rule.mitre.id', + render: (value: any) => { + const destURL = getCore().application.getUrlForApp('mitre-attack', { + path: `#/overview/?tab=mitre&tabView=intelligence&tabRedirect=techniques&idToRedirect=${value}`, + }); + return ( + + + {value} + + + ); + }, + }, + { + id: 'rule.mitre.tactic', + }, + { + id: 'rule.description', + }, + { + id: 'rule.level', + }, + { + id: 'rule.id', + render: (value: any) => { + const destURL = getCore().application.getUrlForApp('rules', { + path: `manager/?tab=ruleset&redirectRule=${value}`, + }); + return ( + + + {value} + + + ); + }, + }, +]; diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index 3872a57ea2..118a953520 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -1,12 +1,51 @@ -import React from 'react'; -import { getPlugins } from '../../../../kibana-services'; +import React, { useState, useEffect, useMemo } from 'react'; +import { getPlugins, getWazuhCorePlugin } from '../../../../kibana-services'; import { ViewMode } from '../../../../../../../src/plugins/embeddable/public'; +import { SearchResponse } from '../../../../../../../src/core/server'; +import { IndexPattern } from '../../../../../../../src/plugins/data/common'; import { getDashboardPanels } from './dashboard_panels'; import { I18nProvider } from '@osd/i18n/react'; import useSearchBar from '../../../common/search-bar/use-search-bar'; import { WAZUH_ALERTS_PATTERN } from '../../../../../common/constants'; import { getKPIsPanel } from './dashboard_panels_kpis'; import { Filter } from '../../../../../../../src/plugins/data/common'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiButtonIcon, + EuiDataGrid, + EuiToolTip, + EuiDataGridCellValueElementProps, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiTitle, + EuiButtonEmpty, +} from '@elastic/eui'; +import { search } from '../../../common/search-bar/search-bar-service'; +import { + ErrorFactory, + ErrorHandler, + HttpError, +} from '../../../../react-services/error-management'; +import { LoadingSpinner } from '../../vulnerabilities/common/components/loading_spinner'; +import { DiscoverNoResults } from '../components/no_results'; +import { + MAX_ENTRIES_PER_QUERY, + exportSearchToCSV, +} from '../../../common/data-grid/data-grid-service'; +import { useDocViewer } from '../../../common/doc-viewer/use-doc-viewer'; +import { useDataGrid } from '../../../common/data-grid/use-data-grid'; +import { HitsCounter } from '../../../../kibana-integrations/discover/application/components/hits_counter/hits_counter'; +import { formatNumWithCommas } from '../../../../kibana-integrations/discover/application/helpers/format_number_with_commas'; +import DocViewer from '../../../common/doc-viewer/doc-viewer'; +import { withErrorBoundary } from '../../../common/hocs/error-boundary/with-error-boundary'; +import './threat_hunting_dashboard.scss'; +import { SampleDataWarning } from '../../../visualize/components/sample-data-warning'; +import { + threatHuntingTableAgentColumns, + threatHuntingTableDefaultColumns, +} from '../config'; const plugins = getPlugins(); @@ -18,71 +57,256 @@ interface DashboardThreatHuntingProps { pinnedAgent: Filter; } -export const DashboardThreatHunting: React.FC = ({ +const DashboardTH: React.FC = ({ pinnedAgent, }) => { - /* TODO: Analyze whether to use the new index pattern handler https://github.com/wazuh/wazuh-dashboard-plugins/issues/6434 */ + /* TODO: Analyze whether to use the new index pattern handler https://github.com/wazuh/wazuh-dashboard-plugins/issues/6434 + Replace WAZUH_ALERTS_PATTERN with appState.getCurrentPattern... */ const TH_INDEX_PATTERN_ID = WAZUH_ALERTS_PATTERN; const { searchBarProps } = useSearchBar({ defaultIndexPatternID: TH_INDEX_PATTERN_ID, }); + const { isLoading, query, indexPatterns } = searchBarProps; + const [indexPattern, setIndexPattern] = useState( + undefined, + ); + const [isSearching, setIsSearching] = useState(false); + const [inspectedHit, setInspectedHit] = useState(undefined); + const [isExporting, setIsExporting] = useState(false); + + const [results, setResults] = useState({} as SearchResponse); + + const sideNavDocked = getWazuhCorePlugin().hooks.useDockedSideNav(); + + const onClickInspectDoc = useMemo( + () => (index: number) => { + const rowClicked = results.hits.hits[index]; + setInspectedHit(rowClicked); + }, + [results], + ); + + const DocViewInspectButton = ({ + rowIndex, + }: EuiDataGridCellValueElementProps) => { + const inspectHintMsg = 'Inspect document details'; + return ( + + onClickInspectDoc(rowIndex)} + iconType='inspect' + aria-label={inspectHintMsg} + /> + + ); + }; + + const dataGridProps = useDataGrid({ + ariaLabelledBy: 'Threat Hunting Table', + defaultColumns: threatHuntingTableDefaultColumns, + results, + indexPattern: indexPattern as IndexPattern, + DocViewInspectButton, + }); + + const { pagination, sorting, columnVisibility } = dataGridProps; + + const docViewerProps = useDocViewer({ + doc: inspectedHit, + indexPattern: indexPattern as IndexPattern, + }); + + useEffect(() => { + const currentColumns = !pinnedAgent + ? threatHuntingTableDefaultColumns + : threatHuntingTableAgentColumns; + columnVisibility.setVisibleColumns(currentColumns.map(({ id }) => id)); + }, [pinnedAgent]); + + useEffect(() => { + if (!isLoading) { + setIndexPattern(indexPatterns?.[0] as IndexPattern); + search({ + indexPattern: indexPatterns?.[0] as IndexPattern, + filters: searchBarProps.filters ?? [], + query, + pagination, + sorting, + }) + .then(results => { + setResults(results); + setIsSearching(false); + }) + .catch(error => { + const searchError = ErrorFactory.create(HttpError, { + error, + message: 'Error fetching vulnerabilities', + }); + ErrorHandler.handleError(searchError); + setIsSearching(false); + }); + } + }, [ + JSON.stringify(searchBarProps), + JSON.stringify(pagination), + JSON.stringify(sorting), + ]); + + const onClickExportResults = async () => { + const params = { + indexPattern: indexPatterns?.[0] as IndexPattern, + filters: searchBarProps.filters ?? [], + query, + fields: columnVisibility.visibleColumns, + pagination: { + pageIndex: 0, + pageSize: results.hits.total, + }, + sorting, + }; + try { + setIsExporting(true); + await exportSearchToCSV(params); + } catch (error) { + const searchError = ErrorFactory.create(HttpError, { + error, + message: 'Error downloading csv report', + }); + ErrorHandler.handleError(searchError); + } finally { + setIsExporting(false); + } + }; + return ( <> - + {isLoading ? : null} + {!isLoading ? ( + + ) : null} + {isSearching ? : null} + + {!isLoading && !isSearching && results?.hits?.total === 0 ? ( + + ) : null} + {!isLoading && !isSearching && results?.hits?.total > 0 ? ( +
+ + + + {}} + tooltip={ + results?.hits?.total && + results?.hits?.total > MAX_ENTRIES_PER_QUERY + ? { + ariaLabel: 'Warning', + content: `The query results has exceeded the limit of 10,000 hits. To provide a better experience the table only shows the first ${formatNumWithCommas( + MAX_ENTRIES_PER_QUERY, + )} hits.`, + iconType: 'alert', + position: 'top', + } + : undefined + } + /> + + Export Formated + + + ), + }} + /> + {inspectedHit && ( + setInspectedHit(undefined)} size='m'> + + +

Document details

+
+
+ + + + + + + +
+ )} +
+ ) : null}
- - ); }; + +export const DashboardThreatHunting = withErrorBoundary(DashboardTH); diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts index a095aa5a47..77d2626643 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels.ts @@ -1,6 +1,8 @@ import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; +/* WARNING: The panel id must be unique including general and agents visualizations. Otherwise, the visualizations will not refresh when we pin an agent, because they are cached by id */ + /* Overview visualizations */ const getVisStateTop10AlertLevelEvolution = (indexPatternId: string) => { diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts index c19a87a527..772add24a0 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard_panels_kpis.ts @@ -60,7 +60,7 @@ const getVisStateTotal = (indexPatternId: string) => { enabled: true, type: 'count', schema: 'metric', - params: { customLabel: 'Total' }, + params: { customLabel: '- Total -' }, }, ], }, @@ -110,32 +110,7 @@ const getVisStateLevel12Alerts = (indexPatternId: string) => { language: 'kuery', query: '', }, - filter: [ - { - $state: { - store: 'appState', - }, - meta: { - alias: null, - disabled: false, - index: 'wazuh-alerts', - key: 'rule.level', - negate: false, - params: { - gte: 12, - lt: null, - }, - type: 'range', - value: '12 to +∞', - }, - range: { - 'rule.level': { - gte: 12, - lt: null, - }, - }, - }, - ], + filter: [], index: indexPatternId, }, references: [ @@ -151,7 +126,24 @@ const getVisStateLevel12Alerts = (indexPatternId: string) => { enabled: true, type: 'count', schema: 'metric', - params: { customLabel: 'Level 12 or above alerts' }, + params: { customLabel: ' ' }, + }, + { + id: '2', + enabled: true, + type: 'filters', + params: { + filters: [ + { + input: { + query: 'rule.level >= 12', + language: 'kuery', + }, + label: '- Level 12 or above alerts', + }, + ], + }, + schema: 'group', }, ], }, @@ -201,50 +193,7 @@ const getVisStateAuthenticationFailure = (indexPatternId: string) => { language: 'kuery', query: '', }, - filter: [ - { - meta: { - index: 'wazuh-alerts', - type: 'phrases', - key: 'rule.groups', - value: - 'win_authentication_failed, authentication_failed, authentication_failures', - params: [ - 'win_authentication_failed', - 'authentication_failed', - 'authentication_failures', - ], - negate: false, - disabled: false, - alias: null, - }, - query: { - bool: { - should: [ - { - match_phrase: { - 'rule.groups': 'win_authentication_failed', - }, - }, - { - match_phrase: { - 'rule.groups': 'authentication_failed', - }, - }, - { - match_phrase: { - 'rule.groups': 'authentication_failures', - }, - }, - ], - minimum_should_match: 1, - }, - }, - $state: { - store: 'appState', - }, - }, - ], + filter: [], index: indexPatternId, }, references: [ @@ -260,7 +209,25 @@ const getVisStateAuthenticationFailure = (indexPatternId: string) => { enabled: true, type: 'count', schema: 'metric', - params: { customLabel: 'Authentication failure' }, + params: { customLabel: ' ' }, + }, + { + id: '2', + enabled: true, + type: 'filters', + params: { + filters: [ + { + input: { + query: + 'rule.groups: "win_authentication_failed" OR rule.groups: "authentication_failed" OR rule.groups: "authentication_failures"', + language: 'kuery', + }, + label: '- Authentication failure', + }, + ], + }, + schema: 'group', }, ], }, @@ -313,34 +280,7 @@ const getVisStateAuthenticationSuccess = (indexPatternId: string) => { language: 'kuery', query: '', }, - filter: [ - { - meta: { - index: 'wazuh-alerts', - negate: false, - disabled: false, - alias: null, - type: 'phrase', - key: 'rule.groups', - value: 'authentication_success', - params: { - query: 'authentication_success', - type: 'phrase', - }, - }, - query: { - match: { - 'rule.groups': { - query: 'authentication_success', - type: 'phrase', - }, - }, - }, - $state: { - store: 'appState', - }, - }, - ], + filter: [], index: indexPatternId, }, references: [ @@ -356,7 +296,24 @@ const getVisStateAuthenticationSuccess = (indexPatternId: string) => { enabled: true, type: 'count', schema: 'metric', - params: { customLabel: 'Authentication success' }, + params: { customLabel: ' ' }, + }, + { + id: '2', + enabled: true, + type: 'filters', + params: { + filters: [ + { + input: { + query: 'rule.groups: "authentication_success"', + language: 'kuery', + }, + label: '- Authentication success', + }, + ], + }, + schema: 'group', }, ], }, diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/threat_hunting_dashboard.scss b/plugins/main/public/components/overview/threat-hunting/dashboard/threat_hunting_dashboard.scss new file mode 100644 index 0000000000..c8e78aed47 --- /dev/null +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/threat_hunting_dashboard.scss @@ -0,0 +1,10 @@ +.th-dashboard-responsive { + @media (max-width: 767px) { + .react-grid-layout { + height: auto !important; + } + .dshLayout-isMaximizedPanel { + height: 100% !important; + } + } +} diff --git a/plugins/main/public/components/visualize/wz-visualize.js b/plugins/main/public/components/visualize/wz-visualize.js index 61aa5c3585..dec378713d 100644 --- a/plugins/main/public/components/visualize/wz-visualize.js +++ b/plugins/main/public/components/visualize/wz-visualize.js @@ -337,7 +337,7 @@ export const WzVisualize = compose( className='embPanel__header' >

- Security Alerts + Security Alerts table

Date: Thu, 18 Apr 2024 17:02:43 -0300 Subject: [PATCH 06/15] Integrated new data source on Threat Hunting module --- .../common/modules/modules-defaults.tsx | 12 +- .../threat-hunting/dashboard/dashboard.tsx | 140 +++++++++--------- 2 files changed, 83 insertions(+), 69 deletions(-) diff --git a/plugins/main/public/components/common/modules/modules-defaults.tsx b/plugins/main/public/components/common/modules/modules-defaults.tsx index 3d52c4055e..92d5c4e891 100644 --- a/plugins/main/public/components/common/modules/modules-defaults.tsx +++ b/plugins/main/public/components/common/modules/modules-defaults.tsx @@ -46,7 +46,10 @@ import { mitreAttackColumns } from '../../overview/mitre/events/mitre-attack-col import { virustotalColumns } from '../../overview/virustotal/events/virustotal-columns'; import { malwareDetectionColumns } from '../../overview/malware-detection/events/malware-detection-columns'; import { WAZUH_VULNERABILITIES_PATTERN } from '../../../../common/constants'; -import { AlertsVulnerabilitiesDataSource } from '../data-source'; +import { + AlertsDataSource, + AlertsVulnerabilitiesDataSource, +} from '../data-source'; const ALERTS_INDEX_PATTERN = 'wazuh-alerts-*'; const DEFAULT_INDEX_PATTERN = ALERTS_INDEX_PATTERN; @@ -87,9 +90,12 @@ export const ModulesDefaults = { id: 'dashboard', name: 'Dashboard', buttons: [ButtonModuleExploreAgent, ButtonModuleGenerateReport], - component: withPinnedAgent(DashboardThreatHunting), + component: DashboardThreatHunting, }, - renderDiscoverTab(DEFAULT_INDEX_PATTERN, threatHuntingColumns), + renderDiscoverTab({ + tableColumns: threatHuntingColumns, + DataSource: AlertsDataSource, + }), ], availableFor: ['manager', 'agent'], }, diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index 118a953520..ae9f31ac10 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -6,9 +6,7 @@ import { IndexPattern } from '../../../../../../../src/plugins/data/common'; import { getDashboardPanels } from './dashboard_panels'; import { I18nProvider } from '@osd/i18n/react'; import useSearchBar from '../../../common/search-bar/use-search-bar'; -import { WAZUH_ALERTS_PATTERN } from '../../../../../common/constants'; import { getKPIsPanel } from './dashboard_panels_kpis'; -import { Filter } from '../../../../../../../src/plugins/data/common'; import { EuiFlexGroup, EuiFlexItem, @@ -46,6 +44,14 @@ import { threatHuntingTableAgentColumns, threatHuntingTableDefaultColumns, } from '../config'; +import { + AlertsDataSource, + AlertsDataSourceRepository, + PatternDataSource, + PatternDataSourceFilterManager, + tParsedIndexPattern, + useDataSource, +} from '../../../common/data-source'; const plugins = getPlugins(); @@ -53,31 +59,31 @@ const SearchBar = getPlugins().data.ui.SearchBar; const DashboardByRenderer = plugins.dashboard.DashboardContainerByValueRenderer; -interface DashboardThreatHuntingProps { - pinnedAgent: Filter; -} +const DashboardTH: React.FC = () => { + const { + filters, + dataSource, + fetchFilters, + isLoading: isDataSourceLoading, + fetchData, + setFilters, + } = useDataSource({ + DataSource: AlertsDataSource, + repository: new AlertsDataSourceRepository(), + }); -const DashboardTH: React.FC = ({ - pinnedAgent, -}) => { - /* TODO: Analyze whether to use the new index pattern handler https://github.com/wazuh/wazuh-dashboard-plugins/issues/6434 - Replace WAZUH_ALERTS_PATTERN with appState.getCurrentPattern... */ - const TH_INDEX_PATTERN_ID = WAZUH_ALERTS_PATTERN; + const [results, setResults] = useState({} as SearchResponse); const { searchBarProps } = useSearchBar({ - defaultIndexPatternID: TH_INDEX_PATTERN_ID, + indexPattern: dataSource?.indexPattern as IndexPattern, + filters, + setFilters, }); + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; - const { isLoading, query, indexPatterns } = searchBarProps; - const [indexPattern, setIndexPattern] = useState( - undefined, - ); - const [isSearching, setIsSearching] = useState(false); const [inspectedHit, setInspectedHit] = useState(undefined); const [isExporting, setIsExporting] = useState(false); - const [results, setResults] = useState({} as SearchResponse); - const sideNavDocked = getWazuhCorePlugin().hooks.useDockedSideNav(); const onClickInspectDoc = useMemo( @@ -107,7 +113,7 @@ const DashboardTH: React.FC = ({ ariaLabelledBy: 'Threat Hunting Table', defaultColumns: threatHuntingTableDefaultColumns, results, - indexPattern: indexPattern as IndexPattern, + indexPattern: dataSource?.indexPattern, DocViewInspectButton, }); @@ -115,9 +121,13 @@ const DashboardTH: React.FC = ({ const docViewerProps = useDocViewer({ doc: inspectedHit, - indexPattern: indexPattern as IndexPattern, + indexPattern: dataSource?.indexPattern, }); + const pinnedAgent = + PatternDataSourceFilterManager.getPinnedAgentFilter(dataSource?.id!) + .length > 0; + useEffect(() => { const currentColumns = !pinnedAgent ? threatHuntingTableDefaultColumns @@ -126,38 +136,33 @@ const DashboardTH: React.FC = ({ }, [pinnedAgent]); useEffect(() => { - if (!isLoading) { - setIndexPattern(indexPatterns?.[0] as IndexPattern); - search({ - indexPattern: indexPatterns?.[0] as IndexPattern, - filters: searchBarProps.filters ?? [], - query, - pagination, - sorting, + if (isDataSourceLoading) { + return; + } + fetchData({ query, pagination, sorting }) + .then(results => { + setResults(results); }) - .then(results => { - setResults(results); - setIsSearching(false); - }) - .catch(error => { - const searchError = ErrorFactory.create(HttpError, { - error, - message: 'Error fetching vulnerabilities', - }); - ErrorHandler.handleError(searchError); - setIsSearching(false); + .catch(error => { + const searchError = ErrorFactory.create(HttpError, { + error, + message: 'Error fetching threat hunting', }); - } + ErrorHandler.handleError(searchError); + }); }, [ - JSON.stringify(searchBarProps), + JSON.stringify(fetchFilters), + JSON.stringify(query), JSON.stringify(pagination), JSON.stringify(sorting), + dateRangeFrom, + dateRangeTo, ]); const onClickExportResults = async () => { const params = { - indexPattern: indexPatterns?.[0] as IndexPattern, - filters: searchBarProps.filters ?? [], + indexPattern: dataSource?.indexPattern, + filters: fetchFilters ?? [], query, fields: columnVisibility.visibleColumns, pagination: { @@ -181,31 +186,34 @@ const DashboardTH: React.FC = ({ }; return ( - <> - - {isLoading ? : null} - {!isLoading ? ( - - ) : null} - {isSearching ? : null} - - {!isLoading && !isSearching && results?.hits?.total === 0 ? ( + + <> + {isDataSourceLoading && !dataSource ? ( + + ) : ( +
+ +
+ )} + {dataSource && results?.hits?.total > 0 ? : null} + {dataSource && results?.hits?.total === 0 ? ( ) : null} - {!isLoading && !isSearching && results?.hits?.total > 0 ? ( + {dataSource && results?.hits?.total > 0 ? (
= ({ = ({ )}
) : null} -
- + +
); }; From 3bef252875bfdc2edf7f538b71cbfea443f1b59d Mon Sep 17 00:00:00 2001 From: jbiset Date: Fri, 19 Apr 2024 18:51:47 -0300 Subject: [PATCH 07/15] DiscoverNoResults and LoadingSpinner components are replaced with common components --- .../threat-hunting/components/no_results.tsx | 60 ------------------- .../threat-hunting/dashboard/dashboard.tsx | 5 +- 2 files changed, 2 insertions(+), 63 deletions(-) delete mode 100644 plugins/main/public/components/overview/threat-hunting/components/no_results.tsx diff --git a/plugins/main/public/components/overview/threat-hunting/components/no_results.tsx b/plugins/main/public/components/overview/threat-hunting/components/no_results.tsx deleted file mode 100644 index babfd51d32..0000000000 --- a/plugins/main/public/components/overview/threat-hunting/components/no_results.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import React from 'react'; -import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; - -import { EuiCallOut, EuiPanel } from '@elastic/eui'; - -interface Props { - message?: string; -} - -export const DiscoverNoResults = ({ message }: Props) => { - return ( - - - - ) - } - color='warning' - iconType='help' - data-test-subj='discoverNoResults' - /> - - - ); -}; diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index ae9f31ac10..b9672a7166 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -20,14 +20,11 @@ import { EuiTitle, EuiButtonEmpty, } from '@elastic/eui'; -import { search } from '../../../common/search-bar/search-bar-service'; import { ErrorFactory, ErrorHandler, HttpError, } from '../../../../react-services/error-management'; -import { LoadingSpinner } from '../../vulnerabilities/common/components/loading_spinner'; -import { DiscoverNoResults } from '../components/no_results'; import { MAX_ENTRIES_PER_QUERY, exportSearchToCSV, @@ -52,6 +49,8 @@ import { tParsedIndexPattern, useDataSource, } from '../../../common/data-source'; +import { DiscoverNoResults } from '../../../common/no-results/no-results'; +import { LoadingSpinner } from '../../../common/loading-spinner/loading-spinner'; const plugins = getPlugins(); From 30d8ffd47032fe5c867970243a832d3a66acbf17 Mon Sep 17 00:00:00 2001 From: jbiset Date: Mon, 22 Apr 2024 19:13:20 -0300 Subject: [PATCH 08/15] Clean code and fixed dashboards conditions --- .../common/hocs/withPinnedAgent.tsx | 19 ------- .../threat-hunting/dashboard/dashboard.tsx | 8 +-- .../dashboard/dashboard_panels.ts | 54 +++++++++---------- 3 files changed, 32 insertions(+), 49 deletions(-) delete mode 100644 plugins/main/public/components/common/hocs/withPinnedAgent.tsx diff --git a/plugins/main/public/components/common/hocs/withPinnedAgent.tsx b/plugins/main/public/components/common/hocs/withPinnedAgent.tsx deleted file mode 100644 index 0a8decaf56..0000000000 --- a/plugins/main/public/components/common/hocs/withPinnedAgent.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Wazuh app - React HOCs to manage allowed agents - * Copyright (C) 2015-2022 Wazuh, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Find more information about this on the LICENSE file. - */ - -import React from 'react'; -import { ModulesHelper } from '../modules/modules-helper'; - -export const withPinnedAgent = WrappedComponent => props => { - const pinnedAgent = ModulesHelper.getImplicitPinnedAgent('wazuh-alerts-*'); - return ; -}; diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index b9672a7166..49fedda76d 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -201,11 +201,13 @@ const DashboardTH: React.FC = () => { /> )} - {dataSource && results?.hits?.total > 0 ? : null} - {dataSource && results?.hits?.total === 0 ? ( + {!isDataSourceLoading && dataSource && results?.hits?.total > 0 ? ( + + ) : null} + {!isDataSourceLoading && dataSource && results?.hits?.total === 0 ? ( ) : null} - {dataSource && results?.hits?.total > 0 ? ( + {!isDataSourceLoading && dataSource && results?.hits?.total > 0 ? (
; } => { const pinnedAgentPanels = { - '5': { + '9': { gridData: { w: 24, h: 13, x: 0, y: 0, - i: '5', + i: '9', }, type: 'visualization', explicitInput: { - id: '5', + id: '9', savedVis: getVisStatePinnedAgentTop10AlertGroupsEvolution(indexPatternId), }, }, - '6': { + '10': { gridData: { w: 24, h: 13, x: 24, y: 0, - i: '6', + i: '10', }, type: 'visualization', explicitInput: { - id: '6', + id: '10', savedVis: getVisStateAlertsAgents(indexPatternId), }, }, - '7': { + '11': { gridData: { w: 16, h: 13, x: 0, y: 13, - i: '7', + i: '11', }, type: 'visualization', explicitInput: { - id: '7', + id: '11', savedVis: getVisStateTop5AlertsAgents(indexPatternId), }, }, - '8': { + '12': { gridData: { w: 16, h: 13, x: 16, y: 13, - i: '8', + i: '12', }, type: 'visualization', explicitInput: { - id: '8', + id: '12', savedVis: getVisStateTop5RuleGroupsAgents(indexPatternId), }, }, - '9': { + '13': { gridData: { w: 16, h: 13, x: 32, y: 13, - i: '9', + i: '13', }, type: 'visualization', explicitInput: { - id: '9', + id: '13', savedVis: getVisStateTop5PCIDSSRequirementsAgents(indexPatternId), }, }, }; const panels = { - '1': { + '5': { gridData: { w: 28, h: 13, x: 0, y: 0, - i: '1', + i: '5', }, type: 'visualization', explicitInput: { - id: '1', + id: '5', savedVis: getVisStateTop10AlertLevelEvolution(indexPatternId), }, }, - '2': { + '6': { gridData: { w: 20, h: 13, x: 28, y: 0, - i: '2', + i: '6', }, type: 'visualization', explicitInput: { - id: '2', + id: '6', savedVis: getVisStateTop10MITREATTACKS(indexPatternId), }, }, - '3': { + '7': { gridData: { w: 15, h: 12, x: 0, y: 13, - i: '3', + i: '7', }, type: 'visualization', explicitInput: { - id: '3', + id: '7', savedVis: getVisStateTop5Agents(indexPatternId), }, }, - '4': { + '8': { gridData: { w: 33, h: 12, x: 15, y: 13, - i: '4', + i: '8', }, type: 'visualization', explicitInput: { - id: '4', + id: '8', savedVis: getVisStateAlertEvolutionTop5Agents(indexPatternId), }, }, From e25b05948d8bdb7a2b19b3603656de370eef5636 Mon Sep 17 00:00:00 2001 From: jbiset Date: Tue, 23 Apr 2024 08:57:23 -0300 Subject: [PATCH 09/15] Improved condition for rendering the dashboard and SampleData message --- .../threat-hunting/dashboard/dashboard.tsx | 214 +++++++++--------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index 49fedda76d..c591165bf5 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -201,117 +201,117 @@ const DashboardTH: React.FC = () => { />
)} - {!isDataSourceLoading && dataSource && results?.hits?.total > 0 ? ( - - ) : null} {!isDataSourceLoading && dataSource && results?.hits?.total === 0 ? ( ) : null} {!isDataSourceLoading && dataSource && results?.hits?.total > 0 ? ( -
- - - - {}} - tooltip={ - results?.hits?.total && - results?.hits?.total > MAX_ENTRIES_PER_QUERY - ? { - ariaLabel: 'Warning', - content: `The query results has exceeded the limit of 10,000 hits. To provide a better experience the table only shows the first ${formatNumWithCommas( - MAX_ENTRIES_PER_QUERY, - )} hits.`, - iconType: 'alert', - position: 'top', - } - : undefined - } - /> - - Export Formated - - - ), - }} - /> - {inspectedHit && ( - setInspectedHit(undefined)} size='m'> - - -

Document details

-
-
- - - - - - - -
- )} -
+ <> + +
+ + + + {}} + tooltip={ + results?.hits?.total && + results?.hits?.total > MAX_ENTRIES_PER_QUERY + ? { + ariaLabel: 'Warning', + content: `The query results has exceeded the limit of 10,000 hits. To provide a better experience the table only shows the first ${formatNumWithCommas( + MAX_ENTRIES_PER_QUERY, + )} hits.`, + iconType: 'alert', + position: 'top', + } + : undefined + } + /> + + Export Formated + + + ), + }} + /> + {inspectedHit && ( + setInspectedHit(undefined)} size='m'> + + +

Document details

+
+
+ + + + + + + +
+ )} +
+ ) : null} From 4ac01ffa21d71271c6b37f74ff97a3a4792ba4e6 Mon Sep 17 00:00:00 2001 From: jbiset Date: Wed, 24 Apr 2024 16:05:04 -0300 Subject: [PATCH 10/15] Removed unnecessary general/threat hunting in tabFilters in common data to remove duplicate filters --- plugins/main/public/services/common-data.js | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/main/public/services/common-data.js b/plugins/main/public/services/common-data.js index bd5d18d0f4..96c6029ba0 100644 --- a/plugins/main/public/services/common-data.js +++ b/plugins/main/public/services/common-data.js @@ -128,7 +128,6 @@ export class CommonData { async af(filterHandler, tab, agent = false) { try { const tabFilters = { - general: { group: '' }, welcome: { group: '' }, fim: { group: 'syscheck' }, pm: { group: 'rootcheck' }, From c090a533a466205664a3198ca9a13408ab353cc9 Mon Sep 17 00:00:00 2001 From: jbiset Date: Wed, 24 Apr 2024 16:06:02 -0300 Subject: [PATCH 11/15] Removed unused getImplicitPinnedAgent in modules-helper --- .../common/modules/modules-helper.js | 55 ------------------- 1 file changed, 55 deletions(-) diff --git a/plugins/main/public/components/common/modules/modules-helper.js b/plugins/main/public/components/common/modules/modules-helper.js index 55fa313905..2cae56749a 100644 --- a/plugins/main/public/components/common/modules/modules-helper.js +++ b/plugins/main/public/components/common/modules/modules-helper.js @@ -184,59 +184,4 @@ If this case happens, the implicit filters are regenerated and the function is c return filters; } - - /** - * - * @param {string} indexPattern - Index pattern id being used - * @param {Filter[] | undefined} filters - (Optional) Filter Array in which to search if a pinned agent exists - * @returns - */ - static getImplicitPinnedAgent(indexPattern, filters = []) { - const filterManager = useFilterManager().filterManager; - const initialFilters = - filters?.length > 0 ? filters : filterManager.getFilters(); - const pinnedAgentByFilterManager = initialFilters.find( - filter => - filter?.meta?.key === 'agent.id' && !!filter?.$state?.isImplicit, - ); - const url = window.location.href; - const regex = new RegExp('agentId=' + '[^&]*'); - const match = url.match(regex); - const isPinnedAgentByUrl = match && match[0]; - if (pinnedAgentByFilterManager && isPinnedAgentByUrl) { - return { - ...pinnedAgentByFilterManager, - meta: { - ...pinnedAgentByFilterManager.meta, - index: indexPattern, - }, - $state: { store: FilterStateStore.APP_STATE, isImplicit: true }, - }; - } - - if (isPinnedAgentByUrl) { - const agentId = match[0].split('=')[1]; - return { - meta: { - alias: null, - disabled: false, - key: 'agent.id', - negate: false, - params: { query: agentId }, - type: 'phrase', - index: indexPattern, - }, - query: { - match: { - 'agent.id': { - query: agentId, - type: 'phrase', - }, - }, - }, - $state: { store: 'appState', isImplicit: true }, - }; - } - return undefined; - } } From 52da83ef93323be2f60678fff5c3b8735d0310c4 Mon Sep 17 00:00:00 2001 From: jbiset Date: Wed, 24 Apr 2024 16:12:26 -0300 Subject: [PATCH 12/15] Added dateRange param to fetchData in dashboard useEffect, added wz-discover hide-filter-control classes to hide the button that allows you to affect all the filters in the search bar and use searchbarProps deconstruction --- .../threat-hunting/dashboard/dashboard.tsx | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index c591165bf5..f5b1cb15cc 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -138,7 +138,15 @@ const DashboardTH: React.FC = () => { if (isDataSourceLoading) { return; } - fetchData({ query, pagination, sorting }) + fetchData({ + query, + pagination, + sorting, + dateRange: { + from: dateRangeFrom, + to: dateRangeTo, + }, + }) .then(results => { setResults(results); }) @@ -190,7 +198,7 @@ const DashboardTH: React.FC = () => { {isDataSourceLoading && !dataSource ? ( ) : ( -
+
{ useMargins: true, id: 'kpis-th-dashboard-tab', timeRange: { - from: searchBarProps.dateRangeFrom, - to: searchBarProps.dateRangeTo, + from: dateRangeFrom, + to: dateRangeTo, }, title: 'KPIs Threat Hunting dashboard', description: 'KPIs Dashboard of the Threat Hunting', - query: searchBarProps.query, + query: query, refreshConfig: { pause: false, value: 15, @@ -239,12 +247,12 @@ const DashboardTH: React.FC = () => { useMargins: true, id: 'th-dashboard-tab', timeRange: { - from: searchBarProps.dateRangeFrom, - to: searchBarProps.dateRangeTo, + from: dateRangeFrom, + to: dateRangeTo, }, title: 'Threat Hunting dashboard', description: 'Dashboard of the Threat Hunting', - query: searchBarProps.query, + query: query, refreshConfig: { pause: false, value: 15, From ffa1282a60b3dc13649709db93e6fe34be2e2a74 Mon Sep 17 00:00:00 2001 From: jbiset Date: Wed, 24 Apr 2024 16:15:20 -0300 Subject: [PATCH 13/15] Deleted unnecessary wz-discover class on SearchBar wrapper --- .../components/overview/threat-hunting/dashboard/dashboard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index f5b1cb15cc..f5d405bdd7 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -198,7 +198,7 @@ const DashboardTH: React.FC = () => { {isDataSourceLoading && !dataSource ? ( ) : ( -
+
Date: Wed, 24 Apr 2024 16:36:42 -0300 Subject: [PATCH 14/15] Changed Threat Hunting columns file name --- .../components/overview/threat-hunting/dashboard/dashboard.tsx | 2 +- .../{config/index.tsx => events/threat-hunting-columns.tsx} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename plugins/main/public/components/overview/threat-hunting/{config/index.tsx => events/threat-hunting-columns.tsx} (100%) diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index f5d405bdd7..e812c2f832 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -40,7 +40,7 @@ import { SampleDataWarning } from '../../../visualize/components/sample-data-war import { threatHuntingTableAgentColumns, threatHuntingTableDefaultColumns, -} from '../config'; +} from '../events/threat-hunting-columns'; import { AlertsDataSource, AlertsDataSourceRepository, diff --git a/plugins/main/public/components/overview/threat-hunting/config/index.tsx b/plugins/main/public/components/overview/threat-hunting/events/threat-hunting-columns.tsx similarity index 100% rename from plugins/main/public/components/overview/threat-hunting/config/index.tsx rename to plugins/main/public/components/overview/threat-hunting/events/threat-hunting-columns.tsx From e8611aac9520bff18746cfc575045ab8e6f1645a Mon Sep 17 00:00:00 2001 From: jbiset Date: Wed, 24 Apr 2024 17:35:10 -0300 Subject: [PATCH 15/15] Deleted unused imports in modules-helper --- plugins/main/public/components/common/modules/modules-helper.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/main/public/components/common/modules/modules-helper.js b/plugins/main/public/components/common/modules/modules-helper.js index 2cae56749a..0443f4a40b 100644 --- a/plugins/main/public/components/common/modules/modules-helper.js +++ b/plugins/main/public/components/common/modules/modules-helper.js @@ -2,8 +2,6 @@ import { getAngularModule, getDataPlugin } from '../../../kibana-services'; import { AppState } from '../../../react-services/app-state'; import { FilterHandler } from '../../../utils/filter-handler'; import { VULNERABILITY_IMPLICIT_CLUSTER_MODE_FILTER } from '../../../../common/constants'; -import { useFilterManager } from '../hooks'; -import { FilterStateStore } from '../../../../../../src/plugins/data/common'; export class ModulesHelper { static async getDiscoverScope() {