diff --git a/device_certificate_report/components/data_collection.py b/device_certificate_report/components/data_collection.py index b6aa486..cf683bc 100644 --- a/device_certificate_report/components/data_collection.py +++ b/device_certificate_report/components/data_collection.py @@ -70,22 +70,26 @@ def process_csv_file(csv_file: str) -> List[DeviceInfo]: device = DeviceInfo( device_name=device_names[i] if i < len(device_names) else None, model=model or None, - serial_number=serial_numbers[i] - if i < len(serial_numbers) - else None, + serial_number=( + serial_numbers[i] if i < len(serial_numbers) else None + ), ipv4_address=ipv4_addresses[i] if i < len(ipv4_addresses) else None, device_state=device_states[i] if i < len(device_states) else None, - device_certificate=device_certificates[i] - if i < len(device_certificates) - else None, - device_certificate_expiry_date=device_certificate_expiry_dates[i] - if i < len(device_certificate_expiry_dates) - else None, + device_certificate=( + device_certificates[i] if i < len(device_certificates) else None + ), + device_certificate_expiry_date=( + device_certificate_expiry_dates[i] + if i < len(device_certificate_expiry_dates) + else None + ), software_version=software_version or None, - globalprotect_client=globalprotect_clients[i] - if i < len(globalprotect_clients) - and globalprotect_clients[i] != "0.0.0" - else None, + globalprotect_client=( + globalprotect_clients[i] + if i < len(globalprotect_clients) + and globalprotect_clients[i] != "0.0.0" + else None + ), ) devices.append(device) @@ -147,9 +151,9 @@ def collect_data_from_panorama(panorama: Panorama) -> List[DeviceInfo]: device_certificate=device_certificate or "", device_certificate_expiry_date=device_certificate_expiry_date or "", software_version=software_version or "", - globalprotect_client=globalprotect_client - if globalprotect_client != "0.0.0" - else "", + globalprotect_client=( + globalprotect_client if globalprotect_client != "0.0.0" else "" + ), ) devices.append(device) except Exception as e: @@ -256,8 +260,8 @@ def collect_data_from_firewall(firewall: Firewall) -> DeviceInfo: device_certificate=device_certificate_status or "", device_certificate_expiry_date=device_certificate_expiry_date or "", software_version=software_version or "", - globalprotect_client=globalprotect_client - if globalprotect_client != "0.0.0" - else "", + globalprotect_client=( + globalprotect_client if globalprotect_client != "0.0.0" else "" + ), ) return device diff --git a/device_certificate_report/main.py b/device_certificate_report/main.py index 4026851..5a30dcb 100644 --- a/device_certificate_report/main.py +++ b/device_certificate_report/main.py @@ -315,7 +315,9 @@ def firewall( devices_with_certificates=devices_with_certificates, output_file=output_file if len(output_file) > 0 else f"{hostname}.pdf", ) - typer.echo(f"Report generated at {output_file if len(output_file) > 0 else f'{hostname}.pdf'}") + typer.echo( + f"Report generated at {output_file if len(output_file) > 0 else f'{hostname}.pdf'}" + ) except Exception as e: logger.error(f"Failed to process Firewall: {e}") sys.exit(1) diff --git a/device_certificate_report/utilities/filters.py b/device_certificate_report/utilities/filters.py index 0483c46..95bf0dc 100644 --- a/device_certificate_report/utilities/filters.py +++ b/device_certificate_report/utilities/filters.py @@ -1,7 +1,10 @@ # device_certificate_report/components/filters.py from typing import List, Tuple -from device_certificate_report.config.hardware_families import AffectedModels, UnaffectedModels +from device_certificate_report.config.hardware_families import ( + AffectedModels, + UnaffectedModels, +) from device_certificate_report.config.panos_versions import MinimumPatchedVersions from device_certificate_report.models.device import DeviceInfo from device_certificate_report.components.version import parse_version diff --git a/pyproject.toml b/pyproject.toml index 14616c7..a0c882f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,9 @@ mkdocs = "^1.6.1" mkdocs-material = "^9.5.35" pytest = "^8.3.3" ipdb = "^0.13.13" +black = "^24.8.0" +flake8 = "^7.1.1" +factory-boy = "^3.3.1" [build-system] requires = ["poetry-core"] diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..ec9e3b8 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,8 @@ +# tests/conftest.py + +import pytest +from tests.factories import DeviceInfoFactory + +@pytest.fixture +def sample_device(): + return DeviceInfoFactory() \ No newline at end of file diff --git a/tests/factories.py b/tests/factories.py new file mode 100644 index 0000000..9d49b36 --- /dev/null +++ b/tests/factories.py @@ -0,0 +1,20 @@ +# tests/factories.py + +import factory +from device_certificate_report.models.device import DeviceInfo + +class DeviceInfoFactory(factory.Factory): + class Meta: + model = DeviceInfo + + device_name = factory.Sequence(lambda n: f"device{n}") + model = "PA-220" + serial_number = factory.Sequence(lambda n: f"serial{n}") + ipv4_address = factory.Sequence(lambda n: f"192.168.1.{n}") + device_state = "Connected" + device_certificate = "Valid" + device_certificate_expiry_date = "2024-12-31" + software_version = "10.0.0" + globalprotect_client = "5.2.6" + min_required_version = None + notes = None \ No newline at end of file diff --git a/tests/test_cleaner.py b/tests/test_cleaner.py new file mode 100644 index 0000000..27d14dc --- /dev/null +++ b/tests/test_cleaner.py @@ -0,0 +1,28 @@ +# tests/test_cleaner.py + +from device_certificate_report.utilities.cleaner import clean_html_tags, clean_csv +import csv +import io + +def test_clean_html_tags(): + text = '
"Some;Text";
' + cleaned = clean_html_tags(text) + assert cleaned == '"Some;Text";' + +def test_clean_csv(tmp_path): + input_content = '''"Column1","Column2" +"Data1
","Data2
" +"Data;3","Data;4" +''' + input_file = tmp_path / "input.csv" + output_file = tmp_path / "output.csv" + input_file.write_text(input_content) + + clean_csv(str(input_file), str(output_file)) + + with open(output_file, "r", encoding="utf-8") as f: + reader = csv.reader(f) + rows = list(reader) + assert rows[0] == ['Column1', 'Column2'] + assert rows[1] == ['Data1', 'Data2'] + assert rows[2] == ['Data;3', 'Data;4'] \ No newline at end of file diff --git a/tests/test_data_collection.py b/tests/test_data_collection.py new file mode 100644 index 0000000..2bc77e4 --- /dev/null +++ b/tests/test_data_collection.py @@ -0,0 +1,154 @@ +# tests/test_data_collection.py + +import pytest +from unittest.mock import MagicMock +from device_certificate_report.components.data_collection import ( + process_csv_file, + collect_data_from_panorama, + collect_data_from_firewall, +) +from panos.panorama import Panorama +from panos.firewall import Firewall +import xml.etree.ElementTree as ET + +from tests.factories import DeviceInfoFactory + +def test_process_csv_file(tmp_path): + # Create sample devices using factories + device1 = DeviceInfoFactory() + device2 = DeviceInfoFactory( + device_name="device2", + model="PA-3020", + software_version="9.1.0", + globalprotect_client=None, + ) + + # Create CSV content from devices + csv_content = f"""Device Name,IP Address Serial Number,IP Address IPv4,Status Device State,Status Device Certificate,Status Device Certificate Expiry Date,GlobalProtect Client,Model,Software Version +"{device1.device_name}","{device1.serial_number}","{device1.ipv4_address}","{device1.device_state}","{device1.device_certificate}","{device1.device_certificate_expiry_date}","{device1.globalprotect_client or '0.0.0'}","{device1.model}","{device1.software_version}" +"{device2.device_name}","{device2.serial_number}","{device2.ipv4_address}","{device2.device_state}","{device2.device_certificate}","{device2.device_certificate_expiry_date}","{device2.globalprotect_client or '0.0.0'}","{device2.model}","{device2.software_version}" +""" + csv_file = tmp_path / "test.csv" + csv_file.write_text(csv_content) + + devices = process_csv_file(str(csv_file)) + + assert len(devices) == 2 + assert devices[0].device_name == device1.device_name + assert devices[0].model == device1.model + assert devices[0].software_version == device1.software_version + assert devices[1].device_name == device2.device_name + assert devices[1].globalprotect_client is None # Should be None because it's "0.0.0" + +def test_collect_data_from_panorama(monkeypatch): + # Mock Panorama instance + panorama = Panorama("hostname", "username", "password") + + # Create sample devices using factories + device1 = DeviceInfoFactory() + device2 = DeviceInfoFactory( + device_name="device2", + model="PA-3020", + serial_number="serial2", + ipv4_address="192.168.1.2", + device_state="Disconnected", + device_certificate="Invalid", + device_certificate_expiry_date="2023-11-30", + software_version="9.1.0", + globalprotect_client=None, + ) + + # Create XML response using devices + mock_response = ET.fromstring(f""" +