diff --git a/CHANGELOG.md b/CHANGELOG.md index 65a30bcdc8..78712493f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file. ### Changed +- Fix FIM test_large_changes test suite ([#3948](https://github.com/wazuh/wazuh-qa/pull/3948)) \- (Tests) - Update `get_test_cases_data` function so it handles fim_mode parameter ([#4185](https://github.com/wazuh/wazuh-qa/pull/4185)) \- (Framework) - Change FIM `regular_file_cud` and `EventChecker` file modification steps ([#4183](https://github.com/wazuh/wazuh-qa/pull/4183)) \- (Framework + Tests) - Refactor library to change the environment ([#4145](https://github.com/wazuh/wazuh-qa/pull/4145)) \- (Framework) diff --git a/deps/wazuh_testing/wazuh_testing/__init__.py b/deps/wazuh_testing/wazuh_testing/__init__.py index bf72e1e136..49435fb134 100644 --- a/deps/wazuh_testing/wazuh_testing/__init__.py +++ b/deps/wazuh_testing/wazuh_testing/__init__.py @@ -109,6 +109,7 @@ VALID_FIM_MODES = ['scheduled', 'realtime', 'whodata'] OS_EXCLUDED_FROM_RT_WD = ['darwin', 'sunos5'] + def is_udp(protocol): return protocol.upper() == UDP diff --git a/deps/wazuh_testing/wazuh_testing/modules/fim/event_monitor.py b/deps/wazuh_testing/wazuh_testing/modules/fim/event_monitor.py index 131a51a14c..9a0b8fb88c 100644 --- a/deps/wazuh_testing/wazuh_testing/modules/fim/event_monitor.py +++ b/deps/wazuh_testing/wazuh_testing/modules/fim/event_monitor.py @@ -193,6 +193,7 @@ def callback_integrity_sync_message(line): Args: line (String): string line to be checked by callback in FileMonitor. Returns: + List: returns a list with formated datetime, And the event's JSON data. """ if callback_detect_integrity_control_event(line): @@ -205,6 +206,7 @@ def callback_detect_integrity_check_global(line): """ Callback that detects if a line contains an 'integrity_check_global' event Args: line (String): string line to be checked by callback in FileMonitor. + Returns: JSON: returns event's JSON data. """ @@ -309,6 +311,7 @@ def callback_real_time_whodata_started(line): match = re.match(CB_REALTIME_WHODATA_ENGINE_STARTED, line) if match: return True + return None return None @@ -388,6 +391,21 @@ def callback_detect_file_deleted_event(line): return None +def callback_detect_file_more_changes(line): + """ Callback that detects if a line in a log contains 'More changes' in content_changes. + + Args: + line (String): string line to be checked by callback in FileMonitor. + + Returns: + returns JSON string from log. + """ + json_event = callback_detect_event(line) + if json_event is not None and 'content_changes' in json_event['data']: + if 'More changes' in json_event['data']['content_changes']: + return json_event + + def callback_audit_cannot_start(line): """ Callback that detects if a line shows whodata engine could not start and monitoring switched to realtime. @@ -435,6 +453,30 @@ def check_fim_event(file_monitor=None, callback='', error_message=None, update_p callback=generate_monitoring_callback(callback), error_message=error_message) +def get_fim_event(file_monitor=None, callback='', error_message=None, update_position=True, + timeout=T_60, accum_results=1, file_to_monitor=LOG_FILE_PATH): + """ Check if FIM event occurs and return it according to the callback. + + 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 + accum_results (int): Accumulation of matches. + + Returns: + returns the value given by the callback used. Default None. + """ + 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 + + result = file_monitor.start(timeout=timeout, update_position=update_position, accum_results=accum_results, + callback=callback, error_message=error_message).result() + return result + + def detect_initial_scan(file_monitor): """Detect initial scan when restarting Wazuh. diff --git a/deps/wazuh_testing/wazuh_testing/tools/configuration.py b/deps/wazuh_testing/wazuh_testing/tools/configuration.py index 0fcd04f8b6..b78a6cb159 100644 --- a/deps/wazuh_testing/wazuh_testing/tools/configuration.py +++ b/deps/wazuh_testing/wazuh_testing/tools/configuration.py @@ -718,6 +718,7 @@ def get_test_cases_data(data_file_path): configuration_parameters = [] configuration_metadata = [] test_cases_ids = [] + def set_test_case_data(): configuration_parameters.append(test_case['configuration_parameters']) metadata_parameters = {'name': test_case['name'], 'description': test_case['description']} diff --git a/tests/integration/test_fim/test_files/test_report_changes/data/configuration_template/configuration_large_changes.yaml b/tests/integration/test_fim/test_files/test_report_changes/data/configuration_template/configuration_large_changes.yaml new file mode 100644 index 0000000000..7c2542c201 --- /dev/null +++ b/tests/integration/test_fim/test_files/test_report_changes/data/configuration_template/configuration_large_changes.yaml @@ -0,0 +1,32 @@ +- sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: INTERVAL + - directories: + value: TEST_DIRECTORIES + attributes: + - check_all: 'yes' + - realtime: REALTIME + - whodata: WHODATA + - report_changes: 'yes' + - diff_size_limit: 200KB + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_fim/test_files/test_report_changes/data/test_cases/cases_large_changes.yaml b/tests/integration/test_fim/test_files/test_report_changes/data/test_cases/cases_large_changes.yaml new file mode 100644 index 0000000000..c90d19cee7 --- /dev/null +++ b/tests/integration/test_fim/test_files/test_report_changes/data/test_cases/cases_large_changes.yaml @@ -0,0 +1,155 @@ +- name: Test changes smaller than limit (Scheduled mode) + description: Test that changes are smaller than limit, 'More changes' does not appear in content_changes + configuration_parameters: + INTERVAL: 4 + REALTIME: 'no' + WHODATA: 'no' + metadata: + filename: regular_1 + original_size: 500 + modified_size: 500 + has_more_changes: false + fim_mode: scheduled + +- name: Test changes smaller than limit (Realtime mode) + description: Test that changes are smaller than limit, 'More changes' does not appear in content_changes + configuration_parameters: + INTERVAL: 10000 + REALTIME: 'yes' + WHODATA: 'no' + metadata: + filename: regular_1 + original_size: 500 + modified_size: 500 + has_more_changes: false + fim_mode: realtime + +- name: Test changes smaller than limit (Whodata mode) + description: Test that changes are smaller than limit, 'More changes' does not appear in content_changes + configuration_parameters: + INTERVAL: 10000 + REALTIME: 'no' + WHODATA: 'yes' + metadata: + filename: regular_1 + original_size: 500 + modified_size: 500 + has_more_changes: false + fim_mode: whodata + +- name: Test large changes - Same size (Scheduled mode) + description: Test that changes are bigger than limit, 'More changes' appears in content_changes + configuration_parameters: + INTERVAL: 4 + REALTIME: 'no' + WHODATA: 'no' + metadata: + filename: regular_2 + original_size: 200000 + modified_size: 200000 + has_more_changes: true + fim_mode: scheduled + +- name: Test large changes - Same size (Realtime mode) + description: Test that changes are bigger than limit, 'More changes' appears in content_changes + configuration_parameters: + INTERVAL: 10000 + REALTIME: 'yes' + WHODATA: 'no' + metadata: + filename: regular_2 + original_size: 200000 + modified_size: 200000 + has_more_changes: true + fim_mode: realtime + +- name: Test large changes - Same size (Whodata mode) + description: Test that changes are bigger than limit, 'More changes' appears in content_changes. + configuration_parameters: + INTERVAL: 10000 + REALTIME: 'no' + WHODATA: 'yes' + metadata: + filename: regular_2 + original_size: 200000 + modified_size: 200000 + has_more_changes: true + fim_mode: whodata + +- name: Test large changes - File bigger after change (Scheduled mode) + description: Test that changes are bigger than limit, 'More changes' appears in content_changes. + configuration_parameters: + INTERVAL: 4 + REALTIME: 'no' + WHODATA: 'no' + metadata: + filename: regular_3 + original_size: 10 + modified_size: 200000 + has_more_changes: true + fim_mode: scheduled + +- name: Test large changes - File bigger after change (Realtime mode) + description: Test that changes are bigger than limit, 'More changes' appears in content_changes. + configuration_parameters: + INTERVAL: 10000 + REALTIME: 'yes' + WHODATA: 'no' + metadata: + filename: regular_3 + original_size: 10 + modified_size: 200000 + has_more_changes: true + fim_mode: realtime + +- name: Test large changes - File bigger after change (Whodata mode) + description: Test that changes are bigger than limit, 'More changes' appears in content_changes. + configuration_parameters: + INTERVAL: 10000 + REALTIME: 'no' + WHODATA: 'yes' + metadata: + filename: regular_3 + original_size: 10 + modified_size: 200000 + has_more_changes: true + fim_mode: whodata + +- name: Test large changes - File smaller after change (Scheduled mode) + description: Test that changes are bigger than limit, 'More changes' appears in content_changes. + configuration_parameters: + INTERVAL: 4 + REALTIME: 'no' + WHODATA: 'no' + metadata: + filename: regular_4 + original_size: 200000 + modified_size: 10 + has_more_changes: true + fim_mode: scheduled + +- name: Test large changes - File smaller after change (Realtime mode) + description: Test that changes are bigger than limit, 'More changes' appears in content_changes. + configuration_parameters: + INTERVAL: 10000 + REALTIME: 'yes' + WHODATA: 'no' + metadata: + filename: regular_4 + original_size: 200000 + modified_size: 10 + has_more_changes: true + fim_mode: realtime + +- name: Test large changes - File smaller after change (Whodata mode) + description: Test that changes are bigger than limit, 'More changes' appears in content_changes. + configuration_parameters: + INTERVAL: 10000 + REALTIME: 'no' + WHODATA: 'yes' + metadata: + filename: regular_4 + original_size: 200000 + modified_size: 10 + has_more_changes: true + fim_mode: whodata diff --git a/tests/integration/test_fim/test_files/test_report_changes/test_large_changes.py b/tests/integration/test_fim/test_files/test_report_changes/test_large_changes.py index bdc6c3c619..46f2cf112d 100644 --- a/tests/integration/test_fim/test_files/test_report_changes/test_large_changes.py +++ b/tests/integration/test_fim/test_files/test_report_changes/test_large_changes.py @@ -64,81 +64,50 @@ tags: - fim_report_changes ''' -import gzip import os -import shutil -import subprocess import sys import pytest from wazuh_testing.tools import PREFIX -from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.configuration import get_test_cases_data, load_configuration_template from wazuh_testing.tools.monitoring import FileMonitor -from wazuh_testing import global_parameters, LOG_FILE_PATH, REGULAR -from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS -from wazuh_testing.modules.fim.event_monitor import callback_detect_event -from wazuh_testing.modules.fim.utils import create_file, generate_params -from test_fim.common import generate_string, make_diff_file_path +from wazuh_testing import global_parameters, LOG_FILE_PATH, REGULAR, T_20 +from wazuh_testing.modules.fim import TEST_DIR_1 +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import (callback_detect_event, get_fim_event, + callback_detect_file_more_changes) +from wazuh_testing.modules.fim.utils import create_file +from test_fim.common import generate_string -# Marks +# Marks pytestmark = pytest.mark.tier(level=1) +# 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') -# variables -local_internal_options = FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS -test_directories = [os.path.join(PREFIX, 'testdir')] -nodiff_file = os.path.join(PREFIX, 'testdir_nodiff', 'regular_file') -directory_str = ','.join(test_directories) -testdir = test_directories[0] -unzip_diff_dir = os.path.join(PREFIX, 'unzip_diff') - -wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) -test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') -configurations_path = os.path.join(test_data_path, 'wazuh_conf.yaml') - -# configurations - -conf_params, conf_metadata = generate_params(extra_params={'REPORT_CHANGES': {'report_changes': 'yes'}, - 'TEST_DIRECTORIES': directory_str, - 'NODIFF_FILE': nodiff_file}) -configurations = load_wazuh_configurations(configurations_path, __name__, params=conf_params, metadata=conf_metadata) - - -# fixtures - -@pytest.fixture(scope='module', params=configurations) -def get_configuration(request): - """Get configurations from the module.""" - return request.param - - -# Functions - - -def extra_configuration_before_yield(): - """Create a folder to store diff files unzipped""" - os.makedirs(unzip_diff_dir, exist_ok=True) +# Configuration and cases data +test_cases_path = os.path.join(TEST_CASES_PATH, 'cases_large_changes.yaml') +configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_large_changes.yaml') +# Variables +test_directories = [os.path.join(PREFIX, TEST_DIR_1)] +testdir = test_directories[0] -def extra_configuration_after_yield(): - """Delete the folder after the test""" - shutil.rmtree(unzip_diff_dir, ignore_errors=True) +# Test configurations +configuration_parameters, configuration_metadata, test_case_ids = get_test_cases_data(test_cases_path) +for count, value in enumerate(configuration_parameters): + configuration_parameters[count]['TEST_DIRECTORIES'] = testdir +configurations = load_configuration_template(configurations_path, configuration_parameters, configuration_metadata) # Tests -@pytest.mark.skip('Test skipped for flaky behavior, after it is fixed by Issue wazuh/wazuh#3783, it will be unblocked') -@pytest.mark.parametrize('filename, folder, original_size, modified_size', [ - ('regular_0', testdir, 500, 500), - ('regular_1', testdir, 30000, 30000), - ('regular_2', testdir, 70000, 70000), - ('regular_3', testdir, 10, 20000), - ('regular_4', testdir, 10, 70000), - ('regular_5', testdir, 20000, 10), - ('regular_6', testdir, 70000, 10), -]) -def test_large_changes(filename, folder, original_size, modified_size, get_configuration, configure_environment, - configure_local_internal_options_module, restart_syscheckd, wait_for_fim_start): +@pytest.mark.parametrize('test_folders', [test_directories], scope="module", ids='') +@pytest.mark.parametrize('configuration, metadata', zip(configurations, configuration_metadata), ids=test_case_ids) +def test_large_changes(configuration, metadata, set_wazuh_configuration, configure_local_internal_options_function, + create_monitored_folders_module, restart_syscheck_function, wait_syscheck_start): ''' description: Check if the 'wazuh-syscheckd' daemon detects the character limit in the file changes is reached showing the 'More changes' tag in the 'content_changes' field of the generated events. For this @@ -147,38 +116,35 @@ def test_large_changes(filename, folder, original_size, modified_size, get_confi the test will verify that the generated FIM event contains in its 'content_changes' field the proper value depending on the test case. - wazuh_min_version: 4.2.0 + wazuh_min_version: 4.5.0 tier: 1 parameters: - - filename: - type: str - brief: Name of the testing file to be created. - - folder: - type: str - brief: Path to the directory where the testing files will be created. - - original_size: - type: int - brief: Size of the testing file in bytes before being modified. - - modified_size: - type: int - brief: Size of the testing file in bytes after being modified. - - get_configuration: + - configuration: + type: dict + brief: Configuration values for ossec.conf. + - metadata: + type: dict + brief: Test case data. + - test_folders: + type: dict + brief: List of folders to be created for monitoring. + - set_wazuh_configuration: type: fixture - brief: Get configurations from the module. - - configure_environment: + brief: Set ossec.conf configuration. + - create_monitored_folders_module: type: fixture - brief: Configure a custom environment for testing. - - configure_local_internal_options_module: + brief: Create a given list of folders when the module starts. Delete the folders at the end of the module. + - configure_local_internal_options_function: type: fixture - brief: Configure the local internal options file. - - restart_syscheckd: + brief: Set local_internal_options.conf file. + - restart_syscheck_function: type: fixture - brief: Clear the 'ossec.log' file and start a new monitor. - - wait_for_fim_start: + brief: restart syscheckd daemon, and truncate the ossec.log. + - wait_syscheck_start: type: fixture - brief: Wait for realtime start, whodata start, or end of initial FIM scan. + brief: check that the starting FIM scan is detected. assertions: - Verify that FIM events are generated when adding and modifying the testing file. @@ -190,68 +156,41 @@ def test_large_changes(filename, folder, original_size, modified_size, get_confi of the monitored file when the old content is lower than the allowed limit or the testing platform is Windows. - input_description: A test case (ossec_conf_report) is contained in external YAML file (wazuh_conf.yaml) - which includes configuration settings for the 'wazuh-syscheckd' daemon and, these - are combined with the testing directory and files to be monitored defined in the module. + input_description: The file 'configuration_large_changes.yaml' provides the configuration template. + The file 'cases_large_changes.yaml' provides the test cases configuration + details for each test case. expected_output: - r'.*Sending FIM event: (.+)$' ('added' and 'modified' events) - - The length of the testing file content by running the diff/fc command. - - tags: - - diff - - scheduled + - The 'More changes' message appears in content_changes when the changes size is bigger than the set limit. ''' - limit = 59391 - has_more_changes = False - original_file = os.path.join(folder, filename) - unzip_diff_file = os.path.join(unzip_diff_dir, filename + '-old') - diff_file_path = make_diff_file_path(folder, filename) - - fim_mode = get_configuration['metadata']['fim_mode'] + wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + limit = 50000 # Create the file and and capture the event. - original_string = generate_string(original_size, '0') - create_file(REGULAR, folder, filename, content=original_string) - - wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_detect_event).result() + original_string = generate_string(metadata['original_size'], '0') + create_file(REGULAR, testdir, metadata['filename'], content=original_string) - # Store uncompressed diff file in backup folder - with gzip.open(diff_file_path, 'rb') as f_in: - with open(unzip_diff_file, 'wb') as f_out: - shutil.copyfileobj(f_in, f_out) + wazuh_log_monitor.start(timeout=T_20, callback=callback_detect_event, + error_message="Did not receive the expected FIM event").result() # Modify the file with new content - modified_string = generate_string(modified_size, '1') - create_file(REGULAR, folder, filename, content=modified_string) - - event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_detect_event).result() - - # Run the diff/fc command and get the output length - try: - if sys.platform == 'win32': - subprocess.check_output(['fc', '/n', original_file, unzip_diff_file]) - else: - subprocess.check_output(['diff', original_file, unzip_diff_file]) - except subprocess.CalledProcessError as e: - # Inputs are different - if e.returncode == 1: - if sys.platform == 'win32' and b'*' not in e.output.split(b'\r\n')[1]: - has_more_changes = True - else: - if len(e.output) > limit: - has_more_changes = True + modified_string = generate_string(metadata['modified_size'], '1') + create_file(REGULAR, testdir, metadata['filename'], content=modified_string) # Assert 'More changes' is shown when the command returns more than 'limit' characters - if has_more_changes: - assert 'More changes' in event['data']['content_changes'], '"More changes" not found within content_changes.' + if metadata['has_more_changes']: + event = get_fim_event(timeout=T_20, callback=callback_detect_file_more_changes, + error_message='Did not find event with "More changes" within content_changes.') else: + event = wazuh_log_monitor.start(timeout=T_20, callback=callback_detect_event, + error_message="Did not receive the expected FIM event").result() assert 'More changes' not in event['data']['content_changes'], '"More changes" found within content_changes.' # Assert old content is shown in content_changes assert '0' in event['data']['content_changes'], '"0" is the old value but it is not found within content_changes' # Assert new content is shown when old content is lower than the limit or platform is Windows - if original_size < limit or sys.platform == 'win32': + if metadata['original_size'] < limit or sys.platform == 'win32': assert '1' in event['data']['content_changes'], '"1" is the new value but it is not found ' \ 'within content_changes' diff --git a/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_win32.py b/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_win32.py index 3e2c8e0262..c23fbd7d7c 100644 --- a/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_win32.py +++ b/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_win32.py @@ -123,6 +123,7 @@ def callback_integrity_or_whodata(line): # tests +pytest.mark.skip("This test is skipped. When it is fixed it will be unblocked.") def test_events_while_integrity_scan(get_configuration, configure_environment, restart_syscheckd, configure_local_internal_options_module): ''' @@ -187,7 +188,7 @@ def test_events_while_integrity_scan(get_configuration, configure_environment, r else: # Check the integrity scan has begun - wazuh_log_monitor.start(timeout=global_parameters.default_timeout * 3, + wazuh_log_monitor.start(timeout=global_parameters.default_timeout * 5, callback=callback_detect_synchronization, error_message=ERR_MSG_INTEGRITY_CHECK_EVENT)