diff --git a/docker/osd-dev/dev.yml b/docker/osd-dev/dev.yml
index c07d2b6c6d..2dcc8a56d5 100755
--- a/docker/osd-dev/dev.yml
+++ b/docker/osd-dev/dev.yml
@@ -239,11 +239,13 @@ services:
- ${OSD_PORT}:5601
environment:
- 'LOGS=/proc/1/fd/1'
+ tty: true
volumes:
- osd_cache:/home/node/.cache
- '${SRC}/main:/home/node/kbn/plugins/main'
- '${SRC}/wazuh-core:/home/node/kbn/plugins/wazuh-core'
- '${SRC}/wazuh-check-updates:/home/node/kbn/plugins/wazuh-check-updates'
+ - '${SRC}/wazuh-security-policies:/home/node/kbn/plugins/wazuh-security-policies'
- '${SRC}/wazuh-engine:/home/node/kbn/plugins/wazuh-engine'
- '${SRC}/wazuh-fleet:/home/node/kbn/plugins/wazuh-fleet'
- wd_certs:/home/node/kbn/certs/
diff --git a/plugins/wazuh-security-policies/.i18nrc.json b/plugins/wazuh-security-policies/.i18nrc.json
new file mode 100644
index 0000000000..5e344386a4
--- /dev/null
+++ b/plugins/wazuh-security-policies/.i18nrc.json
@@ -0,0 +1,7 @@
+{
+ "prefix": "wazuhSecurityPolicies",
+ "paths": {
+ "wazuhSecurityPolicies": "."
+ },
+ "translations": ["translations/ja-JP.json"]
+}
diff --git a/plugins/wazuh-security-policies/README.md b/plugins/wazuh-security-policies/README.md
new file mode 100755
index 0000000000..4e213dc5f0
--- /dev/null
+++ b/plugins/wazuh-security-policies/README.md
@@ -0,0 +1,22 @@
+# wazuhSecurityPolicies
+
+A OpenSearch Dashboards plugin
+
+---
+
+## Development
+
+See the [OpenSearch Dashboards contributing
+guide](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/main/CONTRIBUTING.md) for instructions
+setting up your development environment.
+
+ ## Scripts
+
+ yarn osd bootstrap
+ - Execute this to install node_modules and setup the dependencies in your plugin and in OpenSearch Dashboards
+
+
+ yarn plugin-helpers build
+ - Execute this to create a distributable version of this plugin that can be installed in OpenSearch Dashboards
+
+
diff --git a/plugins/wazuh-security-policies/common/index.ts b/plugins/wazuh-security-policies/common/index.ts
new file mode 100644
index 0000000000..2ede64bf71
--- /dev/null
+++ b/plugins/wazuh-security-policies/common/index.ts
@@ -0,0 +1,2 @@
+export const PLUGIN_ID = 'wazuhSecurityPolicies';
+export const PLUGIN_NAME = 'Ruleset';
diff --git a/plugins/wazuh-security-policies/opensearch_dashboards.json b/plugins/wazuh-security-policies/opensearch_dashboards.json
new file mode 100644
index 0000000000..77ac702ffd
--- /dev/null
+++ b/plugins/wazuh-security-policies/opensearch_dashboards.json
@@ -0,0 +1,9 @@
+{
+ "id": "wazuhSecurityPolicies",
+ "version": "1.0.0",
+ "opensearchDashboardsVersion": "opensearchDashboards",
+ "server": true,
+ "ui": true,
+ "requiredPlugins": ["navigation", "opensearchDashboardsUtils"],
+ "optionalPlugins": []
+}
diff --git a/plugins/wazuh-security-policies/package.json b/plugins/wazuh-security-policies/package.json
new file mode 100644
index 0000000000..7832c342e2
--- /dev/null
+++ b/plugins/wazuh-security-policies/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "wazuhSecurityPolicies",
+ "version": "0.0.0",
+ "private": true,
+ "scripts": {
+ "build": "yarn plugin-helpers build",
+ "plugin-helpers": "../../scripts/use_node ../../scripts/plugin_helpers",
+ "osd": "../../scripts/use_node ../../scripts/osd"
+ },
+ "dependencies": {
+ "@types/js-yaml": "^4.0.9",
+ "js-yaml": "^4.1.0"
+ },
+ "devDependencies": {
+ "@types/react": "^19.0.8"
+ }
+}
diff --git a/plugins/wazuh-security-policies/public/application.tsx b/plugins/wazuh-security-policies/public/application.tsx
new file mode 100644
index 0000000000..803dd71fdb
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/application.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { AppMountParameters, CoreStart } from '../../../src/core/public';
+import { AppPluginStartDependencies } from './types';
+import { WazuhSecurityPoliciesApp } from './components/app';
+
+export const renderApp = (
+ { notifications, http }: CoreStart,
+ { navigation }: AppPluginStartDependencies,
+ { appBasePath, element }: AppMountParameters,
+) => {
+ ReactDOM.render(
+ ,
+ element,
+ );
+
+ return () => ReactDOM.unmountComponentAtNode(element);
+};
diff --git a/plugins/wazuh-security-policies/public/components/app.tsx b/plugins/wazuh-security-policies/public/components/app.tsx
new file mode 100644
index 0000000000..a0f409f9cc
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/app.tsx
@@ -0,0 +1,111 @@
+import React, { useState, useEffect } from 'react';
+import { I18nProvider } from '@osd/i18n/react';
+import {
+ EuiPage,
+ EuiPageBody,
+ EuiSideNav,
+ EuiPageSideBar,
+ EuiPanel,
+} from '@elastic/eui';
+import { Router, Route, Switch, Redirect, useParams } from 'react-router-dom';
+import { getCore, getHistory } from '../plugin-services';
+import { views } from './common/views';
+import '../components/common/common.scss';
+
+export const WazuhSecurityPoliciesApp = () => {
+ const history = getHistory();
+ const [currentTab, setCurrentTab] = useState('');
+ const [renderMenu, setRenderMenu] = useState(true);
+ const [isSideNavOpenOnMobile, setIsSideNavOpenOnMobile] = useState(false);
+
+ const toggleOpenOnMobile = () => {
+ setIsSideNavOpenOnMobile(!isSideNavOpenOnMobile);
+ };
+
+ useEffect(() => {
+ setCurrentTab(history.location.pathname);
+ }, [history.location.pathname]);
+
+ const sideNav = [
+ {
+ name: 'Ruleset',
+ id: 'wazuhRuleset',
+ items: views
+ .filter(view => view.renderOnMenu)
+ .map(item => ({
+ id: item.id,
+ name: item.name,
+ onClick: () => {
+ history.push(`${item.path}`);
+ setCurrentTab(item.id);
+ },
+ isSelected:
+ item.id === currentTab ||
+ history.location.pathname === `/${item.id}`,
+ })),
+ },
+ ];
+
+ // Render the application DOM.
+ // Note that `navigation.ui.TopNavMenu` is a stateful component exported on the `navigation` plugin's start contract.
+ return (
+
+
+ <>
+
+ {renderMenu && (
+
+ toggleOpenOnMobile()}
+ isOpenOnMobile={isSideNavOpenOnMobile}
+ aria-label='Ruleset'
+ items={sideNav}
+ />
+
+ )}
+
+
+
+
+ {views.map(view => [
+ {
+ const { id } = useParams() || null;
+
+ if (id) {
+ getCore().chrome.setBreadcrumbs(
+ view.breadcrumb(decodeURIComponent(id)),
+ );
+ } else {
+ getCore().chrome.setBreadcrumbs(view.breadcrumb());
+ }
+
+ if (view.renderMenu) {
+ setRenderMenu(true);
+ } else {
+ setRenderMenu(false);
+ }
+
+ return view.render();
+ }}
+ />,
+ ])}
+
+
+
+
+
+ >
+
+
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/common.scss b/plugins/wazuh-security-policies/public/components/common/common.scss
new file mode 100644
index 0000000000..0b4f8c37fe
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/common.scss
@@ -0,0 +1,12 @@
+.wz-mtb-10 {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
+.wz-mr-10 {
+ margin-right: '10px';
+}
+
+.wz-capitalize {
+ text-transform: capitalize;
+}
diff --git a/plugins/wazuh-security-policies/public/components/common/components/last-update-content-manager-text.tsx.tsx b/plugins/wazuh-security-policies/public/components/common/components/last-update-content-manager-text.tsx.tsx
new file mode 100644
index 0000000000..44733ff087
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/components/last-update-content-manager-text.tsx.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { EuiLink } from '@elastic/eui';
+
+export const LastUpdateContentManagerText = (lastUpdate: {
+ lastUpdateDate: string;
+ status: string;
+}) => (
+ <>
+ Last update of the content manager was {lastUpdate.lastUpdateDate} (
+ {lastUpdate.status}).{' '}
+
+ Learn more
+
+ >
+);
diff --git a/plugins/wazuh-security-policies/public/components/common/components/popover.tsx b/plugins/wazuh-security-policies/public/components/common/components/popover.tsx
new file mode 100644
index 0000000000..d9148c44c4
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/components/popover.tsx
@@ -0,0 +1,35 @@
+import React, { useState } from 'react';
+import { EuiButtonIcon, EuiPopover } from '@elastic/eui';
+
+interface PopoverIconButtonProps {
+ children?: React.ReactNode;
+ styles?: React.CSSProperties;
+ color?: string;
+ icon?: string;
+}
+
+export const PopoverIconButton = (props: PopoverIconButtonProps) => {
+ const { children, styles, color = 'text', icon = 'boxesVertical' } = props;
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+ const onButtonClick = () => setIsPopoverOpen(isPopoverOpen => !isPopoverOpen);
+ const closePopover = () => setIsPopoverOpen(false);
+
+ return (
+
+ }
+ isOpen={isPopoverOpen}
+ closePopover={closePopover}
+ >
+ {children}
+
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/components/render-steps.scss b/plugins/wazuh-security-policies/public/components/common/components/render-steps.scss
new file mode 100644
index 0000000000..2a091c664a
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/components/render-steps.scss
@@ -0,0 +1,3 @@
+.multiple-panels-step:not(:last-child) {
+ margin-bottom: 10px;
+}
diff --git a/plugins/wazuh-security-policies/public/components/common/components/render-steps.tsx b/plugins/wazuh-security-policies/public/components/common/components/render-steps.tsx
new file mode 100644
index 0000000000..1cb6382980
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/components/render-steps.tsx
@@ -0,0 +1,199 @@
+import React, { useState } from 'react';
+import {
+ EuiPanel,
+ EuiAccordion,
+ EuiHorizontalRule,
+ EuiForm,
+ EuiButton,
+ EuiButtonEmpty,
+} from '@elastic/eui';
+import { cloneDeep } from 'lodash';
+import { capitalizeFirstLetter } from '../../utils/capitalize-first-letter';
+import { renderInputs } from '../../utils/inputs/render-inputs';
+import { STEPS } from '../constants';
+import './render-steps.scss';
+import { isEditable } from '../../utils/is-editable';
+import { metadataInitialValues } from '../../rules/schemas/metadata.schema';
+import { RenderCheckStep } from './steps/render-check-step';
+import { RenderNormalizeStep } from './steps/render-normalize-step';
+import { RenderParseStep } from './steps/render-parse-step';
+import { PopoverIconButton } from './popover';
+
+interface StepsProps {
+ step: {
+ key: string;
+ value: any;
+ handleSetItem: (props: { key: string; newValue: any }) => void;
+ keyValue?: string;
+ };
+}
+
+export const RenderStepPanel = ({ step }: StepsProps) => {
+ const editable = isEditable();
+ const [onYaml, setOnYaml] = useState(false);
+ let panelToRender: React.ReactNode;
+
+ const renderCardTitle = (stepName: string, item: any) => {
+ switch (true) {
+ case stepName === STEPS.metadata: {
+ return `${capitalizeFirstLetter(stepName)} of ${item.value.title}, from ${item.value.module}`;
+ }
+
+ case stepName === STEPS.check: {
+ panelToRender = ;
+
+ if (typeof item.value === 'string') {
+ return `${capitalizeFirstLetter(stepName)}: ${item.value}`;
+ }
+
+ return `${capitalizeFirstLetter(stepName)} fields: `;
+ // ${item.value.map((obj: any) => Object.keys(obj)[0]).join(', ')}`;
+ }
+
+ case stepName.startsWith(STEPS.parse): {
+ panelToRender = ;
+
+ if (!stepName.includes('|')) {
+ return 'Parse';
+ }
+
+ return stepName.split('|')[1];
+ }
+
+ case stepName === STEPS.normalize: {
+ // Item is the only step in this case as you can have several normalize steps.
+ panelToRender = ;
+
+ return `${capitalizeFirstLetter(stepName)} fields:
+ ${Object.keys(item).join(', ')}`;
+ }
+
+ case stepName === STEPS.allow: {
+ return capitalizeFirstLetter(stepName);
+ }
+
+ case stepName === STEPS.output: {
+ return capitalizeFirstLetter(stepName);
+ }
+
+ case stepName === STEPS.definitions: {
+ return capitalizeFirstLetter(stepName);
+ }
+
+ default: {
+ return capitalizeFirstLetter(stepName);
+ }
+ }
+ };
+
+ const stepsDiferentRender = [
+ STEPS.check,
+ STEPS.parse,
+ STEPS.normalize,
+ STEPS.definitions,
+ ];
+
+ if (step.key === STEPS.normalize) {
+ return (
+ <>
+ {step.value.map((item, index) => (
+
+
+
+
+ {editable
+ ? panelToRender
+ : renderInputs({
+ key: step.key,
+ value: item,
+ handleSetItem: step.handleSetItem,
+ keyValue: step.keyValue ?? '',
+ })}
+
+
+
+ ))}
+
+ step.handleSetItem({ key: step.key, newValue: [...step.value, {}] })
+ }
+ >
+ Add new
+
+ >
+ );
+ }
+
+ const buttonsPopover = [
+ {
+ id: `editOnFormOrYAMLStep-${step.key}`,
+ label: onYaml ? 'Edit on form' : 'Edit on YAML',
+ color: 'text',
+ onClick: () => setOnYaml(!onYaml),
+ },
+ {
+ id: `duplicateItem-${step.key}`,
+ label: `Duplicate ${step.key}`,
+ color: 'text',
+ onClick: () => {},
+ },
+ {
+ id: `clear-${step.key}`,
+ label: 'Clear',
+ color: 'text',
+ onClick: () => {
+ step.handleSetItem({
+ newValue: cloneDeep(metadataInitialValues[step.key]),
+ key: step.key,
+ });
+ },
+ },
+ ];
+ const popover = (
+
+
+ {buttonsPopover.map((button, index) => (
+
+
+ {button.label}
+
+ {index < buttonsPopover.length - 1 && (
+
+ )}
+
+ ))}
+
+
+ );
+
+ return (
+
+
+
+
+
+ {editable && stepsDiferentRender.includes(step.key)
+ ? panelToRender
+ : renderInputs(step)}
+
+
+
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/components/searchbar.tsx b/plugins/wazuh-security-policies/public/components/common/components/searchbar.tsx
new file mode 100644
index 0000000000..7b5f858290
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/components/searchbar.tsx
@@ -0,0 +1,58 @@
+import React, { useState } from 'react';
+import {
+ EuiCallOut,
+ EuiSearchBar,
+ EuiSearchBarProps,
+ Query,
+} from '@elastic/eui';
+
+const initialQuery = EuiSearchBar.Query.MATCH_ALL;
+
+export const SearchBar = (props: EuiSearchBarProps) => {
+ const { schema, filters, setQuery } = props;
+ const [error, setError] = useState(null);
+
+ const onChange = ({ query, error }: { query: Query; error: Error }) => {
+ if (error) {
+ setError(error);
+ } else {
+ setError(null);
+ setQuery(query);
+ }
+ };
+
+ const renderError = () => {
+ if (!error) {
+ return;
+ }
+
+ return (
+ <>
+
+ >
+ );
+ };
+
+ return (
+ <>
+
+
+
+ {renderError()}
+ >
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/components/steps/render-check-step.tsx b/plugins/wazuh-security-policies/public/components/common/components/steps/render-check-step.tsx
new file mode 100644
index 0000000000..32f3fd6857
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/components/steps/render-check-step.tsx
@@ -0,0 +1,81 @@
+import React, { useState, useRef } from 'react';
+import { EuiRadioGroup, EuiButton } from '@elastic/eui';
+import { inputString } from '../../../utils/inputs/string-inputs';
+import { TableForm } from '../table-form';
+
+interface RenderCheckStepProps {
+ step: {
+ key: string;
+ value: any;
+ handleSetItem: (props: { key: string; newValue: any }) => void;
+ };
+}
+
+export const RenderCheckStep = (props: RenderCheckStepProps) => {
+ const { step } = props;
+ const instanceId = useRef(
+ `${step.key}-${Math.random().toString(36).slice(2, 11)}`,
+ );
+ const [isString, setIsString] = useState(
+ typeof step.value === 'string' ? 'string' : 'array',
+ );
+ const [valueString, setValueString] = useState(
+ typeof step.value === 'string' ? step.value : '',
+ );
+
+ const handleStringItem = ({ newValue }: { newValue: string }) => {
+ setValueString(newValue);
+ };
+
+ const handleSaveButton = () => {
+ step.handleSetItem({
+ key: step.key,
+ newValue: valueString,
+ });
+ };
+
+ return (
+ <>
+ {
+ setIsString(id.split('-')[0]);
+ }}
+ name={`radio-group-${instanceId.current}`}
+ legend={{
+ children: One or more,
+ }}
+ />
+ {isString === 'string' && (
+ <>
+ {inputString(
+ { ...step, value: valueString, handleSetItem: handleStringItem },
+ true,
+ )}
+ {
+ handleSaveButton();
+ }}
+ disabled={valueString === ''}
+ >
+ Save
+
+ >
+ )}
+ {isString === 'array' && (
+
+ )}
+ >
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/components/steps/render-normalize-step.tsx b/plugins/wazuh-security-policies/public/components/common/components/steps/render-normalize-step.tsx
new file mode 100644
index 0000000000..aa1e8b901f
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/components/steps/render-normalize-step.tsx
@@ -0,0 +1,126 @@
+import React, { useState } from 'react';
+import {
+ EuiButton,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiSelect,
+ EuiTitle,
+} from '@elastic/eui';
+import { TableForm } from '../table-form';
+import { STEPS } from '../../constants';
+import { capitalizeFirstLetter } from '../../../utils/capitalize-first-letter';
+import { RenderCheckStep } from './render-check-step';
+import { RenderParseStep } from './render-parse-step';
+
+const optionsToSelect = [
+ {
+ text: 'Select item',
+ value: '',
+ },
+ {
+ text: 'Map',
+ value: 'map',
+ },
+ {
+ text: 'Check',
+ value: 'check',
+ },
+ {
+ text: 'Parse',
+ value: 'parse',
+ },
+];
+
+export const RenderNormalizeStep = (props: {
+ step: {
+ key: string;
+ value: any;
+ handleSetItem: (props: { key: string; newValue: any }) => void;
+ };
+}) => {
+ const [itemSelected, setItemSelected] = useState(optionsToSelect[0].text);
+ const [items, setItems] = useState([]);
+ const [optionSelect, setOptionSelect] =
+ useState<{ text: string; value: string }[]>(optionsToSelect);
+
+ const addItem = () => {
+ setItems([...items, itemSelected]);
+ setOptionSelect(
+ optionSelect.filter(option => option.value !== itemSelected),
+ );
+ };
+
+ return (
+ <>
+
+
+ setItemSelected(event.target.value)}
+ />
+
+
+ addItem()}>
+ Add step
+
+
+
+
+ {items?.map((item, index) => {
+ switch (item) {
+ case STEPS.check: {
+ return (
+
+
+ {capitalizeFirstLetter(STEPS.check)}
+
+
+
+ );
+ }
+
+ case STEPS.parse: {
+ return (
+
+
+ {capitalizeFirstLetter(STEPS.parse)}
+
+
+
+ );
+ }
+
+ default: {
+ return (
+
+
+ Map
+
+
+
+ );
+ }
+ }
+ })}
+
+ >
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/components/steps/render-parse-step.tsx b/plugins/wazuh-security-policies/public/components/common/components/steps/render-parse-step.tsx
new file mode 100644
index 0000000000..1e80933f7b
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/components/steps/render-parse-step.tsx
@@ -0,0 +1,68 @@
+import React, { useState } from 'react';
+import { EuiButton } from '@elastic/eui';
+import { isEqual } from 'lodash';
+import { inputString } from '../../../utils/inputs/string-inputs';
+import { inputArray } from '../../../utils/inputs/array-inputs';
+
+export const RenderParseStep = (props: any) => {
+ const { step } = props;
+ const [value, setValue] = useState('');
+ const [eventField, setEventField] = useState('');
+ const [valueArray, setValueArray] = useState(step?.value || []);
+
+ const handleSetValue = ({ newValue }: { newValue: string }) => {
+ setValue(newValue);
+ };
+
+ const restartValue = () => setValue('');
+
+ const handleAddButton = () => {
+ setValueArray([...valueArray, value]);
+ restartValue();
+ };
+
+ const handleSaveButton = () => {
+ step.handleSetItem({
+ key: `${step.key}|${eventField}`,
+ newValue: valueArray,
+ });
+ };
+
+ const handleParseTitle = ({ newValue }: { newValue: string }) => {
+ setEventField(newValue);
+ };
+
+ return (
+ <>
+ {inputString(
+ {
+ ...step,
+ key: 'Field to parse',
+ value: eventField,
+ handleSetItem: handleParseTitle,
+ },
+ true,
+ )}
+ {inputString({ ...step, value, handleSetItem: handleSetValue }, true)}
+ {
+ handleAddButton();
+ }}
+ disabled={value === ''}
+ >
+ Add item
+
+ {inputArray({ ...step, value: valueArray }, true)}
+ {
+ handleSaveButton();
+ }}
+ disabled={valueArray.length === 0 || isEqual(valueArray, step.value)}
+ >
+ Save
+
+ >
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/components/table-form.tsx b/plugins/wazuh-security-policies/public/components/common/components/table-form.tsx
new file mode 100644
index 0000000000..581284aa73
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/components/table-form.tsx
@@ -0,0 +1,86 @@
+import React, { useState } from 'react';
+import { EuiButton } from '@elastic/eui';
+import { inputArray } from '../../utils/inputs/array-inputs';
+import { inputString } from '../../utils/inputs/string-inputs';
+
+interface TableFormProps {
+ parentKey: string;
+ handleSetItem: (props: { key: string; newValue: any }) => void;
+}
+
+export const TableForm = (props: TableFormProps) => {
+ const { parentKey, handleSetItem } = props;
+ const [valueObject, setValueObject] = useState({ field: '', value: '' });
+ const [valueArray, setValueArray] = useState[]>([]);
+
+ const handleObjectItem = ({
+ key,
+ newValue,
+ }: {
+ key: string;
+ newValue: any;
+ }) => {
+ setValueObject({ ...valueObject, [key]: newValue });
+ };
+
+ const restartValue = () => setValueObject({ field: '', value: '' });
+
+ const handleAddButton = () => {
+ setValueArray([...valueArray, { [valueObject.field]: valueObject.value }]);
+ restartValue();
+ };
+
+ const handleSaveButton = () => {
+ handleSetItem({
+ key: parentKey,
+ newValue: valueArray,
+ });
+ };
+
+ return (
+ <>
+ {inputString(
+ {
+ key: 'field',
+ value: valueObject.field,
+ handleSetItem: handleObjectItem,
+ },
+ true,
+ )}
+ {inputString(
+ {
+ key: 'value',
+ value: valueObject.value,
+ handleSetItem: handleObjectItem,
+ },
+ true,
+ )}
+ {
+ handleAddButton();
+ }}
+ disabled={valueObject.field === '' || valueObject.value === ''}
+ >
+ Add item
+
+ {inputArray(
+ {
+ key: parentKey,
+ value: valueArray,
+ handleSetItem: handleSetItem,
+ },
+ true,
+ )}
+ {
+ handleSaveButton();
+ }}
+ disabled={valueArray.length === 0}
+ >
+ Save
+
+ >
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/components/yaml-editor.tsx b/plugins/wazuh-security-policies/public/components/common/components/yaml-editor.tsx
new file mode 100644
index 0000000000..c04d58d93b
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/components/yaml-editor.tsx
@@ -0,0 +1,45 @@
+import React, { useEffect, useState } from 'react';
+import MonacoEditor from 'react-monaco-editor';
+import yaml from 'js-yaml';
+
+interface YAMLEditorProps {
+ data: any;
+ onChange?: (value: string) => void;
+}
+
+export const YAMLEditor: React.FC = ({ data, onChange }) => {
+ const [yamlContent, setYamlContent] = useState('');
+
+ useEffect(() => {
+ if (typeof data === 'string') {
+ return setYamlContent(data);
+ }
+
+ const yamlData = yaml.dump(data, {
+ indent: 2,
+ lineWidth: -1,
+ noRefs: true,
+ });
+
+ setYamlContent(yamlData);
+ }, [data]);
+
+ const handleEditorChange = (value: string) => {
+ setYamlContent(value);
+ onChange?.(value);
+ };
+
+ return (
+
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/constants.ts b/plugins/wazuh-security-policies/public/components/common/constants.ts
new file mode 100644
index 0000000000..19cd1b08ec
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/constants.ts
@@ -0,0 +1,9 @@
+export const STEPS = {
+ metadata: 'metadata',
+ check: 'check',
+ parse: 'parse',
+ normalize: 'normalize',
+ allow: 'allow',
+ output: 'output',
+ definitions: 'definitions',
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/templates/create-template.tsx b/plugins/wazuh-security-policies/public/components/common/templates/create-template.tsx
new file mode 100644
index 0000000000..65276764ab
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/templates/create-template.tsx
@@ -0,0 +1,279 @@
+import React, { useState } from 'react';
+import { useParams } from 'react-router-dom';
+import {
+ EuiPageHeader,
+ EuiFieldText,
+ EuiButtonEmpty,
+ EuiButton,
+ EuiHorizontalRule,
+ EuiSteps,
+ EuiSelect,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiTitle,
+} from '@elastic/eui';
+import { set, cloneDeep } from 'lodash';
+import yaml from 'js-yaml';
+import { PopoverIconButton } from '../components/popover';
+import { getAppUrl } from '../../utils/get-app-url';
+import { capitalizeFirstLetter } from '../../utils/capitalize-first-letter';
+import { metadataInitialValues } from '../../rules/schemas/metadata.schema';
+import { RenderStepPanel } from '../components/render-steps';
+import { YAMLEditor } from '../components/yaml-editor';
+
+const getAvailableOptions = selectedSteps => {
+ const baseOptions = [
+ { value: 'Select step', text: 'Select step' },
+ { value: 'check', text: 'Check' },
+ { value: 'parse', text: 'Parse' },
+ { value: 'normalize', text: 'Normalize' },
+ { value: 'allow', text: 'Allow' },
+ { value: 'outputs', text: 'Outputs' },
+ { value: 'definitions', text: 'Definitions' },
+ ];
+
+ if (
+ selectedSteps.includes('check') ||
+ selectedSteps.includes('parse') ||
+ selectedSteps.includes('normalize')
+ ) {
+ return baseOptions.filter(
+ option => !['allow', 'outputs', ...selectedSteps].includes(option.value),
+ );
+ }
+
+ if (selectedSteps.includes('outputs')) {
+ return baseOptions.filter(
+ option =>
+ !['normalize', 'parse', ...selectedSteps].includes(option.value),
+ );
+ }
+
+ if (selectedSteps.includes('allow')) {
+ return baseOptions.filter(
+ option =>
+ !['check', 'normalize', ...selectedSteps].includes(option.value),
+ );
+ }
+
+ return baseOptions;
+};
+
+export const CreateTemplate = () => {
+ const cloneInitialValues = cloneDeep(metadataInitialValues);
+ const [onYaml, setOnYaml] = useState(false);
+ const [stepsToRender, setstepsToRender] = useState(['metadata']);
+ const [item, setItem] = useState(cloneInitialValues);
+ const [addStep, setAddStep] = useState(
+ getAvailableOptions(stepsToRender)?.[0]?.value,
+ );
+ const view = getAppUrl();
+
+ const handleSetItem = ({
+ newValue,
+ key,
+ }: {
+ newValue: string | boolean | object;
+ key: string;
+ }) => {
+ setItem(prevItem => {
+ const newItem = { ...prevItem };
+
+ set(newItem, key, newValue);
+
+ return newItem;
+ });
+ };
+
+ const buttonsPopover = [
+ {
+ id: 'editOnFormOrYAML',
+ label: onYaml ? 'Edit on form' : 'Edit on YAML',
+ color: 'text',
+ onClick: () => {
+ if (onYaml) {
+ setItem(yaml.load(item));
+ }
+
+ setOnYaml(!onYaml);
+ },
+ },
+ {
+ id: 'enable/disable',
+ label: item?.enable ? 'Disable' : 'Enable',
+ color: item?.enable ? 'danger' : 'primary',
+ onClick: () => {
+ handleSetItem({
+ newValue: !item?.enable,
+ key: 'enable',
+ });
+ },
+ },
+ {
+ id: 'testItem',
+ label: `Test ${view}`,
+ color: 'text',
+ onClick: () => {},
+ },
+ {
+ id: 'setSaveAsDraft',
+ label: useParams()?.id ? 'Save as Draft' : 'Set as draft',
+ color: 'text',
+ onClick: () =>
+ handleSetItem({
+ newValue: 'draft',
+ key: 'status',
+ }),
+ },
+ ];
+ const buttons = [
+
+
+ {buttonsPopover.map((button, index) => (
+
+
+ {button.label}
+
+ {index < buttonsPopover.length - 1 && (
+
+ )}
+
+ ))}
+
+ ,
+
+ console.log(
+ onYaml
+ ? item
+ : Object.fromEntries(
+ Object.entries(item).filter(
+ ([key]) =>
+ [
+ ...stepsToRender.filter(step => step !== 'parse'),
+ 'name',
+ 'status',
+ 'enable',
+ ].includes(key) || key.startsWith('parse|'),
+ ),
+ ),
+ )
+ }
+ >
+ Save
+ ,
+ history.back()}
+ >
+ Cancel
+ ,
+ ];
+
+ const addStepRender = () => {
+ setstepsToRender([...stepsToRender, addStep]);
+ };
+
+ const steps = stepsItems => {
+ const stepsArray = stepsToRender.map(stepName => ({
+ title: capitalizeFirstLetter(stepName),
+ children: (
+
+ ),
+ }));
+ const optionsToSelect = getAvailableOptions(stepsToRender);
+
+ if (optionsToSelect.length > 1) {
+ stepsArray.push({
+ title: 'Add step',
+ children: (
+
+
+ setAddStep(event.target.value)}
+ placeholder='Select next step'
+ />
+
+
+
+ Add step
+
+
+
+ ),
+ });
+ }
+
+ return stepsArray;
+ };
+
+ return (
+ <>
+
+ test
+
+ ) : (
+
+ handleSetItem({
+ newValue: event.target.value,
+ key: 'name',
+ })
+ }
+ />
+ )
+ }
+ bottomBorder={true}
+ alignItems='center'
+ rightSideGroupProps={{
+ alignItems: 'center',
+ }}
+ rightSideItems={buttons}
+ />
+ {onYaml ? (
+ {
+ setItem(value);
+ console.log(yaml.load(value));
+ }}
+ />
+ ) : (
+
+ )}
+ >
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/templates/details-template.scss b/plugins/wazuh-security-policies/public/components/common/templates/details-template.scss
new file mode 100644
index 0000000000..5377dfda66
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/templates/details-template.scss
@@ -0,0 +1,3 @@
+.steps-details {
+ margin-top: 10px;
+}
diff --git a/plugins/wazuh-security-policies/public/components/common/templates/details-template.tsx b/plugins/wazuh-security-policies/public/components/common/templates/details-template.tsx
new file mode 100644
index 0000000000..3e2871bd84
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/templates/details-template.tsx
@@ -0,0 +1,108 @@
+import React from 'react';
+import {
+ EuiPageHeader,
+ EuiButton,
+ EuiButtonEmpty,
+ EuiText,
+ EuiButtonIcon,
+ EuiSteps,
+} from '@elastic/eui';
+import { useParams } from 'react-router-dom';
+import { decoder } from '../../rules/mock-data-rules';
+import { capitalizeFirstLetter } from '../../utils/capitalize-first-letter';
+import { renderStepPanel } from '../components/render-steps';
+import { STEPS } from '../constants';
+import './details-template.scss';
+
+export const DetailsTemplate = () => {
+ // const { pathname } = useLocation();
+ // const view = pathname.split('/')[1];
+ const { id: name } = useParams();
+ const item = decoder.find(item => item.name === decodeURIComponent(name));
+ const title = (
+
+ {item?.name}
+ {}}
+ iconType='pencil'
+ aria-label='Edit'
+ />
+
+ );
+ const buttons = [
+
+ Edit
+ ,
+ {}}
+ >
+ Test decoder
+ ,
+ {}}
+ className='wz-capitalize'
+ >
+ {item?.status}
+ ,
+ {}}
+ >
+ View in YAML
+ ,
+ ];
+
+ const renderTitleStep = (stepName: string) => {
+ let title = stepName;
+
+ if (stepName.startsWith(STEPS.parse)) {
+ title = stepName.split('|')[0];
+ }
+
+ return capitalizeFirstLetter(title);
+ };
+
+ const step = (item: any) => {
+ const removeEntries = new Set(['id', 'name', 'provider', 'status']);
+ const arraySteps = Object.entries(item)
+ .filter(([key]) => !removeEntries.has(key))
+ .map(([key, value]) => ({
+ key,
+ value,
+ }));
+ const steps = arraySteps.map(step => ({
+ title: renderTitleStep(step.key),
+ children: renderStepPanel(step),
+ }));
+
+ return steps;
+ };
+
+ return (
+ <>
+
+
+ >
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/templates/no-results.tsx b/plugins/wazuh-security-policies/public/components/common/templates/no-results.tsx
new file mode 100644
index 0000000000..8e8f5dbce7
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/templates/no-results.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import { EuiEmptyPrompt } from '@elastic/eui';
+
+export const NoResultsData = (props: { query: { text: string } }) => {
+ const { query } = props;
+
+ return (
+ No results found}
+ body={
+ <>
+
+ No results found for the search with the value '{query.text}
+ '.
+
+ >
+ }
+ />
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/templates/overview-template.tsx b/plugins/wazuh-security-policies/public/components/common/templates/overview-template.tsx
new file mode 100644
index 0000000000..1c501ad082
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/templates/overview-template.tsx
@@ -0,0 +1,275 @@
+import React, { useEffect, useState } from 'react';
+import {
+ EuiPanel,
+ EuiButton,
+ EuiText,
+ EuiBasicTable,
+ EuiHealth,
+ EuiPageHeader,
+ EuiLink,
+} from '@elastic/eui';
+import { decoder } from '../../rules/mock-data-rules';
+import { getHistory } from '../../../plugin-services';
+import { getAppUrl } from '../../utils/get-app-url';
+import { LastUpdateContentManagerText } from '../components/last-update-content-manager-text.tsx';
+import { SearchBar } from '../components/searchbar';
+import { NoResultsData } from './no-results';
+
+export const OverviewTemplate = () => {
+ const view = getAppUrl();
+ const history = getHistory();
+ const [pageIndex, setPageIndex] = useState(0);
+ const [pageSize, setPageSize] = useState(5);
+ const [decoderList, setDecoderList] = useState(decoder);
+ const [query, setQuery] = useState({ text: '' });
+ // Header start
+ const titleHeader = {view};
+ const descriptionHeader = LastUpdateContentManagerText({
+ status: 'Updated',
+ lastUpdateDate: '31/01/2025',
+ });
+
+ const goCreateView = () => {
+ history.push(`/${view}/create`);
+ };
+
+ const rightSideItems = [
+
+ Create
+ ,
+ ];
+ // Header end
+ // Searchbar start
+ const isActiveOption = [
+ { value: 'enable', name: 'Enable' },
+ { value: 'disable', name: 'Disable' },
+ { value: 'draft', name: 'Draft' },
+ ];
+ const integrationOption: string[] = [];
+ const nativeOrCustomOption = [
+ { value: 'native', name: 'Native' },
+ { value: 'custom', name: 'Custom' },
+ ];
+
+ for (const item of decoderList) {
+ if (!integrationOption[item.metadata.module]) {
+ integrationOption.push(item.metadata.module);
+ }
+ }
+
+ const filters = [
+ {
+ type: 'field_value_toggle_group',
+ field: 'status',
+ multiSelect: 'or',
+ items: isActiveOption,
+ },
+ {
+ type: 'field_value_toggle_group',
+ field: 'provider',
+ name: 'Provider',
+ multiSelect: 'or',
+ items: nativeOrCustomOption,
+ },
+ {
+ type: 'field_value_selection',
+ field: 'metadata.module',
+ name: 'Integrations',
+ multiSelect: 'and',
+ cache: 10000, // will cache the loaded tags for 10 sec
+ options: integrationOption.map(integration => ({
+ value: integration,
+ view: {integration},
+ })),
+ },
+ ];
+ const schema = {
+ strict: true,
+ fields: {
+ status: {
+ type: 'string',
+ },
+ 'metadata.module': {
+ type: 'string',
+ },
+ provider: {
+ type: 'string',
+ },
+ },
+ };
+ // Search bar end
+ // Table start
+
+ useEffect(() => {
+ if (query.text === '') {
+ setDecoderList(decoder);
+
+ return;
+ }
+
+ const decoderFilter = decoderList.filter(decoder =>
+ Object.values(decoder).includes('enable'),
+ );
+
+ setDecoderList(decoderFilter);
+ }, [query]);
+
+ const renderStatus = (status: string) => {
+ let color: string;
+ let label: string;
+
+ switch (status) {
+ case 'enable': {
+ color = 'success';
+ label = 'Enable';
+ break;
+ }
+
+ case 'disable': {
+ color = 'danger';
+ label = 'Disable';
+ break;
+ }
+
+ case 'draft': {
+ color = 'warning';
+ label = 'Draft';
+ break;
+ }
+
+ default: {
+ color = 'text';
+ label = '-141';
+ break;
+ }
+ }
+
+ return {label};
+ };
+
+ const handleNavigation = (path: string) => {
+ history.push(path);
+ };
+
+ const getRowProps = (item: string) =>
+ handleNavigation(`/${view}/${encodeURIComponent(item)}`);
+ const columns = [
+ {
+ field: 'name',
+ name: 'Name',
+ sortable: true,
+ truncateText: true,
+ render: (item: string) => (
+ getRowProps(item)} className='wz-capitalize'>
+ {item}
+
+ ),
+ },
+ {
+ field: 'metadata.module',
+ name: 'Integration',
+ sortable: true,
+ truncateText: true,
+ },
+ {
+ field: 'metadata.description',
+ name: 'Description',
+ truncateText: true,
+ },
+ {
+ field: 'provider',
+ name: 'Provider',
+ sortable: true,
+ truncateText: true,
+ render: (item: string) => (
+ {item}
+ ),
+ },
+ {
+ field: 'status',
+ name: 'Status',
+ dataType: 'boolean',
+ render: (status: string) => renderStatus(status),
+ sortable: true,
+ mobileOptions: {
+ show: false,
+ },
+ },
+ {
+ name: 'Actions',
+ actions: [
+ {
+ name: 'Edit',
+ isPrimary: true,
+ description: 'Edit this user',
+ icon: 'pencil',
+ type: 'icon',
+ onClick: () => {},
+ 'data-test-subj': 'action-edit',
+ },
+ {
+ name: 'Remove',
+ description: 'Remove this element',
+ isPrimary: true,
+ icon: 'trash',
+ color: 'danger',
+ type: 'icon',
+ onClick: () => {},
+ },
+ {
+ name: 'Clone',
+ description: 'Clone this user',
+ icon: 'copy',
+ onClick: () => {},
+ },
+ {
+ name: 'Share',
+ description: 'Share this user',
+ icon: 'share',
+ type: 'icon',
+ onClick: () => {},
+ 'data-test-subj': 'action-share',
+ },
+ ],
+ },
+ ];
+
+ const onTableChange = ({
+ page,
+ }: {
+ page: { index: number; size: number };
+ }) => {
+ const { index: pageIndex, size: pageSize } = page;
+
+ setPageIndex(pageIndex);
+ setPageSize(pageSize);
+ };
+
+ const pagination = {
+ pageIndex: pageIndex,
+ pageSize: pageSize,
+ totalItemCount: decoderList.length,
+ pageSizeOptions: [3, 5, 8],
+ };
+
+ // Table end
+
+ return (
+
+
+
+
+ {decoder.length <= 0 && }
+
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/common/views.tsx b/plugins/wazuh-security-policies/public/components/common/views.tsx
new file mode 100644
index 0000000000..7e4eafb38d
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/common/views.tsx
@@ -0,0 +1,312 @@
+import React from 'react';
+import { i18n } from '@osd/i18n';
+import { FormattedMessage } from '@osd/i18n/react';
+import { IntegrationOverview } from '../integretions/overview';
+import { IntegrationView } from '../integretions/integration-details';
+import { getCore } from '../../plugin-services';
+import { OverviewTemplate } from './templates/overview-template';
+import { DetailsTemplate } from './templates/details-template';
+import { CreateTemplate } from './templates/create-template';
+
+interface ViewInterface {
+ name: string;
+ id: string;
+ path: string;
+ renderOnMenu: boolean;
+ renderMenu: boolean;
+ render: () => React.ReactNode;
+ breadcrumb: (
+ name?: string,
+ ) => { text: string | React.ReactNode; className?: string }[];
+}
+
+export const views: ViewInterface[] = [
+ {
+ name: i18n.translate('wz-security-policies-integrations', {
+ defaultMessage: 'Integrations',
+ }),
+ id: 'integrations',
+ path: '/integrations',
+ renderOnMenu: true,
+ renderMenu: true,
+ render: () => ,
+ breadcrumb: () => [
+ {
+ className: 'osdBreadcrumbs',
+ text: (
+
+ ),
+ },
+ ],
+ },
+ {
+ name: i18n.translate('wz-security-policies-integration-details', {
+ defaultMessage: 'Integrations details',
+ }),
+ id: 'integrationsDetails',
+ path: '/integrations/:id',
+ renderOnMenu: false,
+ renderMenu: true,
+ render: () => ,
+ breadcrumb: (name?: string) => [
+ {
+ text: (
+ view.id === 'integrations')?.name
+ }
+ />
+ ),
+ href: getCore().application.getUrlForApp('wazuhSecurityPolicies', {
+ path: `#/${views.find(view => view.id === 'integrations')?.path}`,
+ }),
+ },
+ {
+ className: 'osdBreadcrumbs',
+ text: decodeURIComponent(name || ''),
+ },
+ ],
+ },
+ {
+ name: i18n.translate('wz-security-policies-rules', {
+ defaultMessage: 'Rules',
+ }),
+ id: 'rules',
+ path: '/rules',
+ renderOnMenu: true,
+ renderMenu: true,
+ render: () => ,
+ breadcrumb: () => [
+ {
+ className: 'osdBreadcrumbs',
+ text: (
+
+ ),
+ },
+ ],
+ },
+ {
+ name: i18n.translate('wz-security-policies-rules-create', {
+ defaultMessage: 'Rules create',
+ }),
+ id: 'rulesCreate',
+ path: '/rules/create',
+ renderOnMenu: false,
+ renderMenu: false,
+ render: () => ,
+ breadcrumb: () => [
+ {
+ className: 'osdBreadcrumbs',
+ text: (
+
+ ),
+ href: getCore().application.getUrlForApp('wazuhSecurityPolicies', {
+ path: `#/${views.find(view => view.id === 'rules')?.path}`,
+ }),
+ },
+ {
+ text: (
+
+ ),
+ },
+ ],
+ },
+ {
+ name: i18n.translate('wz-security-policies-rule-details', {
+ defaultMessage: 'Rule details',
+ }),
+ id: 'rulesDetails',
+ path: '/rules/:id',
+ renderOnMenu: false,
+ renderMenu: false,
+ render: () => ,
+ breadcrumb: (name?: string) => [
+ {
+ text: (
+ view.id === 'rules')?.name}
+ />
+ ),
+ href: getCore().application.getUrlForApp('wazuhSecurityPolicies', {
+ path: `#/${views.find(view => view.id === 'rules')?.path}`,
+ }),
+ },
+ {
+ className: 'osdBreadcrumbs',
+ text: decodeURIComponent(name || ''),
+ },
+ ],
+ },
+ {
+ name: i18n.translate('wz-security-policies-decoders', {
+ defaultMessage: 'Decoders',
+ }),
+ id: 'decoders',
+ path: '/decoders',
+ renderOnMenu: true,
+ renderMenu: true,
+ render: () => ,
+ breadcrumb: () => [
+ {
+ className: 'osdBreadcrumbs',
+ text: (
+
+ ),
+ },
+ ],
+ },
+ {
+ name: i18n.translate('wz-security-policies-decoders-details', {
+ defaultMessage: 'Create decoder',
+ }),
+ id: 'decodersCreate',
+ path: '/decoders/create',
+ renderOnMenu: false,
+ renderMenu: false,
+ render: () => ,
+ breadcrumb: () => [
+ {
+ text: (
+ view.id === 'decoders')?.name}
+ />
+ ),
+ href: getCore().application.getUrlForApp('wazuhSecurityPolicies', {
+ path: `#/${views.find(view => view.id === 'decoders')?.path}`,
+ }),
+ },
+ {
+ text: (
+
+ ),
+ },
+ ],
+ },
+ {
+ name: i18n.translate('wz-security-policies-decoders-details', {
+ defaultMessage: 'Decoders details',
+ }),
+ id: 'decodersDetails',
+ path: '/decoders/:id',
+ renderOnMenu: false,
+ renderMenu: false,
+ render: () => ,
+ breadcrumb: (name?: string) => [
+ {
+ text: (
+ view.id === 'decoders')?.name}
+ />
+ ),
+ href: getCore().application.getUrlForApp('wazuhSecurityPolicies', {
+ path: `#/${views.find(view => view.id === 'decoders')?.path}`,
+ }),
+ },
+ {
+ className: 'osdBreadcrumbs',
+ text: decodeURIComponent(name || ''),
+ },
+ ],
+ },
+ {
+ name: i18n.translate('wz-security-policies-kvdb', {
+ defaultMessage: 'KVDB',
+ }),
+ id: 'kvdb',
+ path: '/kvdb',
+ renderOnMenu: true,
+ renderMenu: true,
+ render: () => ,
+ breadcrumb: () => [
+ {
+ className: 'osdBreadcrumbs',
+ text: (
+
+ ),
+ },
+ ],
+ },
+ {
+ name: i18n.translate('wz-security-policies-decoders-details', {
+ defaultMessage: 'Create KVDB',
+ }),
+ id: 'kvdbCreate',
+ path: '/kvdb/create',
+ renderOnMenu: false,
+ renderMenu: false,
+ render: () => ,
+ breadcrumb: () => [
+ {
+ text: (
+ view.id === 'kvdb')?.name}
+ />
+ ),
+ href: getCore().application.getUrlForApp('wazuhSecurityPolicies', {
+ path: `#/${views.find(view => view.id === 'decoders')?.path}`,
+ }),
+ },
+ {
+ text: (
+
+ ),
+ },
+ ],
+ },
+ {
+ name: i18n.translate('wz-security-policies-kvdb-details', {
+ defaultMessage: 'KVDB details',
+ }),
+ id: 'kvdbDetails',
+ path: '/kvdb/:id',
+ renderOnMenu: false,
+ renderMenu: false,
+ render: () => ,
+ breadcrumb: (name?: string) => [
+ {
+ text: (
+ view.id === 'kvdb')?.name}
+ />
+ ),
+ href: getCore().application.getUrlForApp('wazuhSecurityPolicies', {
+ path: `#/${views.find(view => view.id === 'kvdb')?.path}`,
+ }),
+ },
+ {
+ className: 'osdBreadcrumbs',
+ text: decodeURIComponent(name || ''),
+ },
+ ],
+ },
+];
diff --git a/plugins/wazuh-security-policies/public/components/integretions/components/card-integration.tsx b/plugins/wazuh-security-policies/public/components/integretions/components/card-integration.tsx
new file mode 100644
index 0000000000..7935f91448
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/integretions/components/card-integration.tsx
@@ -0,0 +1,79 @@
+import React from 'react';
+import {
+ EuiCard,
+ EuiIcon,
+ EuiButtonEmpty,
+ EuiHorizontalRule,
+} from '@elastic/eui';
+import { PopoverIconButton } from '../../common/components/popover';
+import { getHistory } from '../../../plugin-services';
+
+interface CardIntegrationProps {
+ image: string;
+ title: string;
+ description: string;
+ isEnable: boolean;
+}
+
+export const CardIntegration = (props: CardIntegrationProps) => {
+ const history = getHistory();
+ const { image = 'logoOpenSearch', title, description, isEnable } = props;
+ const buttonIntegrations = [
+ {
+ id: 'goToDecoder',
+ label: 'Go to Decoder',
+ color: 'text',
+ },
+ {
+ id: 'goToRules',
+ label: 'Go to Rules',
+ color: 'text',
+ },
+ {
+ id: 'goToKVDB',
+ label: 'Go to KVDB',
+ color: 'text',
+ },
+ {
+ id: 'enable/disable',
+ label: isEnable ? 'Disable' : 'Enable',
+ color: isEnable ? 'danger' : 'primary',
+ },
+ ];
+
+ const handleNavigation = (path: string) => {
+ history.push(path);
+ };
+
+ return (
+ <>
+ }
+ paddingSize='m'
+ onClick={() => handleNavigation(`/integrations/${title}`)}
+ />
+
+
+ {buttonIntegrations.map((button, index) => (
+
+
+ {button.label}
+
+ {index < buttonIntegrations.length - 1 && (
+
+ )}
+
+ ))}
+
+
+ >
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/integretions/components/integration-description.tsx b/plugins/wazuh-security-policies/public/components/integretions/components/integration-description.tsx
new file mode 100644
index 0000000000..61e9eb256b
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/integretions/components/integration-description.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import {
+ EuiDescriptionListTitle,
+ EuiDescriptionListDescription,
+} from '@elastic/eui';
+
+interface IntegrationDescriptionProps {
+ keyValue: string;
+ value: any;
+}
+
+export const IntegrationDescription = (props: IntegrationDescriptionProps) => {
+ const { keyValue, value } = props;
+ const renderTitleDescription = (key: string, value: string) => (
+
+ {key}
+
+ {value}
+
+
+ );
+
+ const renderObjectValue = (keyObject: string, valueObject: object) => {
+ const subList = Object.entries(valueObject).map(([key, value]) => ({
+ key: `${keyObject}.${key}`,
+ value: value,
+ }));
+
+ return subList.map(item => renderTitleDescription(item.key, item.value));
+ };
+
+ const renderValue = (key: string, value: any) => {
+ if (Array.isArray(value)) {
+ return renderTitleDescription(key, value.join(', '));
+ } else if (typeof value === 'object') {
+ return renderObjectValue(key, value);
+ } else if (typeof value === 'boolean') {
+ return renderTitleDescription(key, value ? 'Enable' : 'Disable');
+ } else {
+ return renderTitleDescription(key, value);
+ }
+ };
+
+ return renderValue(keyValue, value);
+};
diff --git a/plugins/wazuh-security-policies/public/components/integretions/integration-details.tsx b/plugins/wazuh-security-policies/public/components/integretions/integration-details.tsx
new file mode 100644
index 0000000000..9cc1cb5ba2
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/integretions/integration-details.tsx
@@ -0,0 +1,131 @@
+import React, { useEffect, useState } from 'react';
+import {
+ EuiHealth,
+ EuiIcon,
+ EuiButton,
+ EuiDescriptionList,
+ EuiPanel,
+ EuiPageHeader,
+} from '@elastic/eui';
+import { useParams } from 'react-router-dom';
+import { LastUpdateContentManagerText } from '../common/components/last-update-content-manager-text.tsx';
+import { integrations } from './mock-data-integrations';
+import './integrations.scss';
+import { IntegrationDescription } from './components/integration-description';
+
+export const IntegrationView = () => {
+ const id = useParams().id;
+ const [integrationData, setIntegrationData] = useState<{
+ image: string;
+ title: string;
+ description: string;
+ isEnable: boolean;
+ lastUpdate: {
+ lastUpdateDate: string;
+ status: string;
+ };
+ versions: string[];
+ compatibility: string;
+ author: {
+ name: string;
+ date: string;
+ };
+ references: string[];
+ module: string;
+ }>({
+ image: '',
+ title: '',
+ module: '',
+ description: '',
+ isEnable: false,
+ lastUpdate: { lastUpdateDate: '', status: '' },
+ versions: [],
+ compatibility: '',
+ author: {
+ name: '',
+ date: '',
+ },
+ references: [],
+ });
+
+ useEffect(() => {
+ const integration = integrations.find(
+ integration => integration.title === id,
+ );
+
+ if (integration) {
+ setIntegrationData(integration);
+ }
+ }, [id]);
+
+ // Header page start
+
+ const headerTitle = (
+
+
+ {integrationData?.title}
+
+ {integrationData.isEnable ? 'Enabled' : 'Disabled'}
+
+
+ );
+ const descriptionHeader = LastUpdateContentManagerText(
+ integrationData.lastUpdate,
+ );
+
+ const toggleEnableOrDisable = () => {
+ setIntegrationData({
+ ...integrationData,
+ isEnable: !integrationData.isEnable,
+ });
+ };
+
+ const rightSideItems = [
+
+ {integrationData.isEnable ? 'Disable' : 'Enable'}
+ ,
+ ];
+ // Header page end
+ // Description list start
+ const list = Object.entries(integrationData).map(([key, value]) => ({
+ key,
+ value,
+ }));
+
+ // Description list end
+
+ return (
+ <>
+
+
+
+ {list
+ .filter(item => item.key !== 'image')
+ .map(item => (
+
+ ))}
+
+
+ >
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/integretions/integrations.scss b/plugins/wazuh-security-policies/public/components/integretions/integrations.scss
new file mode 100644
index 0000000000..585394ae7c
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/integretions/integrations.scss
@@ -0,0 +1,14 @@
+.integration-title-header {
+ display: flex;
+ align-items: center;
+}
+
+.integration-icon-header {
+ margin-right: 10px;
+}
+
+.data-integration-card {
+ display: flex;
+ margin: 10px;
+ flex-wrap: wrap;
+}
diff --git a/plugins/wazuh-security-policies/public/components/integretions/mock-data-integrations.tsx b/plugins/wazuh-security-policies/public/components/integretions/mock-data-integrations.tsx
new file mode 100644
index 0000000000..602465befd
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/integretions/mock-data-integrations.tsx
@@ -0,0 +1,214 @@
+export const integrations = [
+ {
+ image: 'advancedSettingsApp',
+ module: 'syslog',
+ title: 'Linux Doas Conf File Creation',
+ description:
+ 'Detects the creation of doas.conf file in linux host platform',
+ isEnable: true,
+ versions: ['1.3.1', '1.3.2', '1.3.3'],
+ lastUpdate: {
+ lastUpdateDate: '12/18/2024',
+ status: 'Success',
+ },
+ compatibility: 'This integration was tested on Ubuntu 20.04',
+ author: {
+ name: 'Wazuh, Inc.',
+ date: '2024/09/09',
+ },
+ references: [
+ 'https://research.splunk.com/endpoint/linux_doas_conf_file_creation/',
+ 'https://www.makeuseof.com/how-to-install-and-use-doas/',
+ 'https://github.com/SigmaHQ/sigma/blob/master/rules/linux/file_event/file_event_lnx_doas_conf_creation.yml',
+ ],
+ },
+ {
+ image: 'grokApp',
+ title: 'Integration 2',
+ description: 'Description for integration 2',
+ isEnable: false,
+ lastUpdate: {
+ lastUpdateDate: '12/18/2024',
+ status: 'Success',
+ },
+ versions: ['1.3.1', '1.3.2', '1.3.3'],
+ compatibility: 'This integration was tested on Ubuntu 20.04',
+ author: {
+ name: 'Wazuh, Inc.',
+ date: '2024/09/09',
+ },
+ references: [
+ 'https://research.splunk.com/endpoint/linux_doas_conf_file_creation/',
+ 'https://www.makeuseof.com/how-to-install-and-use-doas/',
+ 'https://github.com/SigmaHQ/sigma/blob/master/rules/linux/file_event/file_event_lnx_doas_conf_creation.yml',
+ ],
+ },
+ {
+ image: 'grokApp',
+ title: 'Integration 3',
+ description: 'Description for integration 3',
+ isEnable: true,
+ lastUpdate: {
+ lastUpdateDate: '12/18/2024',
+ status: 'Success',
+ },
+ versions: ['1.3.1', '1.3.2', '1.3.3'],
+ compatibility: 'This integration was tested on Ubuntu 20.04',
+ author: {
+ name: 'Wazuh, Inc.',
+ date: '2024/09/09',
+ },
+ references: [
+ 'https://research.splunk.com/endpoint/linux_doas_conf_file_creation/',
+ 'https://www.makeuseof.com/how-to-install-and-use-doas/',
+ 'https://github.com/SigmaHQ/sigma/blob/master/rules/linux/file_event/file_event_lnx_doas_conf_creation.yml',
+ ],
+ },
+ {
+ image: 'reportingApp',
+ title: 'Integration 4',
+ description: 'Description for integration 4',
+ isEnable: false,
+ lastUpdate: {
+ lastUpdateDate: '12/18/2024',
+ status: 'Success',
+ },
+ versions: ['1.3.1', '1.3.2', '1.3.3'],
+ compatibility: 'This integration was tested on Ubuntu 20.04',
+ author: {
+ name: 'Wazuh, Inc.',
+ date: '2024/09/09',
+ },
+ references: [
+ 'https://research.splunk.com/endpoint/linux_doas_conf_file_creation/',
+ 'https://www.makeuseof.com/how-to-install-and-use-doas/',
+ 'https://github.com/SigmaHQ/sigma/blob/master/rules/linux/file_event/file_event_lnx_doas_conf_creation.yml',
+ ],
+ },
+ {
+ image: 'heartbeatApp',
+ title: 'Integration 5',
+ description: 'Description for integration 5',
+ isEnable: true,
+ lastUpdate: {
+ lastUpdateDate: '12/18/2024',
+ status: 'Success',
+ },
+ versions: ['1.3.1', '1.3.2', '1.3.3'],
+ compatibility: 'This integration was tested on Ubuntu 20.04',
+ author: {
+ name: 'Wazuh, Inc.',
+ date: '2024/09/09',
+ },
+ references: [
+ 'https://research.splunk.com/endpoint/linux_doas_conf_file_creation/',
+ 'https://www.makeuseof.com/how-to-install-and-use-doas/',
+ 'https://github.com/SigmaHQ/sigma/blob/master/rules/linux/file_event/file_event_lnx_doas_conf_creation.yml',
+ ],
+ },
+ {
+ image: 'appSearchApp',
+ title: 'Integration 6',
+ description: 'Description for integration 6',
+ isEnable: false,
+ lastUpdate: {
+ lastUpdateDate: '12/18/2024',
+ status: 'Success',
+ },
+ versions: ['1.3.1', '1.3.2', '1.3.3'],
+ compatibility: 'This integration was tested on Ubuntu 20.04',
+ author: {
+ name: 'Wazuh, Inc.',
+ date: '2024/09/09',
+ },
+ references: [
+ 'https://research.splunk.com/endpoint/linux_doas_conf_file_creation/',
+ 'https://www.makeuseof.com/how-to-install-and-use-doas/',
+ 'https://github.com/SigmaHQ/sigma/blob/master/rules/linux/file_event/file_event_lnx_doas_conf_creation.yml',
+ ],
+ },
+ {
+ image: 'indexRollupApp',
+ title: 'Integration 7',
+ description: 'Description for integration 7',
+ isEnable: true,
+ lastUpdate: {
+ lastUpdateDate: '12/18/2024',
+ status: 'Success',
+ },
+ versions: ['1.3.1', '1.3.2', '1.3.3'],
+ compatibility: 'This integration was tested on Ubuntu 20.04',
+ author: {
+ name: 'Wazuh, Inc.',
+ date: '2024/09/09',
+ },
+ references: [
+ 'https://research.splunk.com/endpoint/linux_doas_conf_file_creation/',
+ 'https://www.makeuseof.com/how-to-install-and-use-doas/',
+ 'https://github.com/SigmaHQ/sigma/blob/master/rules/linux/file_event/file_event_lnx_doas_conf_creation.yml',
+ ],
+ },
+ {
+ image: 'canvasApp',
+ title: 'Integration 8',
+ description: 'Description for integration 8',
+ isEnable: false,
+ lastUpdate: {
+ lastUpdateDate: '12/18/2024',
+ status: 'Success',
+ },
+ versions: ['1.3.1', '1.3.2', '1.3.3'],
+ compatibility: 'This integration was tested on Ubuntu 20.04',
+ author: {
+ name: 'Wazuh, Inc.',
+ date: '2024/09/09',
+ },
+ references: [
+ 'https://research.splunk.com/endpoint/linux_doas_conf_file_creation/',
+ 'https://www.makeuseof.com/how-to-install-and-use-doas/',
+ 'https://github.com/SigmaHQ/sigma/blob/master/rules/linux/file_event/file_event_lnx_doas_conf_creation.yml',
+ ],
+ },
+ {
+ image: 'securityApp',
+ title: 'Integration 9',
+ description: 'Description for integration 9',
+ isEnable: true,
+ lastUpdate: {
+ lastUpdateDate: '12/18/2024',
+ status: 'Success',
+ },
+ versions: ['1.3.1', '1.3.2', '1.3.3'],
+ compatibility: 'This integration was tested on Ubuntu 20.04',
+ author: {
+ name: 'Wazuh, Inc.',
+ date: '2024/09/09',
+ },
+ references: [
+ 'https://research.splunk.com/endpoint/linux_doas_conf_file_creation/',
+ 'https://www.makeuseof.com/how-to-install-and-use-doas/',
+ 'https://github.com/SigmaHQ/sigma/blob/master/rules/linux/file_event/file_event_lnx_doas_conf_creation.yml',
+ ],
+ },
+ {
+ image: 'lensApp',
+ title: 'Integration 10',
+ description: 'Description for integration 10',
+ isEnable: false,
+ lastUpdate: {
+ lastUpdateDate: '12/18/2024',
+ status: 'Success',
+ },
+ versions: ['1.3.1', '1.3.2', '1.3.3'],
+ compatibility: 'This integration was tested on Ubuntu 20.04',
+ author: {
+ name: 'Wazuh, Inc.',
+ date: '2024/09/09',
+ },
+ references: [
+ 'https://research.splunk.com/endpoint/linux_doas_conf_file_creation/',
+ 'https://www.makeuseof.com/how-to-install-and-use-doas/',
+ 'https://github.com/SigmaHQ/sigma/blob/master/rules/linux/file_event/file_event_lnx_doas_conf_creation.yml',
+ ],
+ },
+];
diff --git a/plugins/wazuh-security-policies/public/components/integretions/overview.tsx b/plugins/wazuh-security-policies/public/components/integretions/overview.tsx
new file mode 100644
index 0000000000..fb70c81bb3
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/integretions/overview.tsx
@@ -0,0 +1,130 @@
+import React, { useState } from 'react';
+import {
+ EuiButton,
+ EuiHealth,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiText,
+ EuiPageHeader,
+} from '@elastic/eui';
+import './integrations.scss';
+import { SearchBar } from '../common/components/searchbar';
+import { LastUpdateContentManagerText } from '../common/components/last-update-content-manager-text.tsx';
+import { NoResultsData } from '../common/templates/no-results';
+import { CardIntegration } from './components/card-integration';
+import { integrations } from './mock-data-integrations';
+
+export const IntegrationOverview = () => {
+ const [query, setQuery] = useState({ text: '' });
+ const [lastUpdate, setLastUpdate] = useState({
+ lastUpdateDate: '12/18/2024',
+ status: 'Success',
+ });
+ // Header page start
+ const titleHeader = (
+
+ Integrations
+
+ Updated
+
+
+ );
+
+ const updateContentManager = () => {
+ const currentDate = new Date().toLocaleString();
+
+ setLastUpdate({
+ lastUpdateDate: currentDate,
+ status: 'Success',
+ });
+ };
+
+ const descriptionHeader = LastUpdateContentManagerText(
+ integrations[0].lastUpdate,
+ );
+ const rightSideItems = [
+
+ Update
+ ,
+ ];
+ // Header page end
+ // Search bar start
+ const filters = [
+ {
+ type: 'field_value_selection',
+ field: 'integration',
+ name: 'Integrations',
+ multiSelect: 'and',
+ operator: 'exact',
+ cache: 10000, // will cache the loaded tags for 10 sec
+ options: integrations.map(integration => ({
+ value: integration.title,
+ view: {integration.title},
+ })),
+ },
+ ];
+ const schema = {
+ strict: true,
+ fields: {
+ integration: {
+ type: 'string',
+ },
+ },
+ };
+ // Search bar end
+ const listAllIntegrationsComponent = integrations.map(
+ (integration, index) => (
+
+
+
+ ),
+ );
+ const integrationFilter = integrations
+ .filter(integration =>
+ query.text
+ .toLocaleLowerCase()
+ .includes(integration.title.toLocaleLowerCase()),
+ )
+ .map((integration, index) => (
+
+
+
+ ));
+
+ return (
+ <>
+
+
+
+ {!query.text && listAllIntegrationsComponent}
+ {query.text && integrationFilter.length === 0 ? (
+
+ ) : (
+ integrationFilter
+ )}
+
+ >
+ );
+};
diff --git a/plugins/wazuh-security-policies/public/components/rules/mock-data-rules.tsx b/plugins/wazuh-security-policies/public/components/rules/mock-data-rules.tsx
new file mode 100644
index 0000000000..ca7f222101
--- /dev/null
+++ b/plugins/wazuh-security-policies/public/components/rules/mock-data-rules.tsx
@@ -0,0 +1,704 @@
+export const decoder = [
+ {
+ id: 1,
+ name: 'rule/discovery_kernel_module_enumeration/0',
+ provider: 'native',
+ status: 'enable',
+ metadata: {
+ module: 'Linux',
+ title: 'System Information Discovery',
+ description: 'Detects System Information Discovery commands.',
+ compatibility: '',
+ versions: [''],
+ author: {
+ name: 'Wazuh, Inc.',
+ date: '2024/09/09',
+ },
+ references: [
+ 'https://github.com/redcanaryco/atomic-red-team/blob/f296668303c29d3f4c07e42bdd2b28d8dd6625f9/atomics/T1082/T1082.md',
+ 'https://github.com/SigmaHQ/sigma/blob/master/rules/linux/auditd/lnx_auditd_system_info_discovery.yml',
+ ],
+ },
+ definitions: {
+ excluded_process_parents_name: [
+ 'mkinitramfs',
+ 'cryptroot',
+ 'framebuffer',
+ 'dracut',
+ 'jem',
+ 'thin-provisioning-tools',
+ 'readykernel',
+ 'lvm2',
+ 'vz-start',
+ 'iscsi',
+ 'mdadm',
+ 'ovalprobes',
+ 'bcache',
+ 'plymouth',
+ 'dkms',
+ 'overlayroot',
+ 'weak-modules',
+ 'zfs',
+ ],
+ },
+ check:
+ "$event.module == sysmon-linux AND array_contains($event.category, process) AND array_contains($event.type, start) AND (($process.name == lsmod OR $process.name == modinfo) OR ($process.name == kmod AND array_contains($process.args, list)) OR ($process.name == depmod AND array_contains_any($process.args, '--all', '-a'))) AND NOT match_value($process.parent.name, $excluded_process_parents_name)",
+ normalize: [
+ {
+ map: [
+ { 'event.risk_score': '47.0' },
+ {
+ 'rule.description':
+ 'Detects System Information Discovery commands.',
+ },
+ { 'rule.license': 'Wazuh Inc.' },
+ { 'rule.name': 'Enumeration of Kernel Modules' },
+ { 'threat.framework': 'MITRE ATT&CK' },
+ { 'threat.technique.id': ['T1082'] },
+ { 'threat.technique.name': ['System Information Discovery'] },
+ {
+ 'threat.technique.reference': [
+ 'https://attack.mitre.org/techniques/T1082/',
+ ],
+ },
+ { 'threat.tactic.id': ['TA0005'] },
+ { 'threat.tactic.name': ['Discovery'] },
+ {
+ 'threat.tactic.reference': [
+ 'https://attack.mitre.org/tactics/TA0005/',
+ ],
+ },
+ {
+ 'wazuh.rules': 'array_append(discovery_kernel_module_enumeration)',
+ },
+ { 'vulnerability.severity': 'medium' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 2,
+ name: 'decoder/system-auth/0',
+ provider: 'native',
+ status: 'disable',
+ metadata: {
+ module: 'system',
+ dataset: 'system-auth',
+ title: 'system-auth logs',
+ description: 'Decoder for system athenticated action logs.',
+ compatibility:
+ 'This integration was tested with logs from OS like Ubuntu 20.04, Centos 7, and macOS Sierra.',
+ versions: ['any'],
+ author: {
+ name: 'Wazuh Inc.',
+ email: 'info@wazuh.com',
+ date: '2023/05/15',
+ },
+ references: [
+ 'https://www.loggly.com/ultimate-guide/linux-logging-basics/',
+ ],
+ },
+ parents: ['decoder/syslog/0'],
+ definitions: {
+ isAuthProcess:
+ '$process.name == sshd OR $process.name == sudo OR $process.name == groupadd OR $process.name == useradd OR $process.name == groupdel OR $process.name == groupmod OR $process.name == userdel OR $process.name == usermod OR $process.name == CRON',
+ },
+ check: '$isAuthProcess',
+ normalize: [
+ {
+ map: [
+ { 'event.dataset': 'system-auth' },
+ { 'event.kind': 'event' },
+ { 'event.module': 'system' },
+ { 'event.outcome': 'success' },
+ { 'wazuh.decoders': 'array_append(system-auth)' },
+ ],
+ },
+ {
+ check: [{ 'process.name': 'sshd' }],
+ 'parse|message': [
+ '<_system.auth.ssh.event> <_system.auth.ssh.method> for from port ssh2(?:<~>)',
+ '<_system.auth.ssh.event> user from (? port )',
+ 'Did not receive identification string from ',
+ 'subsystem request for <_system.auth.ssh.subsystem> by user ',
+ '<_system.auth.ssh.session.action>: Too many authentication <_system.auth.ssh.event> for [preauth]',
+ ' [<~>][<~>]: <_system.auth.ssh.event>: <_system.auth.ssh.session.process_id> tty<~/literal//>?<~/literal/s><_system.process.tty.char_device.major>',
+ '<_system.auth.ssh.event>: Read from socket failed: Connection reset by peer [preauth]',
+ 'Received <_system.auth.ssh.event> from : <~>: [<~>]',
+ ],
+ },
+ {
+ check:
+ '$_system.auth.ssh.event == Accepted OR $_system.auth.ssh.event == USER_PROCESS',
+ map: [
+ { 'event.action': 'ssh_login' },
+ { 'event.category': 'array_append(authentication, session)' },
+ { 'event.outcome': 'success' },
+ { 'event.type': 'array_append(info)' },
+ ],
+ },
+ {
+ check:
+ '$_system.auth.ssh.event == DEAD_PROCESS OR $_system.auth.ssh.event == disconnect',
+ map: [
+ { 'event.action': 'ssh_login' },
+ { 'event.category': 'array_append(authentication, session)' },
+ { 'event.outcome': 'success' },
+ { 'event.type': 'array_append(end)' },
+ ],
+ },
+ {
+ check:
+ '$_system.auth.ssh.event == Invalid OR $_system.auth.ssh.event == Failed OR $_system.auth.ssh.event == failures OR $_system.auth.ssh.event == fatal',
+ map: [
+ { 'event.action': 'ssh_login' },
+ { 'event.category': 'array_append(authentication)' },
+ { 'event.outcome': 'failure' },
+ { 'event.type': 'array_append(info)' },
+ ],
+ },
+ {
+ check: [{ 'process.name': 'sudo' }],
+ 'parse|message': [
+ String.raw` : <_system.auth.sudo.error> ; TTY=tty<~/literal/\/>?<~/literal/s><_system.process.tty.char_device.major> ; PWD=<_system.auth.sudo.pwd> ; USER= ; COMMAND=<_system.auth.sudo.command>`,
+ ' : <_system.auth.sudo.error> ; TTY=<_system.auth.sudo.tty> ; PWD=<_system.auth.sudo.pwd> ; USER= ; COMMAND=<_system.auth.sudo.command>',
+ ' : TTY=<_system.auth.sudo.tty> ; PWD=<_system.auth.sudo.pwd> ; USER= ; COMMAND=<_system.auth.sudo.command>',
+ String.raw` : TTY=tty<~/literal/\/>?<~/literal/s><_system.process.tty.char_device.major> ; PWD=<_system.auth.sudo.pwd> ; USER= ; COMMAND=<_system.auth.sudo.command>`,
+ ],
+ map: [{ 'event.category': 'array_append(process)' }],
+ },
+ {
+ check: [{ message: 'contains("session opened")' }],
+ map: [{ 'event.action': 'logged-on' }],
+ },
+ {
+ check: [{ message: 'contains("session closed")' }],
+ map: [{ 'event.action': 'logged-off' }],
+ },
+ {
+ check: [{ message: 'contains(pam_)' }],
+ 'parse|message': [
+ String.raw`pam_unix\(<~>:<~>\): authentication <_system.auth.pam.session.action>; logname= uid= euid= tty= ruser= rhost= user=`,
+ ],
+ map: [{ 'event.category': 'array_append(authentication)' }],
+ },
+ {
+ check: [{ message: 'contains(pam_)' }],
+ 'parse|message': [
+ String.raw`pam_unix\(<~>:<~>\): session <_system.auth.pam.session.action> for user <_system.auth.pam.foruser.name> by <_system.auth.pam.byuser.name>\(uid=\)`,
+ String.raw`pam_unix\(<~>:<~>\): session <_system.auth.pam.session.action> for user <_system.auth.pam.foruser.name> by \(uid=\)`,
+ String.raw`pam_unix\(<~>:<~>\): session <_system.auth.pam.session.action> for user <_system.auth.pam.foruser.name>`,
+ ],
+ map: [{ 'event.category': 'array_append(session)' }],
+ },
+ {
+ check: [{ message: 'contains(pam_succeed_if)' }],
+ 'parse|message': [
+ String.raw`pam_succeed_if\(<~>:<~>\): requirement <~> not met by user `,
+ ],
+ map: [{ 'event.outcome': 'failure' }],
+ },
+ {
+ check: [{ message: 'contains(PAM)' }],
+ 'parse|message': [
+ 'PAM <~> more authentication <_system.auth.pam.session.action>; logname= uid= euid= tty= ruser= rhost= user=',
+ ],
+ map: [{ 'event.category': 'array_append(authentication, session)' }],
+ },
+ {
+ check: [{ message: 'contains(PAM)' }],
+ 'parse|message': [
+ 'error: PAM: <~> authentication <~> user from ',
+ ],
+ },
+ {
+ check: [{ '_system.auth.pam.byuser.name': "string_not_equal('')" }],
+ map: [
+ { 'user.name': '$_system.auth.pam.byuser.name' },
+ { 'user.effective.name': '$_system.auth.pam.foruser.name' },
+ ],
+ },
+ {
+ check: [{ '_system.auth.pam.byuser.name': 'not_exists()' }],
+ map: [{ 'user.name': '$_system.auth.pam.foruser.name' }],
+ },
+ {
+ check: '$_system.auth.pam.session.action == closed',
+ },
+ ],
+ },
+ {
+ id: 3,
+ name: 'decoder/apache-access/0',
+ provider: 'native',
+ status: 'disable',
+ metadata: {
+ module: 'apache-http',
+ title: 'Apache HTTP Server access logs decoder',
+ description: 'Decoder for Apache HTTP Server access logs.',
+ versions: ['2.2.31', '2.4.16'],
+ compatibility:
+ 'The Apache datasets were tested with Apache 2.4.12 and 2.4.46 and are expected to work with all versions >= 2.2.31 and >= 2.4.16 (independent from operating system).',
+ author: {
+ name: 'Wazuh Inc.',
+ date: '2023/11/29',
+ },
+ references: [
+ 'https://httpd.apache.orgPlease generate document codes/2.4/logs.html',
+ ],
+ },
+ check: '$event.module == apache-access',
+ 'parse|event.original': [
+ ' - [] "<~/literal/->?<_http_request>" ?<~/literal/-> "" ""',
+ ' - [] "<~/literal/->?<_http_request>" ?<~/literal/-> "" ""',
+ ' - [] "<_http_request>" <_ignore/literal/->?(? "" "")',
+ ' - [] "-" -',
+ ' - - [] "-" -',
+ ' - - [] "<~/literal/->?<_http_request>" ?<~/literal/-> "" ""',
+ ' - [] "<~/literal/->?<_http_request>" ?<~/literal/-> "" ""',
+ '[] "<_http_request>" ?<~/literal/->',
+ '[] "<_http_request>" ?<~/literal/->',
+ ' - - [] "<~/literal/->?<_http_request>" ?<~/literal/-> "" "" "-"',
+ ' - [] "<~/literal/->?<_http_request>" ?<~/literal/-> "" "" X-Forwarded-For="<_forwarded_for>"',
+ ],
+ normalize: [
+ {
+ map: [
+ { 'event.category': 'array_append(web)' },
+ { 'event.dataset': 'apache-access' },
+ { 'event.kind': 'event' },
+ { 'event.module': 'apache-http' },
+ { 'service.type': 'apache' },
+ { 'wazuh.decoders': 'array_append(apache-access)' },
+ { 'source.ip': '$source.address' },
+ { _tls: "split($network.protocol, 'v')" },
+ { _tls_1: '$_tls.1' },
+ { _client_ip: "split($_forwarded_for, ',')" },
+ { 'client.ip': '$_client_ip.0' },
+ { 'network.forwarded_ip': '$_client_ip.0' },
+ { 'tls.version_protocol': '$_tls.0' },
+ { 'tls.cipher': '$tls.cipher' },
+ ],
+ 'parse|_http_request': [
+ ' HTTP/',
+ ],
+ },
+ {
+ check: [{ _tls_1: String.raw`regex_match(\d+\.\d+)` }],
+ map: [{ 'tls.version': '$_tls_1' }],
+ },
+ {
+ check: [{ _tls_1: String.raw`regex_not_match(\d+\.d+)` }],
+ map: [{ 'tls.version': "concat_any($_tls_1, '.0')" }],
+ },
+ {
+ check: 'int_less($http.response.status_code, 400)',
+ map: [{ 'event.outcome': 'success' }],
+ },
+ {
+ check: 'int_greater_or_equal($http.response.status_code, 400)',
+ map: [{ 'event.outcome': 'failure' }],
+ },
+ {
+ check: [{ 'source.ip': 'not_exists()' }],
+ map: [{ 'source.domain': 'parse_fqdn($source.address)' }],
+ },
+ {
+ map: [
+ {
+ 'url.extension': String.raw`regex_extract($url.original, '.*\.([a-zA-Z0-9]+)(?:\?|$)')`,
+ },
+ { 'url.path': '$url.original' },
+ { 'url.query': String.raw`regex_extract($url.original, '\?(.*)')` },
+ { 'url.domain': '$destination.domain' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 4,
+ name: 'decoder/syslog/0',
+ provider: 'native',
+ status: 'disable',
+ metadata: {
+ module: 'syslog',
+ title: 'Syslog Decoder event',
+ description: 'Syslog header',
+ compatibility: 'This decoder has been tested on Wazuh version 4.3',
+ versions: ['4.3'],
+ author: {
+ name: 'Wazuh, Inc.',
+ url: 'https://wazuh.com',
+ date: '2022/11/08',
+ },
+ references: [
+ 'https://www.ietf.org/rfc/rfc3164.txt',
+ 'https://www.ietf.org/rfc/rfc5424.txt',
+ ],
+ },
+ check: '$event.module == syslog',
+ 'parse|event.original': [
+ // BSD Syslog RFC 3164 standard
+ ' []:<~/ignore/ >',
+ // BSD Syslog RFC 3164 no pid
+ ' :<~/ignore/ >',
+ // BSD Syslog RFC 3164 standard ISO8601
+ ' []: ',
+ // BSD Syslog RFC 3164 no pid ISO8601
+ ' : ',
+ // RFC3164 example 2 section 5.4
+ ' ',
+ // RFC3164 example 4 section 5.4
+ ' []:<~/ignore/ >',
+ ],
+ normalize: [
+ {
+ map: [
+ { 'event.kind': 'event' },
+ { 'wazuh.decoders': 'array_append(syslog)' },
+ { 'related.hosts': 'array_append($host.hostname)' },
+ { 'process.name': 'rename($TAG)' },
+ { 'host.ip': 'array_append($tmp.host_ip)' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 5,
+ name: 'decoder/syslog/1',
+ provider: 'native',
+ status: 'disable',
+ metadata: {
+ module: 'syslog5',
+ title: 'Syslog Decoder event',
+ description: 'Syslog header',
+ compatibility: 'This decoder has been tested on Wazuh version 4.3',
+ author: {
+ name: 'Wazuh, Inc.',
+ url: 'https://wazuh.com',
+ date: '2022/11/08',
+ },
+ references: [
+ 'https://www.ietf.org/rfc/rfc3164.txt',
+ 'https://www.ietf.org/rfc/rfc5424.txt',
+ ],
+ },
+ 'parse|event.original': [
+ ' []:<~/ignore/ >',
+
+ ' :<~/ignore/ >',
+
+ ' []: ',
+
+ ' : ',
+ ' ',
+
+ ' []:<~/ignore/ >',
+ ],
+ normalize: [
+ {
+ map: [
+ { 'event.kind': 'event' },
+ { 'wazuh.decoders': 'array_append(syslog)' },
+ { 'related.hosts': 'array_append($host.hostname)' },
+ { 'process.name': 'rename($TAG)' },
+ { 'host.ip': 'array_append($tmp.host_ip)' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 6,
+ name: 'check/string',
+ provider: 'native',
+ status: 'draft',
+ metadata: {
+ module: 'syslog6',
+ title: 'Syslog Decoder event',
+ description: 'Syslog header',
+ compatibility: 'This decoder has been tested on Wazuh version 4.3',
+ author: {
+ name: 'Wazuh, Inc.',
+ url: 'https://wazuh.com',
+ date: '2022/11/08',
+ },
+ references: [
+ 'https://www.ietf.org/rfc/rfc3164.txt',
+ 'https://www.ietf.org/rfc/rfc5424.txt',
+ ],
+ },
+ check:
+ ' []:<~/ignore/ >',
+ normalize: [
+ {
+ map: [
+ { 'event.kind': 'event' },
+ { 'wazuh.decoders': 'array_append(syslog)' },
+ { 'related.hosts': 'array_append($host.hostname)' },
+ { 'process.name': 'rename($TAG)' },
+ { 'host.ip': 'array_append($tmp.host_ip)' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 7,
+ name: 'check/array',
+ provider: 'custom',
+ status: 'enable',
+ metadata: {
+ module: 'syslog',
+ title: 'Syslog Decoder event',
+ description: 'Syslog header',
+ compatibility: 'This decoder has been tested on Wazuh version 4.3',
+ author: {
+ name: 'Wazuh, Inc.',
+ url: 'https://wazuh.com',
+ date: '2022/11/08',
+ },
+ references: [
+ 'https://www.ietf.org/rfc/rfc3164.txt',
+ 'https://www.ietf.org/rfc/rfc5424.txt',
+ ],
+ },
+ 'parse|event.original': [
+ ' []:<~/ignore/ >',
+
+ ' :<~/ignore/ >',
+
+ ' []: ',
+
+ ' : ',
+ ' ',
+
+ ' []:<~/ignore/ >',
+ ],
+ check: [
+ { 'event.kind': 'event' },
+ { 'wazuh.decoders': 'array_append(syslog)' },
+ { 'related.hosts': 'array_append($host.hostname)' },
+ { 'process.name': 'rename($TAG)' },
+ { 'host.ip': 'array_append($tmp.host_ip)' },
+ ],
+ },
+ {
+ id: 8,
+ name: 'decoder/syslog/1',
+ provider: 'custom',
+ status: 'enable',
+ metadata: {
+ module: 'syslog',
+ title: 'Syslog Decoder event',
+ description: 'Syslog header',
+ compatibility: 'This decoder has been tested on Wazuh version 4.3',
+ author: {
+ name: 'Wazuh, Inc.',
+ url: 'https://wazuh.com',
+ date: '2022/11/08',
+ },
+ references: [
+ 'https://www.ietf.org/rfc/rfc3164.txt',
+ 'https://www.ietf.org/rfc/rfc5424.txt',
+ ],
+ },
+ 'parse|event.original': [
+ ' []:<~/ignore/ >',
+
+ ' :<~/ignore/ >',
+
+ ' []: ',
+
+ ' : ',
+ ' ',
+
+ ' []:<~/ignore/ >',
+ ],
+ normalize: [
+ {
+ map: [
+ { 'event.kind': 'event' },
+ { 'wazuh.decoders': 'array_append(syslog)' },
+ { 'related.hosts': 'array_append($host.hostname)' },
+ { 'process.name': 'rename($TAG)' },
+ { 'host.ip': 'array_append($tmp.host_ip)' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 9,
+ name: 'decoder/syslog/2',
+ provider: 'custom',
+ status: 'enable',
+ metadata: {
+ module: 'syslog',
+ title: 'Syslog Decoder event',
+ description: 'Syslog header',
+ compatibility: 'This decoder has been tested on Wazuh version 4.3',
+ author: {
+ name: 'Wazuh, Inc.',
+ url: 'https://wazuh.com',
+ date: '2022/11/08',
+ },
+ references: [
+ 'https://www.ietf.org/rfc/rfc3164.txt',
+ 'https://www.ietf.org/rfc/rfc5424.txt',
+ ],
+ },
+ 'parse|event.original': [
+ ' []:<~/ignore/ >',
+
+ ' :<~/ignore/ >',
+
+ ' []: ',
+
+ ' : ',
+ ' ',
+
+ ' []:<~/ignore/ >',
+ ],
+ normalize: [
+ {
+ map: [
+ { 'event.kind': 'event' },
+ { 'wazuh.decoders': 'array_append(syslog)' },
+ { 'related.hosts': 'array_append($host.hostname)' },
+ { 'process.name': 'rename($TAG)' },
+ { 'host.ip': 'array_append($tmp.host_ip)' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 10,
+ name: 'decoder/syslog/0',
+ provider: 'custom',
+ status: 'draft',
+ metadata: {
+ module: 'syslog',
+ title: 'Syslog Decoder event',
+ description: 'Syslog header',
+ compatibility: 'This decoder has been tested on Wazuh version 4.3',
+ author: {
+ name: 'Wazuh, Inc.',
+ url: 'https://wazuh.com',
+ date: '2022/11/08',
+ },
+ references: [
+ 'https://www.ietf.org/rfc/rfc3164.txt',
+ 'https://www.ietf.org/rfc/rfc5424.txt',
+ ],
+ },
+ 'parse|event.original': [
+ '