diff --git a/deps/wazuh_testing/wazuh_testing/modules/eps/__init__.py b/deps/wazuh_testing/wazuh_testing/modules/eps/__init__.py new file mode 100644 index 0000000000..085e57c960 --- /dev/null +++ b/deps/wazuh_testing/wazuh_testing/modules/eps/__init__.py @@ -0,0 +1,21 @@ +import os +import json +from datetime import datetime, timedelta +from copy import deepcopy + +from wazuh_testing.tools.time import parse_date_time_format + + +# Timeouts +T_5 = 5 +T_10 = 10 +T_15 = 15 +T_20 = 20 +T_60 = 60 + +ANALYSISD_PREFIX = r'.*wazuh-analysisd.*' +MAILD_PREFIX = r'.*wazuh-maild.*' +# wazuh-analysisd.state file default update configuration +ANALYSISD_STATE_INTERNAL_DEFAULT = '5' +PERCENTAGE_PROCESS_MSGS = 0.95 +QUEUE_SIZE = 16384 \ No newline at end of file diff --git a/deps/wazuh_testing/wazuh_testing/modules/eps/event_monitor.py b/deps/wazuh_testing/wazuh_testing/modules/eps/event_monitor.py new file mode 100644 index 0000000000..90d4bc4605 --- /dev/null +++ b/deps/wazuh_testing/wazuh_testing/modules/eps/event_monitor.py @@ -0,0 +1,120 @@ +import re +from datetime import datetime + +from wazuh_testing.modules import eps as eps +from wazuh_testing.tools import LOG_FILE_PATH, ANALYSISD_STATE, ALERT_LOGS_PATH +from wazuh_testing.tools.monitoring import FileMonitor + + +def make_analysisd_callback(pattern, prefix=eps.ANALYSISD_PREFIX): + """Create a callback function from a text pattern. + + It already contains the vulnerability-detector prefix. + + Args: + pattern (str): String to match on the log. + prefix (str): regular expression used as prefix before the pattern. + + Returns: + lambda: function that returns if there's a match in the file + + Examples: + >>> callback_bionic_update_started = make_vuln_callback("Starting Ubuntu Bionic database update") + """ + pattern = r'\s+'.join(pattern.split()) + regex = re.compile(r'{}{}'.format(prefix, pattern)) + + return lambda line: regex.match(line) is not None + + +def check_analysisd_event(file_monitor=None, callback='', error_message=None, update_position=True, + timeout=eps.T_60, prefix=eps.ANALYSISD_PREFIX, accum_results=1, + file_to_monitor=LOG_FILE_PATH): + """Check if a analysisd event occurs + + Args: + file_monitor (FileMonitor): FileMonitor object to monitor the file content. + callback (str): log regex to check in Wazuh log + error_message (str): error message to show in case of expected event does not occur + update_position (boolean): filter configuration parameter to search in Wazuh log + timeout (str): timeout to check the event in Wazuh log + prefix (str): log pattern regex + accum_results (int): Accumulation of matches. + """ + file_monitor = FileMonitor(file_to_monitor) if file_monitor is None else file_monitor + error_message = f"Could not find this event in {file_to_monitor}: {callback}" if error_message is None else \ + error_message + + file_monitor.start(timeout=timeout, update_position=update_position, accum_results=accum_results, + callback=make_analysisd_callback(callback, prefix), error_message=error_message) + + +def check_eps_disabled(): + """Check if the eps module is disabled""" + check_analysisd_event(callback=fr'.*INFO: EPS limit disabled.*', timeout=eps.T_10) + + +def check_eps_enabled(maximun, timeframe): + """Check if the eps module is enable""" + check_analysisd_event(callback=fr".*INFO: EPS limit enabled, EPS: '{maximun}', timeframe: '{timeframe}'", + timeout=eps.T_10) + + +def check_configuration_error(): + """Check the configuration error event in ossec.log""" + check_analysisd_event(timeout=eps.T_10, callback=r".* \(\d+\): Configuration error at.*", + error_message="Could not find the event 'Configuration error at 'etc/ossec.conf' " + 'in ossec.log', prefix=eps.MAILD_PREFIX) + + +def get_words_from_file(words, filename): + """Get the words from file + + Args: + wordss (str): Word to find in the file + Returns: + str: Line that match in file + """ + with open(filename, 'r') as file: + for _, line in enumerate(file): + # search string + if words in line: + return line + + +def get_analysisd_state(word): + """Get the value of word in wazuh-analysisd.state + + Args: + word (str): Word to find in the file + """ + line = get_words_from_file(word, ANALYSISD_STATE) + return float(line.split("\'")[1::2][0]) + + +def get_alert_timestamp(start_log, end_log): + """Get the timestamp of the alert if exist in the alerts.log file between two string + + Args: + start_log (str): Start message to find + end_log (str): End message to find + """ + with open(ALERT_LOGS_PATH, 'r') as file: + str_file = file.read() + index1 = str_file.find(end_log) + index2 = str_file[0: index1].rfind(start_log) + str_alert = str_file[index2: index1] + timestamp = str_alert[str_alert.find(start_log) + len(start_log):str_alert.find(': ')] + + return datetime.fromtimestamp(float(timestamp)).strftime('%Y-%m-%d %H:%M:%S') + + +def get_msg_with_number(message): + """Check if the alerts.log file contains the message + + Args: + message (str): Message to find + """ + check_analysisd_event(timeout=eps.T_20, callback=message, + error_message="Could not find the event in alerts.log", prefix="", \ + file_to_monitor=ALERT_LOGS_PATH) \ No newline at end of file diff --git a/deps/wazuh_testing/wazuh_testing/processes/__init__.py b/deps/wazuh_testing/wazuh_testing/processes/__init__.py index ebd1aec370..ce74feeba8 100644 --- a/deps/wazuh_testing/wazuh_testing/processes/__init__.py +++ b/deps/wazuh_testing/wazuh_testing/processes/__init__.py @@ -4,3 +4,13 @@ def check_if_modulesd_is_running(): """Check if modulesd daemon is running""" assert check_if_process_is_running('wazuh-modulesd'), 'wazuh-modulesd is not running. It may have crashed' + + +def check_if_deamon_is_running(daemon): + """Check if the specified daemon is running""" + assert check_if_process_is_running(daemon), f"{daemon} is not running. It may have crashed" + + +def check_if_deamon_is_not_running(daemon): + """Check if the specified daemon is running""" + assert check_if_process_is_running(daemon) == False, f"{daemon} is running. It may have crashed" diff --git a/deps/wazuh_testing/wazuh_testing/scripts/simulate_agents.py b/deps/wazuh_testing/wazuh_testing/scripts/simulate_agents.py index 14e91d0a04..2f06ae8d72 100644 --- a/deps/wazuh_testing/wazuh_testing/scripts/simulate_agents.py +++ b/deps/wazuh_testing/wazuh_testing/scripts/simulate_agents.py @@ -41,13 +41,16 @@ def process_script_parameters(args): args (argparse.Namespace): Script args. """ # Add keepalive and receive_message modules if they are not specified in script parameters - if 'keepalive' not in args.modules: - args.modules.append('keepalive') - args.modules_eps.append('0') + if None == args.disable_keepalive: + if 'keepalive' not in args.modules: + args.modules.append('keepalive') + args.modules_eps.append('0') - if 'receive_messages' not in args.modules: - args.modules.append('receive_messages') - args.modules_eps.append('0') + + if None == args.disable_receive: + if 'receive_messages' not in args.modules: + args.modules.append('receive_messages') + args.modules_eps.append('0') def set_agent_modules_and_eps(agent, active_modules, modules_eps): @@ -129,13 +132,14 @@ def create_agents(args): return agents -def create_injectors(agents, manager_address, protocol): +def create_injectors(agents, manager_address, protocol, limit_msg): """Create injectos objects from list of agents and connection parameters. Args: agents (list): List of agents to create the injectors (1 injector/agent). manager_address (str): Manager IP address to connect the agents. protocol (str): TCP or UDP protocol to connect the agents to the manager. + limit_msg (int): Maximun amount of message to be sent. Returns: list: List of injector objects. @@ -146,12 +150,12 @@ def create_injectors(agents, manager_address, protocol): for agent in agents: sender = ag.Sender(manager_address, protocol=protocol) - injectors.append(ag.Injector(sender, agent)) + injectors.append(ag.Injector(sender, agent, limit_msg)) return injectors -def start(injector, time_alive): +def start(injector, time_alive, flag_disable_keepalive): """Start the injector process for a specified time. Args: @@ -160,7 +164,10 @@ def start(injector, time_alive): """ try: injector.run() - sleep(time_alive) + if not flag_disable_keepalive: + sleep(time_alive) + else: + injector.wait() finally: stop(injector) @@ -174,7 +181,7 @@ def stop(injector): injector.stop_receive() -def run(injectors, time_alive): +def run(injectors, time_alive, flag_disable_keepalive): """Run each injector in a separated process. Args: @@ -184,7 +191,7 @@ def run(injectors, time_alive): processes = [] for injector in injectors: - processes.append(Process(target=start, args=(injector, time_alive))) + processes.append(Process(target=start, args=(injector, time_alive, flag_disable_keepalive))) for agent_process in processes: agent_process.start() @@ -322,6 +329,18 @@ def main(): help='Waiting time in seconds between agent registration and the sending of events.', required=False, default=0, dest='waiting_connection_time') + arg_parser.add_argument('-e', '--limit-msg', metavar='', type=int, + help='Amount of message to sent.', + required=False, default=None, dest='limit_msg') + + arg_parser.add_argument('-k', '--disable-keepalive', metavar='', type=bool, + help='Disable keepalive module', + required=False, default=False, dest='disable_keepalive') + + arg_parser.add_argument('-d', '--disable-receive', metavar='', type=bool, + help='Disable receive message module', + required=False, default=False, dest='disable_receive') + args = arg_parser.parse_args() process_script_parameters(args) @@ -333,10 +352,10 @@ def main(): # Waiting time to prevent CPU overload when registering many agents (registration + event generation). sleep(args.waiting_connection_time) - injectors = create_injectors(agents, args.manager_address, args.agent_protocol) + injectors = create_injectors(agents, args.manager_address, args.agent_protocol, args.limit_msg) - run(injectors, args.simulation_time) + run(injectors, args.simulation_time, args.disable_keepalive) if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/deps/wazuh_testing/wazuh_testing/tools/__init__.py b/deps/wazuh_testing/wazuh_testing/tools/__init__.py index 9584356065..f8d0457a22 100644 --- a/deps/wazuh_testing/wazuh_testing/tools/__init__.py +++ b/deps/wazuh_testing/wazuh_testing/tools/__init__.py @@ -77,6 +77,9 @@ else: HOSTS_FILE_PATH = os.path.join('/', 'etc', 'hosts') GLOBAL_DB_PATH = os.path.join(WAZUH_PATH, 'queue', 'db', 'global.db') + ANALYSISD_STATE = os.path.join(WAZUH_PATH, 'var', 'run', 'wazuh-analysisd.state') + SIMULATE_AGENT = os.path.join('deps','wazuh_testing','wazuh_testing','scripts','simulate_agents.py') + WAZUH_INTERNAL_OPTIONS = os.path.join(WAZUH_PATH, 'etc', 'internal_options.conf') try: import grp @@ -126,6 +129,7 @@ def get_service(): CLIENT_CUSTOM_CERT_PATH = os.path.join(_data_path, 'sslmanager.cert') WAZUH_LOGS_PATH = os.path.join(WAZUH_PATH, 'logs') +ALERT_PATH = os.path.join(WAZUH_LOGS_PATH, 'alerts') ALERT_FILE_PATH = os.path.join(WAZUH_LOGS_PATH, 'alerts', 'alerts.json') ALERT_LOGS_PATH = os.path.join(WAZUH_LOGS_PATH, 'alerts', 'alerts.log') CLUSTER_LOGS_PATH = os.path.join(WAZUH_LOGS_PATH, 'cluster.log') diff --git a/deps/wazuh_testing/wazuh_testing/tools/agent_simulator.py b/deps/wazuh_testing/wazuh_testing/tools/agent_simulator.py index 3b2089b780..c012a8e660 100644 --- a/deps/wazuh_testing/wazuh_testing/tools/agent_simulator.py +++ b/deps/wazuh_testing/wazuh_testing/tools/agent_simulator.py @@ -1527,6 +1527,7 @@ class Injector: thread_number (int): total number of threads created. This may change depending on the modules used in the agent. threads (list): list containing all the threads created. + limit_msg (int): Maximun amount of message to be sent. Examples: To create an Injector, you need to create an agent, a sender and then, create the injector using both of them. @@ -1538,16 +1539,17 @@ class Injector: >>> injector.run() """ - def __init__(self, sender, agent): + def __init__(self, sender, agent, limit): self.sender = sender self.agent = agent + self.limit_msg = limit self.thread_number = 0 self.threads = [] for module, config in self.agent.modules.items(): if config["status"] == "enabled": self.threads.append( InjectorThread(self.thread_number, f"Thread-{self.agent.id}{module}", self.sender, - self.agent, module)) + self.agent, module, self.limit_msg)) self.thread_number += 1 def run(self): @@ -1566,6 +1568,11 @@ def stop_receive(self): self.sender.socket.close() + def wait(self): + for thread in range(self.thread_number): + self.threads[thread].join() + + class InjectorThread(threading.Thread): """This class creates a thread who will create and send the events to the manager for each module. @@ -1576,8 +1583,9 @@ class InjectorThread(threading.Thread): agent (Agent): agent owner of the injector and the sender. module (str): module used to send events (fim, syscollector, etc). stop_thread (int): 0 if the thread is running, 1 if it is stopped. + limit_msg (int): Maximun amount of message to be sent. """ - def __init__(self, thread_id, name, sender, agent, module): + def __init__(self, thread_id, name, sender, agent, module, limit_msg): super(InjectorThread, self).__init__() self.thread_id = thread_id self.name = name @@ -1586,6 +1594,7 @@ def __init__(self, thread_id, name, sender, agent, module): self.totalMessages = 0 self.module = module self.stop_thread = 0 + self.limit_msg = limit_msg def keep_alive(self): """Send a keep alive message from the agent to the manager.""" @@ -1668,6 +1677,11 @@ def run_module(self, module): char_size = getsizeof(event_msg[0]) - getsizeof('') event_msg += 'A' * (dummy_message_size//char_size) + # Add message limitiation + if self.totalMessages >= self.limit_msg: + self.stop_thread = 1 + break + event = self.agent.create_event(event_msg) self.sender.send_event(event) self.totalMessages += 1 diff --git a/deps/wazuh_testing/wazuh_testing/tools/configuration.py b/deps/wazuh_testing/wazuh_testing/tools/configuration.py index 79166ce962..e0e75b4787 100644 --- a/deps/wazuh_testing/wazuh_testing/tools/configuration.py +++ b/deps/wazuh_testing/wazuh_testing/tools/configuration.py @@ -742,3 +742,21 @@ def update_configuration_template(configurations, old_values, new_values): configurations_to_update = configurations_to_update.replace(old_value, new_value) return json.loads(configurations_to_update) + + +def get_simulate_agent_configuration(data_file_path): + """Load simulate agent configuration file. + + Args: + data_file_path (str): Test case template file path. + + Returns: + dict: Configurations names. + """ + configuration_file = file.read_yaml(data_file_path) + configuration_parameters = {} + + for test_case in configuration_file: + configuration_parameters.update(test_case['configuration_parameters']) + + return configuration_parameters diff --git a/requirements.txt b/requirements.txt index 44203663d8..4895c7e182 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,14 +21,16 @@ py~=1.10.0 pycryptodome>=3.9.8 pyOpenSSL==19.1.0 pytest-html==3.1.1 -pytest==6.2.5 +pytest==6.2.2 ; python_version <= "3.9" +pytest==7.1.2 ; python_version >= "3.10" pyyaml==5.4 requests==2.23.0 scipy>=1.0; platform_system == "Linux" or platform_system == "Darwin" or platform_system=='Windows' seaborn>=0.11.1; platform_system == "Linux" or platform_system == "Darwin" or platform_system=='Windows' setuptools~=56.0.0 testinfra==5.0.0 -jq>=1.1.2; platform_system == "Linux" or platform_system == "Darwin" +jq==1.1.2 ; (platform_system == "Linux" or platform_system == "Darwin") and python_version <= "3.9" +jq==1.2.2 ; python_version >= "3.10" cryptography==3.3.2; platform_system == "Linux" or platform_system == "Darwin" or platform_system=='Windows' urllib3 numpydoc>=1.1.0 diff --git a/tests/integration/test_analysisd/test_eps/conftest.py b/tests/integration/test_analysisd/test_eps/conftest.py new file mode 100644 index 0000000000..712a0ac7ea --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/conftest.py @@ -0,0 +1,159 @@ +# Copyright (C) 2015-2021, Wazuh Inc. +# Created by Wazuh, Inc. . +# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 +import os +import re +import subprocess +import socket +import shutil +from typing import List +import pytest + +from wazuh_testing.tools.services import control_service +from wazuh_testing.tools import configuration, SIMULATE_AGENT, ARCHIVES_LOG_FILE_PATH, ALERT_LOGS_PATH, ALERT_FILE_PATH, ALERT_PATH, WAZUH_INTERNAL_OPTIONS + + +@pytest.fixture(scope='function') +def restart_analysisd_function(): + """Restart wazuh-analysisd daemon before starting a test, and stop it after finishing""" + control_service('restart', daemon='wazuh-analysisd') + yield + control_service('stop', daemon='wazuh-analysisd') + + +@pytest.fixture(scope='session') +def configure_local_internal_options_eps(request): + """Fixture to configure the local internal options file.""" + # Define local internal options for vulnerability detector tests + local_internal_options = {'wazuh_modules.debug': '2', 'monitord.rotate_log': '0',\ + 'analysisd.state_interval': f"{request.param[0]}"} + + # Backup the old local internal options + backup_local_internal_options = configuration.get_wazuh_local_internal_options() + + # Set the new local internal options configuration + configuration.set_wazuh_local_internal_options(configuration.create_local_internal_options(local_internal_options)) + + yield + + # Backup the old local internal options cofiguration + configuration.set_wazuh_local_internal_options(backup_local_internal_options) + + +@pytest.fixture(scope='function') +def set_wazuh_configuration_eps(configuration, set_wazuh_configuration, configure_local_internal_options_eps): + """Set wazuh configuration + + Args: + configuration (dict): Configuration template data to write in the ossec.conf. + set_wazuh_configuration (fixture): Set the wazuh configuration according to the configuration data. + configure_local_internal_options_eps (fixture): Set the local_internal_options.conf file. + """ + yield + + +@pytest.fixture(scope='function') +def simulate_agent(request): + """Fixture to execute the script simulate_agent.py""" + #Get IP address of the host + hostname = socket.gethostname() + IPAddr = socket.gethostbyname(hostname) + + file_excecute = os.path.abspath(SIMULATE_AGENT) + subprocess.call(f"python3 {file_excecute} -a {IPAddr} -n {request.param['num_agent']} \ + -m {request.param['modules']} -s {request.param['eps']} -t {request.param['time']} \ + -f {request.param['msg_size']} -e {request.param['total_msg']} \ + -k {request.param['keepalive_disabled']} -d {request.param['receive_msg_disabled']}", shell=True) + + + yield + + +def delete_folder_content(folder): + """Delete alerts folder content execution""" + for filename in os.listdir(folder): + filepath = os.path.join(folder, filename) + try: + shutil.rmtree(filepath) + except OSError: + os.remove(filepath) + + +@pytest.fixture(scope='function') +def delete_alerts_folder(): + """Delete alerts folder content before and after execution""" + + delete_folder_content(ALERT_PATH) + + yield + + delete_folder_content(ALERT_PATH) + + +def get_wazuh_internal_options() -> List[str]: + """Get current `internal_options.conf` file content. + + Returns + List of str: A list containing all the lines of the `ossec.conf` file. + """ + with open(WAZUH_INTERNAL_OPTIONS) as f: + lines = f.readlines() + return lines + + +def set_wazuh_internal_options(wazuh_local_internal_options: List[str]): + """Set up Wazuh `local_internal_options.conf` file content. + + Returns + List of str: A list containing all the lines of the `local_interal_options.conf` file. + """ + with open(WAZUH_INTERNAL_OPTIONS, 'w') as f: + f.writelines(wazuh_local_internal_options) + + +def change_internal_options(param, value, value_regex='[0-9]*'): + """Change the value of a given parameter in internal_options. + + Args: + param (str): parameter to change. + value (obj): new value. + value_regex (str, optional): regex to match value in local_internal_options.conf. Default '[0-9]*' + """ + add_pattern = True + with open(WAZUH_INTERNAL_OPTIONS, "r") as sources: + lines = sources.readlines() + + with open(WAZUH_INTERNAL_OPTIONS, "w") as sources: + for line in lines: + sources.write( + re.sub(f'{param}={value_regex}', f'{param}={value}', line)) + if param in line: + add_pattern = False + + if add_pattern: + with open(WAZUH_INTERNAL_OPTIONS, "a") as sources: + sources.write(f'\n\n{param}={value}') + + +@pytest.fixture(scope='session') +def configure_internal_options_eps(): + """Fixture to configure the internal options file.""" + + # Backup the old local internal options + backup_internal_options = get_wazuh_internal_options() + + change_internal_options('analysisd.event_threads', '1') + change_internal_options('analysisd.syscheck_threads', '1') + change_internal_options('analysisd.syscollector_threads', '1') + change_internal_options('analysisd.rootcheck_threads', '1') + change_internal_options('analysisd.sca_threads', '1') + change_internal_options('analysisd.hostinfo_threads', '1') + change_internal_options('analysisd.winevt_threads', '1') + change_internal_options('analysisd.rule_matching_threads', '1') + change_internal_options('analysisd.dbsync_threads', '1') + change_internal_options('remoted.worker_pool', '1') + + yield + + # Backup the old local internal options cofiguration + set_wazuh_internal_options(backup_internal_options) diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_simulate_agent.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_simulate_agent.yaml new file mode 100644 index 0000000000..103a7b217c --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_simulate_agent.yaml @@ -0,0 +1,10 @@ +- name: 'Simulate agent params configuration' + description: 'Simulate agent params configuration' + configuration_parameters: + num_agent: '1' + modules: 'logcollector' + eps: '10000' + time: '15' + msg_size: '1' + keepalive_disabled: 'True' + receive_msg_disabled: 'True' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_disabled.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_disabled.yaml new file mode 100644 index 0000000000..3a2efc06f5 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_disabled.yaml @@ -0,0 +1,49 @@ +- sections: + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUN + - timeframe: + value: TIMEFRAME + + - section: remote + elements: + - connection: + value: 'secure' + - port: + value: '1514' + - protocol: + value: 'TCP' + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: syscheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'syscollector' + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'osquery' + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_enabled.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_enabled.yaml new file mode 100644 index 0000000000..3a2efc06f5 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_enabled.yaml @@ -0,0 +1,49 @@ +- sections: + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUN + - timeframe: + value: TIMEFRAME + + - section: remote + elements: + - connection: + value: 'secure' + - port: + value: '1514' + - protocol: + value: 'TCP' + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: syscheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'syscollector' + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'osquery' + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_invalid_values.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_invalid_values.yaml new file mode 100644 index 0000000000..3a2efc06f5 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_invalid_values.yaml @@ -0,0 +1,49 @@ +- sections: + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUN + - timeframe: + value: TIMEFRAME + + - section: remote + elements: + - connection: + value: 'secure' + - port: + value: '1514' + - protocol: + value: 'TCP' + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: syscheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'syscollector' + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'osquery' + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_no_eps_configuration.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_no_eps_configuration.yaml new file mode 100644 index 0000000000..80e983476d --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_no_eps_configuration.yaml @@ -0,0 +1,38 @@ +- sections: + - section: remote + elements: + - connection: + value: 'secure' + - port: + value: '1514' + - protocol: + value: 'TCP' + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: syscheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'syscollector' + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'osquery' + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_process_old_events_instead_new_events.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_process_old_events_instead_new_events.yaml new file mode 100644 index 0000000000..3a2efc06f5 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_process_old_events_instead_new_events.yaml @@ -0,0 +1,49 @@ +- sections: + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUN + - timeframe: + value: TIMEFRAME + + - section: remote + elements: + - connection: + value: 'secure' + - port: + value: '1514' + - protocol: + value: 'TCP' + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: syscheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'syscollector' + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'osquery' + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_start_dropping_events_when_queue_full.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_start_dropping_events_when_queue_full.yaml new file mode 100644 index 0000000000..3a2efc06f5 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_start_dropping_events_when_queue_full.yaml @@ -0,0 +1,49 @@ +- sections: + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUN + - timeframe: + value: TIMEFRAME + + - section: remote + elements: + - connection: + value: 'secure' + - port: + value: '1514' + - protocol: + value: 'TCP' + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: syscheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'syscollector' + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'osquery' + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_start_queuing_events_when_limit_reached.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_start_queuing_events_when_limit_reached.yaml new file mode 100644 index 0000000000..3a2efc06f5 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_start_queuing_events_when_limit_reached.yaml @@ -0,0 +1,49 @@ +- sections: + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUN + - timeframe: + value: TIMEFRAME + + - section: remote + elements: + - connection: + value: 'secure' + - port: + value: '1514' + - protocol: + value: 'TCP' + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: syscheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'syscollector' + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'osquery' + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_stop_processing_events.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_stop_processing_events.yaml new file mode 100644 index 0000000000..3a2efc06f5 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_stop_processing_events.yaml @@ -0,0 +1,49 @@ +- sections: + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUN + - timeframe: + value: TIMEFRAME + + - section: remote + elements: + - connection: + value: 'secure' + - port: + value: '1514' + - protocol: + value: 'TCP' + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: syscheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'syscollector' + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'osquery' + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_without_maximun.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_without_maximun.yaml new file mode 100644 index 0000000000..8a486df331 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_without_maximun.yaml @@ -0,0 +1,47 @@ +- sections: + - section: global + elements: + - limits: + elements: + - eps: + elements: + - timeframe: + value: TIMEFRAME + + - section: remote + elements: + - connection: + value: 'secure' + - port: + value: '1514' + - protocol: + value: 'TCP' + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: syscheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'syscollector' + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'osquery' + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_without_timeframe.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_without_timeframe.yaml new file mode 100644 index 0000000000..34664d09b7 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_without_timeframe.yaml @@ -0,0 +1,47 @@ +- sections: + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUN + + - section: remote + elements: + - connection: + value: 'secure' + - port: + value: '1514' + - protocol: + value: 'TCP' + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: syscheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'syscollector' + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'osquery' + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_without_timeframe_maximun.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_without_timeframe_maximun.yaml new file mode 100644 index 0000000000..dafbd9a40c --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/configuration_without_timeframe_maximun.yaml @@ -0,0 +1,45 @@ +- sections: + - section: global + elements: + - limits: + elements: + - eps: + elements: + + - section: remote + elements: + - connection: + value: 'secure' + - port: + value: '1514' + - protocol: + value: 'TCP' + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: syscheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'syscollector' + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: 'osquery' + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_disabled.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_disabled.yaml new file mode 100644 index 0000000000..fb74cd4c3d --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_disabled.yaml @@ -0,0 +1,8 @@ +- name: 'EPS Limits disabled' + description: 'EPS Limits disabled' + configuration_parameters: + MAXIMUN: '0' + TIMEFRAME: '5' + metadata: + maximun: 0 + timeframe: 5 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_enabled.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_enabled.yaml new file mode 100644 index 0000000000..431925290b --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_enabled.yaml @@ -0,0 +1,8 @@ +- name: 'EPS Limits enabled' + description: 'EPS Limits enabled' + configuration_parameters: + MAXIMUN: '10' + TIMEFRAME: '5' + metadata: + maximun: 10 + timeframe: 5 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_invalid_values.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_invalid_values.yaml new file mode 100644 index 0000000000..53d0df843a --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_invalid_values.yaml @@ -0,0 +1,35 @@ +- name: 'EPS Limits with maximun values over the maximun allowed' + description: 'EPS Limits with maximun values over the maximun allowed' + configuration_parameters: + MAXIMUN: '100001' + TIMEFRAME: '5' + metadata: + maximun: 100001 + timeframe: 5 + +- name: 'EPS Limits with timeframe values over the timeframe allowed' + description: 'EPS Limits with timeframe values over the timeframe allowed' + configuration_parameters: + MAXIMUN: '10' + TIMEFRAME: '3601' + metadata: + maximun: 10 + timeframe: 3601 + +- name: 'EPS Limits with timeframe value 0' + description: 'EPS Limits with timeframe value 0' + configuration_parameters: + MAXIMUN: '10' + TIMEFRAME: '0' + metadata: + maximun: 10 + timeframe: 0 + +- name: 'EPS Limits with maximun and timeframe values 0' + description: 'EPS Limits with maximun and timeframe values 0' + configuration_parameters: + MAXIMUN: '0' + TIMEFRAME: '0' + metadata: + maximun: 0 + timeframe: 0 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_no_eps_configuration.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_no_eps_configuration.yaml new file mode 100644 index 0000000000..58af1f1f3c --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_no_eps_configuration.yaml @@ -0,0 +1,8 @@ +- name: 'EPS Limits disables' + description: 'EPS Limits disables' + configuration_parameters: + MAXIMUN: '0' + TIMEFRAME: '5' + metadata: + maximun: 0 + timeframe: 5 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_process_old_events_multi_thread.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_process_old_events_multi_thread.yaml new file mode 100644 index 0000000000..6eaac1df8a --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_process_old_events_multi_thread.yaml @@ -0,0 +1,8 @@ +- name: 'EPS Limits process old events instead of new ones - Multithread' + description: 'EPS Limits process old events instead of new ones - Multithread' + configuration_parameters: + MAXIMUN: '10' + TIMEFRAME: '5' + metadata: + maximun: 10 + timeframe: 5 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_process_old_events_one_thread.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_process_old_events_one_thread.yaml new file mode 100644 index 0000000000..f019ae79b7 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_process_old_events_one_thread.yaml @@ -0,0 +1,8 @@ +- name: 'EPS Limits process old events instead of new ones - One thread' + description: 'EPS Limits process old events instead of new ones - One thread' + configuration_parameters: + MAXIMUN: '100' + TIMEFRAME: '5' + metadata: + maximun: 100 + timeframe: 5 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_start_dropping_events.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_start_dropping_events.yaml new file mode 100644 index 0000000000..b0c5c2e8ff --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_start_dropping_events.yaml @@ -0,0 +1,8 @@ +- name: 'EPS Limits start dropping events' + description: 'EPS Limits start dropping events' + configuration_parameters: + MAXIMUN: '1' + TIMEFRAME: '5' + metadata: + maximun: 1 + timeframe: 5 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_start_queueing_events.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_start_queueing_events.yaml new file mode 100644 index 0000000000..479e83d025 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_start_queueing_events.yaml @@ -0,0 +1,8 @@ +- name: 'EPS Limits start queueing events' + description: 'EPS Limits start queueing events' + configuration_parameters: + MAXIMUN: '100' + TIMEFRAME: '5' + metadata: + maximun: 100 + timeframe: 5 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_stop_process_events.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_stop_process_events.yaml new file mode 100644 index 0000000000..aa82ebfa68 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_stop_process_events.yaml @@ -0,0 +1,8 @@ +- name: 'EPS Limits stop processing events' + description: 'EPS Limits stop processing events' + configuration_parameters: + MAXIMUN: '100' + TIMEFRAME: '5' + metadata: + maximun: 100 + timeframe: 5 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_without_maximun.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_without_maximun.yaml new file mode 100644 index 0000000000..02f401a024 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_without_maximun.yaml @@ -0,0 +1,6 @@ +- name: 'EPS Limits without maximun value' + description: 'EPS Limits without maximun value' + configuration_parameters: + TIMEFRAME: '5' + metadata: + timeframe: 5 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_without_timeframe.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_without_timeframe.yaml new file mode 100644 index 0000000000..04923c0ed0 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_without_timeframe.yaml @@ -0,0 +1,6 @@ +- name: 'EPS Limits without timeframe value' + description: 'EPS Limits without timeframe value' + configuration_parameters: + MAXIMUN: '500' + metadata: + maximun: 500 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/cases_without_timeframe_maximun.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_without_timeframe_maximun.yaml new file mode 100644 index 0000000000..04923c0ed0 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/cases_without_timeframe_maximun.yaml @@ -0,0 +1,6 @@ +- name: 'EPS Limits without timeframe value' + description: 'EPS Limits without timeframe value' + configuration_parameters: + MAXIMUN: '500' + metadata: + maximun: 500 diff --git a/tests/integration/test_analysisd/test_eps/test_disabled.py b/tests/integration/test_analysisd/test_eps/test_disabled.py new file mode 100644 index 0000000000..783d8cdbbd --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/test_disabled.py @@ -0,0 +1,76 @@ +import os +import pytest + +from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data +from wazuh_testing.modules.eps import event_monitor as evm +from wazuh_testing.modules.eps import ANALYSISD_STATE_INTERNAL_DEFAULT +from wazuh_testing.processes import check_if_deamon_is_running + + +pytestmark = [pytest.mark.server] + +# Reference paths +TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template') +TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases') + +# Configuration and cases data +configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_disabled.yaml') + +t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_disabled.yaml') + +# Disabled test configurations (t1) +t1_configuration_parameters, t1_configuration_metadata, t1_case_ids = get_test_cases_data(t1_cases_path) +t1_configurations = load_configuration_template(configurations_path, t1_configuration_parameters, + t1_configuration_metadata) + + +@pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [ANALYSISD_STATE_INTERNAL_DEFAULT], indirect=True) +def test_disabled(configuration, metadata, set_wazuh_configuration_eps, + truncate_monitored_files, restart_wazuh_daemon_function): + ''' + description: Check that limits EPS is not started when `maximum` is set to a value equal to 0, or with an empty + value, and `timeframe` is set to a value greater than 0 and lower than 3600. + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Check in the log that the EPS limits is disabled. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart all the wazuh daemons. + + assertions: + - Verify that when the `maximum` value is set to 0 or with an empty value and, `timeframe` value is set to a + value greater than 0 and lower than 3600, the module EPS limits is not running. + - Verify that the wazuh-analysisd daemon is running. + + input_description: + - The `cases_disabled.yaml` file provides the module configuration for this test. + + expected_output: + - r'(.*)wazuh-analysisd: INFO: EPS limit disabled' + ''' + evm.check_eps_disabled() + # Check that wazuh-analysisd is running + check_if_deamon_is_running('wazuh-analysisd') diff --git a/tests/integration/test_analysisd/test_eps/test_enabled.py b/tests/integration/test_analysisd/test_eps/test_enabled.py new file mode 100644 index 0000000000..d93d742aff --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/test_enabled.py @@ -0,0 +1,75 @@ +import os +import pytest + +from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data +from wazuh_testing.modules.eps import event_monitor as evm +from wazuh_testing.modules.eps import ANALYSISD_STATE_INTERNAL_DEFAULT +from wazuh_testing.processes import check_if_deamon_is_running + + +pytestmark = [pytest.mark.server] + +# Reference paths +TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template') +TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases') + +# Configuration and cases data +configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_enabled.yaml') +t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_enabled.yaml') + +# Enabled test configurations (t1) +t1_configuration_parameters, t1_configuration_metadata, t1_case_ids = get_test_cases_data(t1_cases_path) +t1_configurations = load_configuration_template(configurations_path, t1_configuration_parameters, + t1_configuration_metadata) + + +@pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [ANALYSISD_STATE_INTERNAL_DEFAULT], indirect=True) +def test_enabled(configuration, metadata, set_wazuh_configuration_eps, + truncate_monitored_files, restart_wazuh_daemon_function): + ''' + description: Check that limits EPS is started when `maximum` is set to a value greater than 0 lower and than 100000, + and `timeframe` is set to a value greater than 0 and lower than 3600. + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Check in the log that the EPS limits is enabled. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart all the wazuh daemons. + + assertions: + - Verify that when the `maximum` value is set to a values greater than 0 and lower than 100000 and, `timeframe` + value is set to a value greater than 0 and lower than 3600, the module EPS limits is running. + - Verify that the wazuh-analysisd daemon is running. + + input_description: + - The `cases_enabled.yaml` file provides the module configuration for this test. + + expected_output: + - r'(.*)wazuh-analysisd: INFO: EPS limit enabled, EPS: (.*), timeframe: (.*)' + ''' + evm.check_eps_enabled(metadata['maximun'], metadata['timeframe']) + # Check that wazuh-analysisd is running + check_if_deamon_is_running('wazuh-analysisd') diff --git a/tests/integration/test_analysisd/test_eps/test_invalid_configuration.py b/tests/integration/test_analysisd/test_eps/test_invalid_configuration.py new file mode 100644 index 0000000000..40c306ffac --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/test_invalid_configuration.py @@ -0,0 +1,200 @@ +import os +import pytest + +from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data +from wazuh_testing.modules.eps import event_monitor as evm +from wazuh_testing.tools.services import control_service +from wazuh_testing.modules.eps import ANALYSISD_STATE_INTERNAL_DEFAULT +from wazuh_testing.processes import check_if_deamon_is_not_running + + +pytestmark = [pytest.mark.server] + +# Reference paths +TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template') +TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases') + +# Configuration and cases data +t1_configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_without_maximun.yaml') +t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_without_maximun.yaml') + +t2_configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_without_timeframe.yaml') +t2_cases_path = os.path.join(TEST_CASES_PATH, 'cases_without_timeframe.yaml') + +t3_configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_without_timeframe_maximun.yaml') +t3_cases_path = os.path.join(TEST_CASES_PATH, 'cases_without_timeframe_maximun.yaml') + +# Test configurations without maximun value (t1) +t1_configuration_parameters, t1_configuration_metadata, t1_case_ids = get_test_cases_data(t1_cases_path) +t1_configurations = load_configuration_template(t1_configurations_path, t1_configuration_parameters, + t1_configuration_metadata) + +# Test configurations without timeframe value (t2) +t2_configuration_parameters, t2_configuration_metadata, t2_case_ids = get_test_cases_data(t2_cases_path) +t2_configurations = load_configuration_template(t2_configurations_path, t2_configuration_parameters, + t2_configuration_metadata) + +# Test configurations without timeframe and maximun values (t3) +t3_configuration_parameters, t3_configuration_metadata, t3_case_ids = get_test_cases_data(t3_cases_path) +t3_configurations = load_configuration_template(t3_configurations_path, t3_configuration_parameters, + t3_configuration_metadata) + + +@pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [ANALYSISD_STATE_INTERNAL_DEFAULT], indirect=True) +def test_without_maximun(configuration, metadata, set_wazuh_configuration_eps, + truncate_monitored_files, restart_wazuh_daemon_after_finishing): + ''' + description: Check that wazuh manager is not started when `maximum` value is not present in the + configuration file. + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Check that wazuh manager does not start. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - restart_wazuh_daemon_after_finishing: + type: fixture + brief: Restart wazuh modules after finishing the test module. + + assertions: + - The error message appears when the `maximum` and/or `timeframe` values have invalid values. + - Verify that the wazuh-analysisd daemon is running. + + input_description: + - The `cases_invalid_value.yaml` file provides the module configuration for this test. + + expected_output: + - r'.*: Configuration error at.*' + ''' + try: + control_service('restart') + except ValueError: + evm.check_configuration_error() + # Check that wazuh-analysisd is not running + check_if_deamon_is_not_running('wazuh-analysisd') + + +@pytest.mark.parametrize('configuration, metadata', zip(t2_configurations, t2_configuration_metadata), ids=t2_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [ANALYSISD_STATE_INTERNAL_DEFAULT], indirect=True) +def test_without_timeframe(configuration, metadata, set_wazuh_configuration_eps, + truncate_monitored_files, restart_wazuh_daemon_after_finishing): + ''' + description: Check that wazuh manager is not started when `timeframe` value is not present in the + configuration file + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Check that wazuh manager does not start. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - restart_wazuh_daemon_after_finishing: + type: fixture + brief: Restart wazuh modules after finishing the test module. + + assertions: + - The error message appears when the `maximum` and/or `timeframe` values have invalid values. + - Verify that the wazuh-analysisd daemon is running. + + input_description: + - The `cases_invalid_value.yaml` file provides the module configuration for this test. + + expected_output: + - r'.*: Configuration error at.*' + ''' + try: + control_service('restart') + except ValueError: + evm.check_configuration_error() + # Check that wazuh-analysisd is not running + check_if_deamon_is_not_running('wazuh-analysisd') + + +@pytest.mark.parametrize('configuration, metadata', zip(t3_configurations, t3_configuration_metadata), ids=t3_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [ANALYSISD_STATE_INTERNAL_DEFAULT], indirect=True) +def test_without_timeframe_maximun(configuration, metadata, set_wazuh_configuration_eps, + truncate_monitored_files, restart_wazuh_daemon_after_finishing): + ''' + description: Check that wazuh manager is not started when `maximum` and/or `timeframe` are not present in the + configuration file. + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Check that wazuh manager does not start. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - restart_wazuh_daemon_after_finishing: + type: fixture + brief: Restart wazuh modules after finishing the test module. + + assertions: + - The error message appears when the `maximum` and/or `timeframe` values have invalid values. + - Verify that the wazuh-analysisd daemon is running. + + input_description: + - The `cases_invalid_value.yaml` file provides the module configuration for this test. + + expected_output: + - r'.*: Configuration error at.*' + ''' + try: + control_service('restart') + except ValueError: + evm.check_configuration_error() + # Check that wazuh-analysisd is not running + check_if_deamon_is_not_running('wazuh-analysisd') diff --git a/tests/integration/test_analysisd/test_eps/test_invalid_values.py b/tests/integration/test_analysisd/test_eps/test_invalid_values.py new file mode 100644 index 0000000000..245df33ddd --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/test_invalid_values.py @@ -0,0 +1,78 @@ +import os +import pytest + +from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data +from wazuh_testing.modules.eps import event_monitor as evm +from wazuh_testing.tools.services import control_service +from wazuh_testing.modules.eps import ANALYSISD_STATE_INTERNAL_DEFAULT +from wazuh_testing.processes import check_if_deamon_is_not_running + + +pytestmark = [pytest.mark.server] + +# Reference paths +TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template') +TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases') + +# Configuration and cases data +configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_invalid_values.yaml') + +t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_invalid_values.yaml') + +# Invalid value test configurations (t1) +t1_configuration_parameters, t1_configuration_metadata, t1_case_ids = get_test_cases_data(t1_cases_path) +t1_configurations = load_configuration_template(configurations_path, t1_configuration_parameters, + t1_configuration_metadata) + + +@pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [ANALYSISD_STATE_INTERNAL_DEFAULT], indirect=True) +def test_invalid_values(configuration, metadata, set_wazuh_configuration_eps, + truncate_monitored_files, restart_wazuh_daemon_after_finishing): + ''' + description: Check that wazuh manager is not started when an invalid value is set to `maximum` and/or `timeframe`. + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Check that wazuh manager does not start. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - restart_wazuh_daemon_after_finishing: + type: fixture + brief: Restart wazuh modules after finishing the test module. + + assertions: + - The error message appears when the `maximum` and/or `timeframe` values have invalid values. + - Verify that the wazuh-analysisd daemon is running. + + input_description: + - The `cases_invalid_value.yaml` file provides the module configuration for this test. + + expected_output: + - r'.*: Configuration error at.*' + ''' + try: + control_service('restart') + except ValueError: + evm.check_configuration_error() + # Check that wazuh-analysisd is not running + check_if_deamon_is_not_running('wazuh-analysisd') diff --git a/tests/integration/test_analysisd/test_eps/test_no_eps_configuration.py b/tests/integration/test_analysisd/test_eps/test_no_eps_configuration.py new file mode 100644 index 0000000000..02990fbe4e --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/test_no_eps_configuration.py @@ -0,0 +1,136 @@ +import os +from time import sleep +import pytest + +from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data, \ +get_simulate_agent_configuration +from wazuh_testing.modules.eps import event_monitor as evm +from wazuh_testing.modules.eps import ANALYSISD_STATE_INTERNAL_DEFAULT, PERCENTAGE_PROCESS_MSGS + + +pytestmark = [pytest.mark.server] + +# Reference paths +TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template') +TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases') +# Configuration and cases data +configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_no_eps_configuration.yaml') +configurations_simulate_agent_path = os.path.join(TEST_DATA_PATH, + 'configuration_simulate_agent.yaml') +t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_no_eps_configuration.yaml') + +# Enabled test configurations (t1) +t1_configuration_parameters, t1_configuration_metadata, t1_case_ids = get_test_cases_data(t1_cases_path) +t1_configurations = load_configuration_template(configurations_path, t1_configuration_parameters, + t1_configuration_metadata) + +# Get simulate agent configurations (t1) +params_disabled_eps = get_simulate_agent_configuration(configurations_simulate_agent_path) +timeframe_eps_t1 = [metadata['timeframe'] for metadata in t1_configuration_metadata] +total_msg = 1000 # of 1Kb message of 16384 Kb of queue size +params_disabled_eps.update({'total_msg': total_msg}) + + +@pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [ANALYSISD_STATE_INTERNAL_DEFAULT], indirect=True) +def test_disabled(configuration, metadata, set_wazuh_configuration_eps, + truncate_monitored_files, restart_wazuh_daemon_function): + ''' + description: Check that limits EPS is disabled when it is not configured. + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Check in the log that the EPS limits is disabled. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart all the wazuh daemons. + + assertions: + - Verify that when the `maximum` value is set to 0 or with an empty value and, `timeframe` value is set to a + value greater than 0 and lower than 3600, the module EPS limits is not running. + + input_description: + - The `cases_no_eps_configuration.yaml` file provides the module configuration for this test. + + expected_output: + - r'(.*)wazuh-analysisd: INFO: EPS limit disabled' + ''' + evm.check_eps_disabled() + + +@pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [timeframe_eps_t1], indirect=True) +@pytest.mark.parametrize('simulate_agent', [params_disabled_eps], indirect=True) +def test_without_eps_setting(configuration, metadata, set_wazuh_configuration_eps, + truncate_monitored_files, restart_wazuh_daemon_function, simulate_agent): + ''' + description: Check that limits EPS is disabled when it is not configured and the received events are similar or + equal to the processed events. + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Check in the log that the EPS limits is disabled. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart all the wazuh daemons. + - simulate_agent: + type: fixture + brief: Execute a script that simulate agent and send `logcolector` logs to the manager. + + assertions: + - Verify the events_received are equal or greater than a porcentage of events_processed. + + input_description: + - The `cases_disabled.yaml` file provides the module configuration for this test. + + expected_output: + - r'(.*)wazuh-analysisd: INFO: EPS limit disabled' + ''' + # Wait 'timeframe' / 2 second to read the wazuh-analysisd.state to ensure that has corrects values + sleep(metadata['timeframe'] / 2) + events_processed = evm.get_analysisd_state('events_processed') + events_received = evm.get_analysisd_state('events_received') + # There are some internal event that are processed but not are reflected in events_received, That why it has been used PERCENTAGE_PROCESS_MSGS variable + assert events_processed >= events_received * PERCENTAGE_PROCESS_MSGS and \ + events_processed > 0, 'The events_processed value is similar to events_received' diff --git a/tests/integration/test_analysisd/test_eps/test_process_old_events_instead_new_events.py b/tests/integration/test_analysisd/test_eps/test_process_old_events_instead_new_events.py new file mode 100644 index 0000000000..46aab15107 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/test_process_old_events_instead_new_events.py @@ -0,0 +1,206 @@ +import os +from time import sleep +from datetime import datetime +import pytest + +from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data, \ +get_simulate_agent_configuration +from wazuh_testing.modules.eps import event_monitor as evm + + +pytestmark = [pytest.mark.server] + +# Reference paths +TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template') +TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases') + +# Configuration and cases data +configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_process_old_events_instead_new_events.yaml') +configurations_simulate_agent_path = os.path.join(TEST_DATA_PATH, + 'configuration_simulate_agent.yaml') +t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_process_old_events_one_thread.yaml') +t2_cases_path = os.path.join(TEST_CASES_PATH, 'cases_process_old_events_multi_thread.yaml') + +# Process old events instead of new ones test configurations multi thread (t1) +t1_configuration_parameters, t1_configuration_metadata, t1_case_ids = get_test_cases_data(t1_cases_path) +t1_configurations = load_configuration_template(configurations_path, t1_configuration_parameters, + t1_configuration_metadata) + +# Process old events instead of new ones test configurations one thread (t2) +t2_configuration_parameters, t2_configuration_metadata, t2_case_ids = get_test_cases_data(t2_cases_path) +t2_configurations = load_configuration_template(configurations_path, t2_configuration_parameters, + t2_configuration_metadata) + +# Get simulate agent configurations (t1) +params_process_old_events_one_thread = get_simulate_agent_configuration(configurations_simulate_agent_path) +timeframe_eps_t1 = [metadata['timeframe'] for metadata in t1_configuration_metadata] +total_msg = 10000 # of 1Kb message of 16384 Kb of queue size +params_process_old_events_one_thread.update({'total_msg': total_msg}) + +# Get simulate agent configurations (t2) +params_process_old_events_multithread = get_simulate_agent_configuration(configurations_simulate_agent_path) +maximun_eps_t2 = [metadata['maximun'] for metadata in t2_configuration_metadata] +timeframe_eps_t2 = [metadata['timeframe'] for metadata in t2_configuration_metadata] +# It is sent `width_frame` time frame width to reduce test time execution +frame_width = 3 +total_msg = maximun_eps_t2[0] * timeframe_eps_t2[0] * frame_width +params_process_old_events_multithread.update({'total_msg': total_msg}) + +@pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [timeframe_eps_t1], indirect=True) +@pytest.mark.parametrize('simulate_agent', [params_process_old_events_one_thread], indirect=True) +def test_process_old_events_one_thread(configuration, metadata, set_wazuh_configuration_eps, + configure_internal_options_eps, truncate_monitored_files, + delete_alerts_folder, restart_wazuh_daemon_function, simulate_agent): + ''' + description: Check that `wazuh-analysisd` processes queued events first instead of new events when the moving + average frees up some space. To do this, read the alerts.log file and find the numerated alerts + messages and gets the timestamp. The oldest message must have lower timestamp. To do so, first it must + set the `internal_options.conf` file to work with one thread, otherwise the message are not in the + increasing order. + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Execute agent simulated script. + - Check alerts.log file. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - configure_internal_options_eps: + type: fixture + brief: Set the wazuh internal option configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - delete_alerts_folder: + type: fixture + brief: Delete all the content od the /var/log/alerts folder. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart all the wazuh daemons. + - simulate_agent: + type: fixture + brief: Execute a script that simulate agent and send `logcolector` logs to the manager. + + assertions: + - The timestamp of the oldest numerated messages have to be lower than he new messages. + + input_description: + - The `cases_process_old_events_one_thread.yaml` file provides the module configuration for this test. + ''' + # Set logcollector message that the agent sents + logcollector_message = 'Invalid user random_user from 172.17.1.1 port 56550:Message number:' + # Set the alerts start message + start_alert_msg = '** Alert ' + # Initial timestamp to compare + timestamp_bkp = datetime.fromtimestamp(float(0.0)).strftime('%Y-%m-%d %H:%M:%S') + # Factor to iterate the alerts.log file to reduce the test execution time + time_events_processed = 5 + + # Wait 'timeframe' / 2 second to read the wazuh-analysisd.state to ensure that has corrects values + sleep(metadata['timeframe'] / 2) + events_processed = int(evm.get_analysisd_state('events_processed')) + events_received = int(evm.get_analysisd_state('events_received')) + + # Check that the timestamp of the message in the alerts.log is lower than the next one + # In order to reduce the test time execution, It will check {time_events_processed} consecutive timeframe + # by checking events_processed * time_events_processed + if(events_processed * time_events_processed <= events_received): + for index in range((events_processed * time_events_processed) - 1): + # Get the timestamp of the log + timestamp = evm.get_alert_timestamp(start_alert_msg, f"{logcollector_message} {index}") + # Check that the timestamp of the first message y lower than the previous one + assert timestamp >= timestamp_bkp, 'The timestamp of the previous message has to be lower than the '\ + 'next one' + # Store the timestamp to be compared with the next one + timestamp_bkp = timestamp + else: + raise Exception('Not enough messages were sent. Please increase the `total_msg` for ' \ + 'this test.') + + +@pytest.mark.parametrize('configuration, metadata', zip(t2_configurations, t2_configuration_metadata), ids=t2_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [timeframe_eps_t2], indirect=True) +@pytest.mark.parametrize('simulate_agent', [params_process_old_events_multithread], indirect=True) +def test_process_old_events_multi_thread(configuration, metadata, set_wazuh_configuration_eps, + truncate_monitored_files, delete_alerts_folder, + restart_wazuh_daemon_function, simulate_agent): + ''' + description: Check that `wazuh-analysisd` processes queued events first instead of new events when the moving + average frees up some space. To do this, read the alerts.log file and find the numerated alerts + messages with the FileMonitor tool. To do so, it iterates the `n` frames of `maximun` * `timeframe` and + checks if the message number belongs to the respective frame. + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Execute agent simulated script. + - Check alerts.log file. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - configure_internal_options_eps: + type: fixture + brief: Set the wazuh internal option configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - delete_alerts_folder: + type: fixture + brief: Delete all the content od the /var/log/alerts folder. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart all the wazuh daemons. + - simulate_agent: + type: fixture + brief: Execute a script that simulate agent and send `logcolector` logs to the manager. + + assertions: + - The timestamp of the oldest numerated messages have to be lower than he new messages. + + input_description: + - The `cases_process_old_events_multi_thread.yaml` file provides the module configuration for this test. + ''' + # Set logcollector message that the agent sents + logcollector_message = 'Invalid user random_user from 172.17.1.1 port 56550:Message number:' + # Wait 'timeframe' / 2 second to read the wazuh-analysisd.state to ensure that has corrects values + sleep(metadata['timeframe'] / 2) + events_received = evm.get_analysisd_state('events_received') + index = 0 + frame = metadata['timeframe'] * metadata['maximun'] + # Iterate over each frame to find the respective numerated message belongs to the frame + while (index + 1) * frame <= events_received: + start_index = index * frame + end_index = (index + 1) * frame + # Iterate over the frame to find the respective numerated message + for msg_number in range(start_index, end_index): + evm.get_msg_with_number(fr".*{logcollector_message} {msg_number}") + index += 1 diff --git a/tests/integration/test_analysisd/test_eps/test_start_dropping_events_when_queue_full.py b/tests/integration/test_analysisd/test_eps/test_start_dropping_events_when_queue_full.py new file mode 100644 index 0000000000..bd5ea25e34 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/test_start_dropping_events_when_queue_full.py @@ -0,0 +1,114 @@ +import os +from time import sleep +from datetime import datetime +import pytest + +from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data, \ +get_simulate_agent_configuration +from wazuh_testing.modules.eps import event_monitor as evm +from wazuh_testing.modules.eps import PERCENTAGE_PROCESS_MSGS, QUEUE_SIZE + + +pytestmark = [pytest.mark.server] + +# Reference paths +TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template') +TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases') + +# Configuration and cases data +configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_start_dropping_events_when_queue_full.yaml') +configurations_simulate_agent_path = os.path.join(TEST_DATA_PATH, + 'configuration_simulate_agent.yaml') +t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_start_dropping_events.yaml') + + +# Start dropping events test configurations (t1) +t1_configuration_parameters, t1_configuration_metadata, t1_case_ids = get_test_cases_data(t1_cases_path) +t1_configurations = load_configuration_template(configurations_path, t1_configuration_parameters, + t1_configuration_metadata) + +# Get simulate agent configurations (t1) +params_start_dropping_events_when_queue_full = get_simulate_agent_configuration(configurations_simulate_agent_path) +timeframe_eps_t1 = [metadata['timeframe'] for metadata in t1_configuration_metadata] +total_msg = 16500 # of 1Kb message of 16384 Kb of queue size. Total dropped aproximatelly 116 +expected_msg_dropped = total_msg - QUEUE_SIZE +params_start_dropping_events_when_queue_full.update({'total_msg': total_msg}) + + +@pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [timeframe_eps_t1], indirect=True) +@pytest.mark.parametrize('simulate_agent', [params_start_dropping_events_when_queue_full], indirect=True) +def test_start_dropping_events_when_queue_full(configuration, metadata, set_wazuh_configuration_eps, + truncate_monitored_files, restart_wazuh_daemon_function, + simulate_agent): + ''' + description: Check that the `events_dropped` value in the `/var/ossec/var/run/wazuh-analysisd.state` file must + be greater than 1 and, `event_queue_usage` is equal to 1 + than 1.0. + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Execute agent simulated script. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart all the wazuh daemons. + - simulate_agent: + type: fixture + brief: Execute a script that simulate agent and send `logcolector` logs to the manager. + + assertions: + - The `events_processed` value in the `/var/ossec/var/run/wazuh-analysisd.state` file must be lower or equal + than `maximun` * `timeframe` and greater than a percentage of `maximun` * `timeframe` to confirm that + `events_processed` is not null. The `events_received` value must be greater than `events_processed` and, + the `events_dropped` value greater than 0 and finaly, `event_queue_usage` is equal to 1.0. + + input_description: + - The `cases_start_queueing_events.yaml` file provides the module configuration for this test. + ''' + # Wait 'timeframe' / 2 second to read the wazuh-analysisd.state to ensure that has corrects values + sleep(metadata['timeframe'] / 2) + events_processed = evm.get_analysisd_state('events_processed') + events_received = evm.get_analysisd_state('events_received') + events_dropped = evm.get_analysisd_state('events_dropped') + event_queue_usage = evm.get_analysisd_state('event_queue_usage') + + # Check that processed events reach the EPS limit + assert events_processed <= float(metadata['maximun'] * metadata['timeframe']) and \ + events_processed >= float(metadata['maximun'] * metadata['timeframe']) * PERCENTAGE_PROCESS_MSGS, \ + 'events_processed must be lower or equal to maximun * timeframe' + + # Check that events continue receiving although the EPS limit was reached + assert events_received > events_processed, 'events_received must be bigger than events_processed' + + # Check that there is no event dropped and the queue usage is less than 1.0 (100%). This means the queue is not full + assert events_dropped >= int(expected_msg_dropped * PERCENTAGE_PROCESS_MSGS) \ + and events_dropped <= int(expected_msg_dropped * (1 + (1 - PERCENTAGE_PROCESS_MSGS))), 'events_dropped must be '\ + 'in the range of (total_msg - QUEUE_SIZE)' + + # Check that there is no event dropped and the queue usage is less than 1.0 (100%). This means the queue is not full + assert event_queue_usage == 1.0, 'event_queue_usage must be 1.0' + + # Check that events_dropped are in the range of events_received - events_processed + assert events_processed <= events_received - events_dropped, 'events_processed must be lower than' \ + 'events_received - events_dropped' \ No newline at end of file diff --git a/tests/integration/test_analysisd/test_eps/test_start_queuing_events_when_limit_reached.py b/tests/integration/test_analysisd/test_eps/test_start_queuing_events_when_limit_reached.py new file mode 100644 index 0000000000..9f784aced0 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/test_start_queuing_events_when_limit_reached.py @@ -0,0 +1,111 @@ +import os +from time import sleep +from datetime import datetime +import pytest + +from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data, \ +get_simulate_agent_configuration +from wazuh_testing.modules.eps import event_monitor as evm +from wazuh_testing.modules.eps import PERCENTAGE_PROCESS_MSGS, QUEUE_SIZE + + +pytestmark = [pytest.mark.server] + +# Reference paths +TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template') +TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases') + +# Configuration and cases data +configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_start_queuing_events_when_limit_reached.yaml') +configurations_simulate_agent_path = os.path.join(TEST_DATA_PATH, + 'configuration_simulate_agent.yaml') +t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_start_queueing_events.yaml') + +# Start queueing events test configurations (t1) +t1_configuration_parameters, t1_configuration_metadata, t1_case_ids = get_test_cases_data(t1_cases_path) +t1_configurations = load_configuration_template(configurations_path, t1_configuration_parameters, + t1_configuration_metadata) + +# Get simulate agent configurations (t1) +params_start_queuing_events_when_limit_reached = get_simulate_agent_configuration(configurations_simulate_agent_path) +maximun_eps = [metadata['maximun'] for metadata in t1_configuration_metadata] +timeframe_eps_t1 = [metadata['timeframe'] for metadata in t1_configuration_metadata] +# It is sent `width_frame` time frame width to reduce test time execution +width_frame = 3 +total_msg = maximun_eps[0] * timeframe_eps_t1[0] * width_frame +if total_msg > QUEUE_SIZE: + total_msg = QUEUE_SIZE - 1 +params_start_queuing_events_when_limit_reached.update({'total_msg': total_msg}) + + +@pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [timeframe_eps_t1], indirect=True) +@pytest.mark.parametrize('simulate_agent', [params_start_queuing_events_when_limit_reached], indirect=True) +def test_start_queuing_events_when_limit_reached(configuration, metadata, set_wazuh_configuration_eps, + truncate_monitored_files, restart_wazuh_daemon_function, + simulate_agent): + ''' + description: Check that the `events_processed` value in the `/var/ossec/var/run/wazuh-analysisd.state` file must + be lower or equal than `maximun` * `timeframe` and, the `events_received` value must be greater than + `events_processed` and, the `events_dropped` value equal to 0 and finaly, `event_queue_usage` is lower + than 1.0. + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Execute agent simulated script. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart all the wazuh daemons. + - simulate_agent: + type: fixture + brief: Execute a script that simulate agent and send `logcolector` logs to the manager. + + assertions: + - The `events_processed` value in the `/var/ossec/var/run/wazuh-analysisd.state` file must be lower or equal + than `maximun` * `timeframe` and greater than a percentage of `maximun` * `timeframe` to confirm that + `events_processed` is not null. The `events_received` value must be greater than `events_processed` and, + the `events_dropped` value equal to 0 and finaly, `event_queue_usage` is lower than 1.0. + + input_description: + - The `cases_start_queueing_events.yaml` file provides the module configuration for this test. + ''' + # Wait 'timeframe' / 2 second to read the wazuh-analysisd.state to ensure that has corrects values + sleep(metadata['timeframe'] / 2) + events_processed = evm.get_analysisd_state('events_processed') + events_received = evm.get_analysisd_state('events_received') + events_dropped = evm.get_analysisd_state('events_dropped') + event_queue_usage = evm.get_analysisd_state('event_queue_usage') + + # Check that processed events reach the EPS limit + assert events_processed <= float(metadata['maximun'] * metadata['timeframe']) and \ + events_processed >= float(metadata['maximun'] * metadata['timeframe']) * PERCENTAGE_PROCESS_MSGS, \ + 'events_processed must be lower or equal to maximun * timeframe' + + # Check that events continue receiving although the EPS limit was reached + assert events_received > events_processed, 'events_received must be bigger than events_processed' + + # Check that there are not events dropped and the queue usage is less than 1.0 (100%). + # This means the queue is not full + assert events_dropped == 0 and event_queue_usage < 1.0 and event_queue_usage > 0.0, 'events_dropped must be 0 ' \ + 'and event_queue_usage less than 1.0' diff --git a/tests/integration/test_analysisd/test_eps/test_stop_processing_events.py b/tests/integration/test_analysisd/test_eps/test_stop_processing_events.py new file mode 100644 index 0000000000..85fe1d1722 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/test_stop_processing_events.py @@ -0,0 +1,94 @@ +import os +from time import sleep +from datetime import datetime +import pytest + +from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data, \ +get_simulate_agent_configuration +from wazuh_testing.modules.eps import event_monitor as evm +from wazuh_testing.modules.eps import PERCENTAGE_PROCESS_MSGS, QUEUE_SIZE + + +pytestmark = [pytest.mark.server] + +# Reference paths +TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template') +TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases') + +# Configuration and cases data +configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_stop_processing_events.yaml') +configurations_simulate_agent_path = os.path.join(TEST_DATA_PATH, + 'configuration_simulate_agent.yaml') +t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_stop_process_events.yaml') + +# Stop processing events test configurations (t1) +t1_configuration_parameters, t1_configuration_metadata, t1_case_ids = get_test_cases_data(t1_cases_path) +t1_configurations = load_configuration_template(configurations_path, t1_configuration_parameters, + t1_configuration_metadata) + +# Get simulate agent configurations (t1) +params_stop_processing_events = get_simulate_agent_configuration(configurations_simulate_agent_path) +maximun_eps = [metadata['maximun'] for metadata in t1_configuration_metadata] +timeframe_eps_t1 = [metadata['timeframe'] for metadata in t1_configuration_metadata] +total_msg = maximun_eps[0] * timeframe_eps_t1[0] * 3 +if total_msg > QUEUE_SIZE: + total_msg = QUEUE_SIZE - 1 +params_stop_processing_events.update({'total_msg': total_msg}) + + +@pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_eps', [timeframe_eps_t1], indirect=True) +@pytest.mark.parametrize('simulate_agent', [params_stop_processing_events], indirect=True) +def test_stops_processing_events(configuration, metadata, set_wazuh_configuration_eps, truncate_monitored_files, + restart_wazuh_daemon_function, simulate_agent): + ''' + description: Check that the `events_processed` value in the `/var/ossec/var/run/wazuh-analysisd.state` file must + be lower or equal than `maximun` * `timeframe` + + test_phases: + - Set a custom Wazuh configuration. + - Truncate logs files. + - Restart wazuh-daemons. + - Execute agent simulated script. + + wazuh_min_version: 4.4.0 + + tier: 0 + + parameters: + - configuration: + type: dict + brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture. + - metadata: + type: dict + brief: Wazuh configuration metadata. + - set_wazuh_configuration_eps: + type: fixture + brief: Set the wazuh configuration according to the configuration data. + - truncate_monitored_files: + type: fixture + brief: Truncate all the log files and json alerts files before and after the test execution. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart all the wazuh daemons. + - simulate_agent: + type: fixture + brief: Execute a script that simulate agent and send `logcolector` logs to the manager. + + assertions: + - The `events_processed` value in the `/var/ossec/var/run/wazuh-analysisd.state` file must be lower or equal + than `maximun` * `timeframe` and greater than a percentage of `maximun` * `timeframe` to confirm that + `events_processed` is not null. + + input_description: + - The `cases_stop_process_events.yaml` file provides the module configuration for this test. + ''' + # Wait 'timeframe' / 2 second to read the wazuh-analysisd.state to ensure that has corrects values + sleep(metadata['timeframe'] / 2) + events_processed = evm.get_analysisd_state('events_processed') + + # Check that processed events reach the EPS limit + assert events_processed <= float(metadata['maximun'] * metadata['timeframe']) and \ + events_processed >= float(metadata['maximun'] * metadata['timeframe']) * PERCENTAGE_PROCESS_MSGS, \ + 'events_processed must be lower or equal to maximun * timeframe'