diff --git a/CHANGELOG.md b/CHANGELOG.md index d3d20a409b..127ec39b6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### Added +- Add support for the installation/uninstallation of npm packages ([#5092](https://github.com/wazuh/wazuh-qa/pull/5092)) \- (Tests) - Add alert.json file to Vulnerability Detector E2E test report ([#5147](https://github.com/wazuh/wazuh-qa/pull/5147)) \- (Framework) - Add documentation about markers for system tests ([#5080](https://github.com/wazuh/wazuh-qa/pull/5080)) \- (Documentation) - Add AWS Custom Buckets Integration tests ([#4675](https://github.com/wazuh/wazuh-qa/pull/4675)) \- (Framework + Tests) diff --git a/deps/wazuh_testing/wazuh_testing/end_to_end/remote_operations_handler.py b/deps/wazuh_testing/wazuh_testing/end_to_end/remote_operations_handler.py index e4037a2320..24ee82368a 100644 --- a/deps/wazuh_testing/wazuh_testing/end_to_end/remote_operations_handler.py +++ b/deps/wazuh_testing/wazuh_testing/end_to_end/remote_operations_handler.py @@ -167,7 +167,7 @@ def install_package(host: str, operation_data: Dict[str, Dict], host_manager: Ho try: if host_os_arch in install_package_data[host_os_name]: package_id = install_package_data[host_os_name][host_os_arch] - + package_data = load_packages_metadata()[package_id] package_url = package_data['urls'][host_os_name][host_os_arch] @@ -176,7 +176,12 @@ def install_package(host: str, operation_data: Dict[str, Dict], host_manager: Ho current_datetime = datetime.utcnow().isoformat() - host_manager.install_package(host, package_url, system) + use_npm = package_data.get('use_npm', False) + + if use_npm: + host_manager.install_npm_package(host, package_url, system) + else: + host_manager.install_package(host, package_url, system) logging.info(f"Package {package_url} installed on {host}") @@ -194,10 +199,10 @@ def install_package(host: str, operation_data: Dict[str, Dict], host_manager: Ho check_vulnerability_alerts(results, operation_data['check'], current_datetime, host_manager, host, package_data, operation='install') - + else: logging.error(f"Error: Package for {host_os_name} and {host_os_arch} not found") - + except Exception as e: logging.critical(f"Error searching package: {e}") @@ -245,38 +250,37 @@ def remove_package(host: str, operation_data: Dict[str, Dict], host_manager: Hos package_id = None if host_os_name in package_data: - try: - if host_os_arch in package_data[host_os_name]: - package_id = package_data[host_os_name][host_os_arch] + if host_os_arch in package_data[host_os_name]: + package_id = package_data[host_os_name][host_os_arch] + else: + raise ValueError(f"Package for {host_os_name} and {host_os_arch} not found") - package_data = load_packages_metadata()[package_id] + package_data = load_packages_metadata()[package_id] + use_npm = package_data.get('use_npm', False) - current_datetime = datetime.utcnow().isoformat() + current_datetime = datetime.utcnow().isoformat() - logging.info(f"Removing package on {host}") - if 'uninstall_name' in package_data: - uninstall_name = package_data['uninstall_name'] - host_manager.remove_package(host, system, package_uninstall_name=uninstall_name) - elif 'uninstall_custom_playbook' in package_data: - host_manager.remove_package(host, system, - custom_uninstall_playbook=package_data['uninstall_custom_playbook']) + logging.info(f"Removing package on {host}") + if 'uninstall_name' in package_data: + uninstall_name = package_data['uninstall_name'] + if use_npm: + host_manager.remove_npm_package(host, system, package_uninstall_name=uninstall_name) + else: + host_manager.remove_package(host, system, package_uninstall_name=uninstall_name) + elif 'uninstall_custom_playbook' in package_data: + host_manager.remove_package(host, system, + custom_uninstall_playbook=package_data['uninstall_custom_playbook']) - wait_is_required = 'check' in operation_data and (operation_data['check']['alerts'] or - operation_data['check']['state_index'] or - operation_data['check']['no_alerts'] or - operation_data['check']['no_indices']) + wait_is_required = 'check' in operation_data and (operation_data['check']['alerts'] or + operation_data['check']['state_index'] or + operation_data['check']['no_alerts'] or + operation_data['check']['no_indices']) - if wait_is_required: - wait_syscollector_and_vuln_scan(host_manager, host, operation_data, current_datetime) + if wait_is_required: + wait_syscollector_and_vuln_scan(host_manager, host, operation_data, current_datetime) - check_vulnerability_alerts(results, operation_data['check'], current_datetime, host_manager, host, - package_data, operation='remove') - - else: - logging.error(f"Error: Package for {host_os_name} and {host_os_arch} not found") - - except Exception as e: - logging.critical(f"Error searching package: {e}") + check_vulnerability_alerts(results, operation_data['check'], current_datetime, host_manager, host, + package_data, operation='remove') else: logging.info(f"No operation to perform on {host}") @@ -339,7 +343,7 @@ def update_package(host: str, operation_data: Dict[str, Dict], host_manager: Hos try: if host_os_arch in install_package_data_to[host_os_name]: package_id_to = install_package_data_to[host_os_name][host_os_arch] - + package_data_from = load_packages_metadata()[package_id_from] package_data_to = load_packages_metadata()[package_id_to] @@ -349,7 +353,13 @@ def update_package(host: str, operation_data: Dict[str, Dict], host_manager: Hos logging.info(f"Package URL: {package_url_to}") current_datetime = datetime.utcnow().isoformat() - host_manager.install_package(host, package_url_to, system) + + use_npm = package_data_to.get('use_npm', False) + + if use_npm: + host_manager.install_npm_package(host, package_url_to, system) + else: + host_manager.install_package(host, package_url_to, system) logging.info(f"Package {package_url_to} installed on {host}") @@ -364,7 +374,7 @@ def update_package(host: str, operation_data: Dict[str, Dict], host_manager: Hos check_vulnerability_alerts(results, operation_data['check'], current_datetime, host_manager, host, {'from': package_data_from, 'to': package_data_to}, operation='update') - + else: logging.error(f"Error: Package for {host_os_name} and {host_os_arch} not found") diff --git a/deps/wazuh_testing/wazuh_testing/tools/system.py b/deps/wazuh_testing/wazuh_testing/tools/system.py index 9726739b06..7b6b88dc0f 100644 --- a/deps/wazuh_testing/wazuh_testing/tools/system.py +++ b/deps/wazuh_testing/wazuh_testing/tools/system.py @@ -495,7 +495,7 @@ def install_package(self, host, url, system='ubuntu'): result = True elif system == 'centos': result = self.get_host(host).ansible("yum", f"name={url} state=present " - 'sslverify=false disable_gpg_check=True', check=False) + 'sslverify=false disable_gpg_check=True', check=False) elif system == 'macos': package_name = url.split('/')[-1] result = self.get_host(host).ansible("command", f"curl -LO {url}", check=False) @@ -506,6 +506,40 @@ def install_package(self, host, url, system='ubuntu'): return result + def install_npm_package(self, host, url, system='ubuntu'): + """ + Installs a package on the specified host using npm. + + Args: + host (str): The target host on which to install the package. + url (str): The URL or name of the package to be installed. + system (str, optional): The operating system type. Defaults to 'ubuntu'. + Supported values: 'windows', 'ubuntu', 'centos', 'macos'. + + Returns: + Dict: Testinfra Ansible Response of the operation + + Example: + host_manager.install_package('my_host', 'package_name', 'system_name') + """ + + # Define the npm install command + cmd = f"npm install -g {url}" + + if system == 'macos': + cmd = f"PATH=/usr/local/bin:$PATH {cmd}" + shell_type = "shell" + elif system == 'windows': + shell_type = "win_shell" + else: + shell_type = "shell" + + # Execute the command and log the result + result = self.get_host(host).ansible(shell_type, cmd, check=False) + logging.info(f"npm package installed result {result}") + + return result + def get_master_ip(self): """ Retrieves the IP address of the master node from the inventory. @@ -594,6 +628,49 @@ def remove_package(self, host, system, package_uninstall_name=None, custom_unins return remove_operation_result + def remove_npm_package(self, host, system, package_uninstall_name=None, custom_uninstall_playbook=None): + """ + Removes a package from the specified host using npm. + + Args: + host (str): The target host from which to remove the package. + package_name (str): The name of the package to be removed. + system (str): The operating system type. + Supported values: 'windows', 'ubuntu', 'centos', 'macos'. + + Returns: + Dict: Testinfra Ansible Response of the operation + + Example: + host_manager.remove_npm_package('my_host', 'system_name', 'package_name') + """ + logging.info(f"Removing package {package_uninstall_name} from host {host}") + logging.info(f"System: {system}") + + remove_operation_result = False + + os_name = self.get_host_variables(host)['os_name'] + + if custom_uninstall_playbook: + remove_operation_result = self.run_playbook(host, custom_uninstall_playbook) + else: + # Define the npm uninstall command + cmd = f"npm uninstall -g {package_uninstall_name}" + + if system == 'macos': + cmd = f"PATH=/usr/local/bin:$PATH {cmd}" + shell_type = "shell" + elif system == 'windows': + shell_type = "win_shell" + else: + shell_type = "shell" + + # Execute the command and log the result + remove_operation_result = self.get_host(host).ansible(shell_type, cmd, check=False) + logging.info(f"npm package removed result {remove_operation_result}") + + return remove_operation_result + def run_playbook(self, host, playbook_name, params=None): """ Executes an Ansible playbook on the specified host. @@ -670,7 +747,7 @@ def handle_wazuh_services(self, host, operation): if os == 'linux': result = binary_path = f"/var/ossec/bin/wazuh-control" elif os == 'macos': - result= binary_path = f"/Library/Ossec/bin/wazuh-control" + result = binary_path = f"/Library/Ossec/bin/wazuh-control" result = self.get_host(host).ansible('shell', f"{binary_path} {operation}", check=False)