Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Windows tests #5290

Open
wants to merge 5 commits into
base: 4.9.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ __pycache__
.pytest_cache

venv
wazuh_testing.egg-info
*.egg-info
dist
build

# Python bytecode files
*.pyc
Expand Down
2 changes: 1 addition & 1 deletion deployability/deps/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ pytest==7.4.4
paramiko==3.4.0
requests==2.31.0
chardet==5.2.0
pywinrm==0.3.0
pywinrm==0.4.0
8 changes: 6 additions & 2 deletions deployability/modules/generic/ansible.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from pathlib import Path
from pydantic import BaseModel, IPvAnyAddress
from typing import Optional

from modules.generic.utils import Utils
from modules.generic.logger import Logger
Expand All @@ -16,7 +17,8 @@ class Inventory(BaseModel):
ansible_host: str | IPvAnyAddress
ansible_user: str
ansible_port: int
ansible_ssh_private_key_file: str
ansible_ssh_private_key_file: Optional[str] = None
ansible_password: Optional[str] = None


class Ansible:
Expand Down Expand Up @@ -118,7 +120,9 @@ def generate_inventory(self) -> dict:
self.ansible_data.ansible_host: {
'ansible_port': self.ansible_data.ansible_port,
'ansible_user': self.ansible_data.ansible_user,
'ansible_ssh_private_key_file': self.ansible_data.ansible_ssh_private_key_file
**({'ansible_ssh_private_key_file': self.ansible_data.ansible_ssh_private_key_file}
if hasattr(self.ansible_data, 'ansible_ssh_private_key_file')
else {'ansible_password': self.ansible_data.ansible_password})
}
}
}
Expand Down
150 changes: 106 additions & 44 deletions deployability/modules/testing/tests/helpers/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import yaml

from typing import List, Optional
from .constants import WAZUH_CONF, WAZUH_ROOT
from .executor import Executor, WazuhAPI
from .constants import WAZUH_CONF, WAZUH_ROOT, WAZUH_WINDOWS_CONF
from .executor import Executor, WazuhAPI, ConnectionManager
from .generic import HostInformation, CheckFiles
from modules.testing.utils import logger

Expand All @@ -15,32 +15,33 @@ class WazuhAgent:
@staticmethod
def install_agent(inventory_path, agent_name, wazuh_version, wazuh_revision, live) -> None:

if live == True:
if live:
s3_url = 'packages'
release = wazuh_version[0:3]
release = wazuh_version[:1] + ".x"
else:
s3_url = 'packages-dev'
release = 'pre-release'

os_type = HostInformation.get_os_type(inventory_path)
commands = []

if 'linux' in os_type:
distribution = HostInformation.get_linux_distribution(inventory_path)
architecture = HostInformation.get_architecture(inventory_path)

if distribution == 'rpm' and 'x86_64' in architecture:
if distribution == 'rpm' and 'amd64' in architecture:
commands.extend([
f"curl -o wazuh-agent-{wazuh_version}-1.x86_64.rpm https://{s3_url}.wazuh.com/{release}/yum/wazuh-agent-{wazuh_version}-1.x86_64.rpm && sudo WAZUH_MANAGER='MANAGER_IP' WAZUH_AGENT_NAME='{agent_name}' rpm -ihv wazuh-agent-{wazuh_version}-1.x86_64.rpm"
])
elif distribution == 'rpm' and 'aarch64' in architecture:
elif distribution == 'rpm' and 'arm64' in architecture:
commands.extend([
f"curl -o wazuh-agent-{wazuh_version}-1aarch64.rpm https://{s3_url}.wazuh.com/{release}/yum/wazuh-agent-{wazuh_version}-1.aarch64.rpm && sudo WAZUH_MANAGER='MANAGER_IP' WAZUH_AGENT_NAME='{agent_name}' rpm -ihv wazuh-agent-{wazuh_version}-1.aarch64.rpm"
])
elif distribution == 'deb' and 'x86_64' in architecture:
elif distribution == 'deb' and 'amd64' in architecture:
commands.extend([
f"wget https://{s3_url}.wazuh.com/{release}/apt/pool/main/w/wazuh-agent/wazuh-agent_{wazuh_version}-1_amd64.deb && sudo WAZUH_MANAGER='MANAGER_IP' WAZUH_AGENT_NAME='{agent_name}' dpkg -i ./wazuh-agent_{wazuh_version}-1_amd64.deb"
])
elif distribution == 'deb' and 'aarch64' in architecture:
elif distribution == 'deb' and 'arm64' in architecture:
commands.extend([
f"wget https://{s3_url}.wazuh.com/{release}/apt/pool/main/w/wazuh-agent/wazuh-agent_{wazuh_version}-1_arm64.deb && sudo WAZUH_MANAGER='MANAGER_IP' WAZUH_AGENT_NAME='{agent_name}' dpkg -i ./wazuh-agent_{wazuh_version}-1arm64.deb"
])
Expand All @@ -54,15 +55,16 @@ def install_agent(inventory_path, agent_name, wazuh_version, wazuh_revision, liv
commands.extend(system_commands)
elif 'windows' in os_type :
commands.extend([
f"Invoke-WebRequest -Uri https://packages.wazuh.com/{release}/windows/wazuh-agent-{wazuh_version}-1.msi"
"-OutFile ${env.tmp}\wazuh-agent;"
"msiexec.exe /i ${env.tmp}\wazuh-agent /q"
f"WAZUH_MANAGER='MANAGER_IP'"
f"WAZUH_AGENT_NAME='{agent_name}'"
f"WAZUH_REGISTRATION_SERVER='MANAGER_IP'",
"NET START WazuhSvc",
"NET STATUS WazuhSvc"
])
f"Invoke-WebRequest -Uri https://packages.wazuh.com/{release}/windows/wazuh-agent-{wazuh_version}-1.msi "
"-OutFile $env:TEMP\wazuh-agent.msi"
])
commands.extend([
"msiexec.exe /i $env:TEMP\wazuh-agent.msi /q "
f"WAZUH_MANAGER='MANAGER_IP' "
f"WAZUH_AGENT_NAME='{agent_name}' "
f"WAZUH_REGISTRATION_SERVER='MANAGER_IP' "
])
commands.extend(["NET START WazuhSvc"])
elif 'macos' in os_type:
if 'intel' in architecture:
commands.extend([
Expand All @@ -79,7 +81,7 @@ def install_agent(inventory_path, agent_name, wazuh_version, wazuh_revision, liv

commands.extend(system_commands)
logger.info(f'Installing Agent in {HostInformation.get_os_name_and_version_from_inventory(inventory_path)}')
Executor.execute_commands(inventory_path, commands)
ConnectionManager.execute_commands(inventory_path, commands)


@staticmethod
Expand All @@ -97,24 +99,53 @@ def register_agent(inventory_path, manager_path):

internal_ip = HostInformation.get_internal_ip_from_aws_dns(host) if 'amazonaws' in host else host

commands = [
f"sed -i 's/<address>MANAGER_IP<\/address>/<address>{internal_ip}<\/address>/g' {WAZUH_CONF}",
"systemctl restart wazuh-agent"
]
os_type = HostInformation.get_os_type(inventory_path)
logger.info(f'os_type {os_type}')

if 'linux' in os_type:
commands = [
f"sed -i 's/<address>MANAGER_IP<\/address>/<address>{internal_ip}<\/address>/g' {WAZUH_CONF}",
"systemctl restart wazuh-agent"
]

ConnectionManager.execute_commands(inventory_path, commands)
result = ConnectionManager.execute_commands(inventory_path, f'cat {WAZUH_CONF}')
assert internal_ip in result.get('output'), logger.error(f"""Error configuring the Manager IP ({internal_ip})in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent""")
elif 'windows' in os_type :
try:
commands = [
f'(Get-Content -Path "{WAZUH_WINDOWS_CONF}" -Raw) -replace "<address>MANAGER_IP</address>", "<address>{internal_ip}</address>" | Set-Content -Path "{WAZUH_WINDOWS_CONF}"',
"NET START WazuhSvc"
]

Executor.execute_commands(inventory_path, commands)
assert internal_ip in Executor.execute_command(inventory_path, f'cat {WAZUH_CONF}'), logger.error(f'Error configuring the Manager IP ({internal_ip}) in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent')
ConnectionManager.execute_commands(inventory_path, commands)
except Exception as e:
raise Exception(f'Error registering agent. Error executing: {commands} with error: {e}')

result = ConnectionManager.execute_commands(inventory_path, f'Get-Content "{WAZUH_WINDOWS_CONF}"')
assert internal_ip in result.get('output'), logger.error(f'Error configuring the Manager IP ({internal_ip})in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent')

@staticmethod
def set_protocol_agent_connection(inventory_path, protocol):
commands = [
f"sed -i 's/<protocol>[^<]*<\/protocol>/<protocol>{protocol}<\/protocol>/g' {WAZUH_CONF}",
"systemctl restart wazuh-agent"
]
os_type = HostInformation.get_os_type(inventory_path)

if 'linux' in os_type:
commands = [
f"sed -i 's/<protocol>[^<]*<\/protocol>/<protocol>{protocol}<\/protocol>/g' {WAZUH_CONF}",
"systemctl restart wazuh-agent"
]

Executor.execute_commands(inventory_path, commands)
assert protocol in Executor.execute_command(inventory_path, f'cat {WAZUH_CONF}'), logger.error(f'Error configuring the protocol ({protocol}) in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent')
ConnectionManager.execute_commands(inventory_path, commands)
result = ConnectionManager.execute_commands(inventory_path, f'cat {WAZUH_CONF}')
assert protocol in result.get('output'), logger.error(f'Error configuring the protocol ({protocol}) in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent')
elif 'windows' in os_type :
commands = [
f"(Get-Content -Path '{WAZUH_WINDOWS_CONF}') -replace '<protocol>[^<]*<\/protocol>', '<protocol>{protocol}</protocol>' | Set-Content -Path '{WAZUH_WINDOWS_CONF}'"
]

ConnectionManager.execute_commands(inventory_path, commands)
result = ConnectionManager.execute_commands(inventory_path, f'Get-Content -Path "{WAZUH_WINDOWS_CONF}"')
assert protocol in result.get('output'), logger.error(f'Error configuring the protocol ({protocol}) in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent')


@staticmethod
Expand Down Expand Up @@ -150,7 +181,7 @@ def uninstall_agent(inventory_path, wazuh_version=None, wazuh_revision=None) ->
commands.extend(system_commands)
elif 'windows' in os_type:
commands.extend([
f"msiexec.exe /x wazuh-agent-{wazuh_version}-1.msi /qn"
f"msiexec.exe /x $env:TEMP\wazuh-agent.msi /qn"
])
elif 'macos' in os_type:
commands.extend([
Expand All @@ -165,7 +196,7 @@ def uninstall_agent(inventory_path, wazuh_version=None, wazuh_revision=None) ->
])

logger.info(f'Uninstalling Agent in {HostInformation.get_os_name_and_version_from_inventory(inventory_path)}')
Executor.execute_commands(inventory_path, commands)
ConnectionManager.execute_commands(inventory_path, commands)


@staticmethod
Expand All @@ -188,7 +219,7 @@ def _uninstall_agent_callback(wazuh_params, agent_params):
def perform_action_and_scan(agent_params, action_callback) -> dict:
"""
Takes scans using filters, the callback action and compares the result

Args:
agent_params (str): agent parameters
callbak (cb): callback (action)
Expand Down Expand Up @@ -250,7 +281,7 @@ def perform_action_and_scan(agent_params, action_callback) -> dict:
def perform_install_and_scan_for_agent(agent_params, agent_name, wazuh_params) -> None:
"""
Coordinates the action of install the agent and compares the checkfiles

Args:
agent_params (str): agent parameters
wazuh_params (str): wazuh parameters
Expand All @@ -259,14 +290,14 @@ def perform_install_and_scan_for_agent(agent_params, agent_name, wazuh_params) -
action_callback = lambda: WazuhAgent._install_agent_callback(wazuh_params, agent_name, agent_params)
result = WazuhAgent.perform_action_and_scan(agent_params, action_callback)
logger.info(f'Pre and post install checkfile comparison in {HostInformation.get_os_name_and_version_from_inventory(agent_params)}: {result}')
WazuhAgent.assert_results(result)
WazuhAgent.assert_results(result, agent_params)


@staticmethod
def perform_uninstall_and_scan_for_agent(agent_params, wazuh_params) -> None:
"""
Coordinates the action of uninstall the agent and compares the checkfiles

Args:
agent_params (str): agent parameters
wazuh_params (str): wazuh parameters
Expand All @@ -275,23 +306,29 @@ def perform_uninstall_and_scan_for_agent(agent_params, wazuh_params) -> None:
action_callback = lambda: WazuhAgent._uninstall_agent_callback(wazuh_params, agent_params)
result = WazuhAgent.perform_action_and_scan(agent_params, action_callback)
logger.info(f'Pre and post uninstall checkfile comparison in {HostInformation.get_os_name_and_version_from_inventory(agent_params)}: {result}')
WazuhAgent.assert_results(result)
WazuhAgent.assert_results(result, agent_params)


@staticmethod
def assert_results(result) -> None:
def assert_results(result, params = None) -> None:
"""
Gets the status of an agent given its name.

Args:
result (dict): result of comparison between pre and post action scan

"""
categories = ['/root', '/usr/bin', '/usr/sbin', '/boot']
os_type = HostInformation.get_os_type(params)

if os_type == 'linux':
categories = ['/root', '/usr/bin', '/usr/sbin', '/boot']
elif os_type == 'windows':
categories = ['C:\\Program Files', 'C:\\Program Files (x86)','C:\\Users\\vagrant']
actions = ['added', 'modified', 'removed']
# Testing the results
for category in categories:
for action in actions:

assert result[category][action] == [], logger.error(f'{result[category][action]} was found in: {category}{action}')

def areAgent_processes_active(agent_params):
Expand All @@ -304,7 +341,21 @@ def areAgent_processes_active(agent_params):
Returns:
str: Os name.
"""
return bool([int(numero) for numero in Executor.execute_command(agent_params, 'pgrep wazuh').splitlines()])
os_type = HostInformation.get_os_type(agent_params)

if 'linux' in os_type:
result = ConnectionManager.execute_commands(agent_params, 'pgrep wazuh')
if result.get('success'):
return bool([int(numero) for numero in result.get('output').splitlines()])
else:
return False
elif 'windows' in os_type:
result = ConnectionManager.execute_commands(agent_params, 'Get-Process -Name "wazuh-agent" | Format-Table -HideTableHeaders ProcessName')
if result.get('success'):
return 'wazuh-agent' in result.get('output')
else:
return False


def isAgent_port_open(agent_params):
"""
Expand All @@ -316,7 +367,15 @@ def isAgent_port_open(agent_params):
Returns:
str: Os name.
"""
return 'ESTAB' in Executor.execute_command(agent_params, 'ss -t -a -n | grep ":1514" | grep ESTAB')

os_type = HostInformation.get_os_type(agent_params)
if 'linux' in os_type:
result = ConnectionManager.execute_commands(agent_params, 'ss -t -a -n | grep ":1514" | grep ESTAB')
return result.get('success')
elif 'windows' in os_type :
result = ConnectionManager.execute_commands(agent_params, 'netstat -ano | Select-String -Pattern "TCP" | Select-String -Pattern "ESTABLISHED" | Select-String -Pattern ":1514"')
return 'ESTABLISHED' in result.get('output')


def get_agents_information(wazuh_api: WazuhAPI) -> list:
"""
Expand All @@ -337,17 +396,20 @@ def get_agents_information(wazuh_api: WazuhAPI) -> list:
def get_agent_status(wazuh_api: WazuhAPI, agent_name) -> str:
"""
Function to get the status of an agent given its name.

Args:
- agents_data (list): List of dictionaries containing agents' data.
- agent_name (str): Name of the agent whose status is to be obtained.

Returns:
- str: Status of the agent if found in the data, otherwise returns None.
"""
response = requests.get(f"{wazuh_api.api_url}/agents", headers=wazuh_api.headers, verify=False)

for agent in eval(response.text)['data']['affected_items']:
if agent.get('name') == agent_name:


return agent.get('status')

return None
Expand Down
7 changes: 7 additions & 0 deletions deployability/modules/testing/tests/helpers/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
CONFIGURATIONS_DIR = Path(WAZUH_ROOT, "etc")
WAZUH_CONF = Path(CONFIGURATIONS_DIR, "ossec.conf")
CLIENT_KEYS = Path(CONFIGURATIONS_DIR, "client.keys")

WINDOWS_ROOT_DIR = Path("C:", "Program Files (x86)", "ossec-agent")
WINDOWS_CONFIGURATIONS_DIR = Path(WINDOWS_ROOT_DIR, "etc")
WAZUH_WINDOWS_CONF = Path(WINDOWS_ROOT_DIR, "ossec.conf")
WINDOWS_CLIENT_KEYS = Path(WINDOWS_ROOT_DIR, "client.keys")
WINDOWS_VERSION = Path(WINDOWS_ROOT_DIR, "VERSION")
WINDOWS_REVISION = Path(WINDOWS_ROOT_DIR, "REVISION")
# Binaries paths
BINARIES_DIR = Path(WAZUH_ROOT, "bin")
WAZUH_CONTROL = Path(BINARIES_DIR, "wazuh-control")
Expand Down
Loading