diff --git a/deps/wazuh_testing/wazuh_testing/tools/__init__.py b/deps/wazuh_testing/wazuh_testing/tools/__init__.py index 811fb23fe2..f160b5c63c 100644 --- a/deps/wazuh_testing/wazuh_testing/tools/__init__.py +++ b/deps/wazuh_testing/wazuh_testing/tools/__init__.py @@ -27,6 +27,9 @@ WAZUH_SOURCES = os.path.join('/', 'wazuh') + WAZUH_UNIX_USER = 'wazuh' + WAZUH_UNIX_GROUP = 'wazuh' + if sys.platform == 'darwin': WAZUH_PATH = os.path.join("/", "Library", "Ossec") PREFIX = os.path.join('/', 'private', 'var', 'root') @@ -53,8 +56,8 @@ import grp import pwd - WAZUH_UID = pwd.getpwnam("wazuh").pw_uid - WAZUH_GID = grp.getgrnam("wazuh").gr_gid + WAZUH_UID = pwd.getpwnam(WAZUH_UNIX_USER).pw_uid + WAZUH_GID = grp.getgrnam(WAZUH_UNIX_GROUP).gr_gid except (ImportError, KeyError, ModuleNotFoundError): pass @@ -86,6 +89,9 @@ def get_service(): _data_path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'data') +LOCAL_RULES_PATH = os.path.join(WAZUH_PATH, 'etc', 'rules', 'local_rules.xml') +LOCAL_DECODERS_PATH = os.path.join(WAZUH_PATH, 'etc', 'decoders', 'local_decoder.xml') + CLIENT_KEYS_PATH = os.path.join(WAZUH_PATH, 'etc', 'client.keys') SERVER_KEY_PATH = os.path.join(WAZUH_PATH, 'etc', 'manager.key') SERVER_CERT_PATH = os.path.join(WAZUH_PATH, 'etc', 'manager.cert') @@ -108,6 +114,7 @@ def get_service(): AUTHD_SOCKET_PATH = os.path.join(QUEUE_SOCKETS_PATH, 'auth') EXECD_SOCKET_PATH = os.path.join(QUEUE_SOCKETS_PATH, 'com') LOGCOLLECTOR_SOCKET_PATH = os.path.join(QUEUE_SOCKETS_PATH, 'logcollector') +LOGTEST_SOCKET_PATH = os.path.join(QUEUE_SOCKETS_PATH, 'logtest') MONITORD_SOCKET_PATH = os.path.join(QUEUE_SOCKETS_PATH, 'monitor') REMOTED_SOCKET_PATH = os.path.join(QUEUE_SOCKETS_PATH, 'request') SYSCHECKD_SOCKET_PATH = os.path.join(QUEUE_SOCKETS_PATH, 'syscheck') diff --git a/docs/tests/integration/test_logtest/test_log_process_options/test_rules_verbose.md b/docs/tests/integration/test_logtest/test_log_process_options/test_rules_verbose.md new file mode 100644 index 0000000000..e3684ab436 --- /dev/null +++ b/docs/tests/integration/test_logtest/test_log_process_options/test_rules_verbose.md @@ -0,0 +1,33 @@ +# Test log process options - Rules verbose +## Overview + +Check if `wazuh-logtest` works correctly in `verbose` mode for rules debugging + +## Objective + +- To confirm that `wazuh-logtest` does not do rule debugging when the rules_debug field is omitted +- To confirm that `wazuh-logtest` does not do rule debugging when the rules_debug field is set to false +- To confirm that `wazuh-logtest` does not do rule debugging when the rules_debug field is set to a bad type (string) +- To confirm that `wazuh-logtest` does not do rule debugging when the rules_debug field is set to a bad type (number) +- To confirm that `wazuh-logtest` does not do rule debugging when the rules_debug field is set to a bad type (object) +- To confirm that `wazuh-logtest` does not do rule debugging when the rules_debug field is set to a bad type (array) +- To confirm that `wazuh-logtest` does not do rule debugging when the options field is set to a bad type (boolean) +- To confirm that `wazuh-logtest` does not do rule debugging when the options field is set to a bad type (array) +- To confirm that `wazuh-logtest` does not do rule debugging when the options field is set to a bad type (number) +- To confirm that `wazuh-logtest` does not do rule debugging when the options field is set to a bad type (string) +- To confirm that `wazuh-logtest` does rule debugging when the rules_debug field is set to true + +## General info + +|Tier | Number of tests | Time spent | +|:--:|:--:|:--:| +| 0 | 11 | 10s | + +## Expected behavior + +- Pass if `wazuh-logtest` returns rule debugging information when parameters are correct +- Pass if `wazuh-logtest` does not return rule debugging information when parameters are incorrect. + +## Code documentation + +::: tests.integration.test_logtest.test_options.test_log_process_options.test_rules_verbose diff --git a/tests/integration/test_logtest/test_log_process_options/data/rules_verbose.xml b/tests/integration/test_logtest/test_log_process_options/data/rules_verbose.xml new file mode 100644 index 0000000000..b42c8685c8 --- /dev/null +++ b/tests/integration/test_logtest/test_log_process_options/data/rules_verbose.xml @@ -0,0 +1,28 @@ + + + + + json + rules_verbose + Parent rules verbose + + + + 880000 + ^last_match$ + test last_match + + + + 880001 + ^ok$ + test_child test_child + + + diff --git a/tests/integration/test_logtest/test_log_process_options/data/rules_verbose.yaml b/tests/integration/test_logtest/test_log_process_options/data/rules_verbose.yaml new file mode 100644 index 0000000000..3b66da65c5 --- /dev/null +++ b/tests/integration/test_logtest/test_log_process_options/data/rules_verbose.yaml @@ -0,0 +1,74 @@ +--- +- + name: 'rules_debug_omitted' + rule_file: 'rules_verbose.xml' + rule_id: '880002' + input: '{"version":1,"origin":{"name":"Integration Test","module":"api"},"command":"log_processing","parameters":{"event": "{\"it_logtest\" : \"rules_verbose\", \"test\": \"last_match\", \"test_child\" : \"ok\"}","log_format": "syslog","location": "master->/var/log/syslog"}}' +- + name: 'rules_debug_true' + rule_file: 'rules_verbose.xml' + rule_id: '880001' + input: '{"version":1,"origin":{"name":"Integration Test","module":"api"},"command":"log_processing","parameters":{"event": "{\"it_logtest\" : \"rules_verbose\", \"test\": \"last_match\"}","log_format": "syslog","location": "master->/var/log/syslog","options":{"rules_debug":true}}}' + verbose_mode: True +- + name: 'rules_debug_false' + rule_file: 'rules_verbose.xml' + rule_id: '880001' + input: '{"version":1,"origin":{"name":"Integration Test","module":"api"},"command":"log_processing","parameters":{"event": "{\"it_logtest\" : \"rules_verbose\", \"test\": \"last_match\"}","log_format": "syslog","location": "master->/var/log/syslog","options":{"rules_debug":false}}}' + verbose_mode: False +- + name: 'rules_debug_bad_type_string' + rule_file: 'rules_verbose.xml' + rule_id: '880001' + input: '{"version":1,"origin":{"name":"Integration Test","module":"api"},"command":"log_processing","parameters":{"event": "{\"it_logtest\" : \"rules_verbose\", \"test\": \"last_match\"}","log_format": "syslog","location": "master->/var/log/syslog","options":{"rules_debug":"true"}}}' + verbose_mode: False + warning_message: "WARNING: \\(\\d+\\): 'rules_debug' field must be a boolean. The parameter will be ignored" +- + name: 'rules_debug_bad_type_number' + rule_file: 'rules_verbose.xml' + rule_id: '880001' + input: '{"version":1,"origin":{"name":"Integration Test","module":"api"},"command":"log_processing","parameters":{"event": "{\"it_logtest\" : \"rules_verbose\", \"test\": \"last_match\"}","log_format": "syslog","location": "master->/var/log/syslog","options":{"rules_debug":123}}}' + verbose_mode: False + warning_message: "WARNING: \\(\\d+\\): 'rules_debug' field must be a boolean. The parameter will be ignored" +- + name: 'rules_debug_bad_type_object' + rule_file: 'rules_verbose.xml' + rule_id: '880001' + input: '{"version":1,"origin":{"name":"Integration Test","module":"api"},"command":"log_processing","parameters":{"event": "{\"it_logtest\" : \"rules_verbose\", \"test\": \"last_match\"}","log_format": "syslog","location": "master->/var/log/syslog","options":{"rules_debug":{"test":"true"}}}}' + verbose_mode: False + warning_message: "WARNING: \\(\\d+\\): 'rules_debug' field must be a boolean. The parameter will be ignored" +- + name: 'rules_debug_bad_type_array' + rule_file: 'rules_verbose.xml' + rule_id: '880001' + input: '{"version":1,"origin":{"name":"Integration Test","module":"api"},"command":"log_processing","parameters":{"event": "{\"it_logtest\" : \"rules_verbose\", \"test\": \"last_match\"}","log_format": "syslog","location": "master->/var/log/syslog","options":{"rules_debug":["true", "false"]}}}' + verbose_mode: False + warning_message: "WARNING: \\(\\d+\\): 'rules_debug' field must be a boolean. The parameter will be ignored" +- + name: 'options_bad_type_boolean' + rule_file: 'rules_verbose.xml' + rule_id: '880001' + input: '{"version":1,"origin":{"name":"Integration Test","module":"api"},"command":"log_processing","parameters":{"event": "{\"it_logtest\" : \"rules_verbose\", \"test\": \"last_match\"}","log_format": "syslog","location": "master->/var/log/syslog","options":true}}' + verbose_mode: False + warning_message: "WARNING: \\(\\d+\\): 'options' field must be a JSON object. The parameter will be ignored" +- + name: 'options_bad_type_array' + rule_file: 'rules_verbose.xml' + rule_id: '880001' + input: '{"version":1,"origin":{"name":"Integration Test","module":"api"},"command":"log_processing","parameters":{"event": "{\"it_logtest\" : \"rules_verbose\", \"test\": \"last_match\"}","log_format": "syslog","location": "master->/var/log/syslog","options":["true", "false"]}}' + verbose_mode: False + warning_message: "WARNING: \\(\\d+\\): 'options' field must be a JSON object. The parameter will be ignored" +- + name: 'options_bad_type_number' + rule_file: 'rules_verbose.xml' + rule_id: '880001' + input: '{"version":1,"origin":{"name":"Integration Test","module":"api"},"command":"log_processing","parameters":{"event": "{\"it_logtest\" : \"rules_verbose\", \"test\": \"last_match\"}","log_format": "syslog","location": "master->/var/log/syslog","options":123456}}' + verbose_mode: False + warning_message: "WARNING: \\(\\d+\\): 'options' field must be a JSON object. The parameter will be ignored" +- + name: 'options_bad_type_string' + rule_file: 'rules_verbose.xml' + rule_id: '880001' + input: '{"version":1,"origin":{"name":"Integration Test","module":"api"},"command":"log_processing","parameters":{"event": "{\"it_logtest\" : \"rules_verbose\", \"test\": \"last_match\"}","log_format": "syslog","location": "master->/var/log/syslog","options":"true"}}' + verbose_mode: False + warning_message: "WARNING: \\(\\d+\\): 'options' field must be a JSON object. The parameter will be ignored" diff --git a/tests/integration/test_logtest/test_log_process_options/test_rules_verbose.py b/tests/integration/test_logtest/test_log_process_options/test_rules_verbose.py new file mode 100644 index 0000000000..619f397a0b --- /dev/null +++ b/tests/integration/test_logtest/test_log_process_options/test_rules_verbose.py @@ -0,0 +1,123 @@ +# 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 json +import os +import shutil +import re + +import pytest +import yaml +from wazuh_testing.tools import (WAZUH_PATH, LOGTEST_SOCKET_PATH, + WAZUH_UNIX_USER, LOG_FILE_PATH, + LOCAL_RULES_PATH, WAZUH_UNIX_GROUP) +from wazuh_testing.logtest import callback_logtest_started +from wazuh_testing.tools.services import control_service +from wazuh_testing.tools.monitoring import FileMonitor +from wazuh_testing.tools.file import truncate_file + + +# Marks +pytestmark = [pytest.mark.linux, pytest.mark.tier(level=0), pytest.mark.server] + +# Configurations +test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/') +messages_path = os.path.join(test_data_path, 'rules_verbose.yaml') +logtest_startup_timeout = 30 + +with open(messages_path) as f: + test_cases = yaml.safe_load(f) + +# Variables +receiver_sockets_params = [(LOGTEST_SOCKET_PATH, 'AF_UNIX', 'TCP')] +receiver_sockets = None + +local_rules_debug_messages = ['Trying rule: 880000 - Parent rules verbose', '*Rule 880000 matched', + '*Trying child rules', 'Trying rule: 880001 - test last_match', '*Rule 880001 matched', + '*Trying child rules', 'Trying rule: 880002 - test_child test_child'] + + +# Fixtures +@pytest.fixture(scope='function') +def configure_rules_list(get_configuration, request): + """Configure a custom rules for testing. + Restart Wazuh is not needed for applying the configuration is optional. + """ + + # save current rules + shutil.copy(LOCAL_RULES_PATH, LOCAL_RULES_PATH + '.cpy') + + file_test = get_configuration['rule_file'] + # copy test rules + shutil.copy(test_data_path + file_test, LOCAL_RULES_PATH) + shutil.chown(LOCAL_RULES_PATH, WAZUH_UNIX_USER, WAZUH_UNIX_GROUP) + + yield + + # restore previous configuration + shutil.move(LOCAL_RULES_PATH + '.cpy', LOCAL_RULES_PATH) + shutil.chown(LOCAL_RULES_PATH, WAZUH_UNIX_USER, WAZUH_UNIX_GROUP) + + +@pytest.fixture(scope='module', params=test_cases, ids=[test_case['name'] for test_case in test_cases]) +def get_configuration(request): + """Get configurations from the module.""" + return request.param + + +@pytest.fixture(scope='module') +def wait_for_logtest_startup(request): + """Wait until logtest has begun.""" + log_monitor = FileMonitor(LOG_FILE_PATH) + log_monitor.start(timeout=logtest_startup_timeout, callback=callback_logtest_started) + + +@pytest.fixture(scope='module') +def restart_required_logtest_daemons(): + """Wazuh logtests daemons handler.""" + required_logtest_daemons = ['wazuh-analysisd'] + + truncate_file(LOG_FILE_PATH) + + for daemon in required_logtest_daemons: + control_service('restart', daemon=daemon) + + yield + + for daemon in required_logtest_daemons: + control_service('stop', daemon=daemon) + + +# Tests +def test_rules_verbose(get_configuration, restart_required_logtest_daemons, + configure_rules_list, wait_for_logtest_startup, + connect_to_sockets_function): + """Check the correct behaviour of logtest `rules_debug` field. + + This test writes different inputs at the logtest socket and checks the responses to be the expected. + """ + + # send the logtest request + receiver_sockets[0].send(get_configuration['input'], size=True) + + # receive logtest reply and parse it + response = receiver_sockets[0].receive(size=True).rstrip(b'\x00').decode() + result = json.loads(response) + + assert result['error'] == 0 + assert result['data']['output']['rule']['id'] == get_configuration['rule_id'] + + if 'verbose_mode' in get_configuration and get_configuration['verbose_mode']: + if 'rules_debug' in result['data']: + assert result['data']['rules_debug'][-len(local_rules_debug_messages):] == local_rules_debug_messages + else: + assert False, 'The rules_debug field was not found in the response data' + + else: + assert 'rules_debug' not in result['data'] + + if 'warning_message' in get_configuration: + r = re.compile(get_configuration['warning_message']) + match_list = list(filter(r.match, result['data']['messages'])) + assert match_list, 'The warning message was not found in the response data'