From ae018e54d15edda0ac1158e5a87299e939dc8728 Mon Sep 17 00:00:00 2001 From: ozgen Date: Tue, 21 Jul 2026 15:34:40 +0200 Subject: [PATCH] add: add get_scan_report request support --- gvm/protocols/gmp/_gmpnext.py | 29 ++++++++++ gvm/protocols/gmp/requests/next/__init__.py | 2 + .../gmp/requests/next/_scan_report.py | 39 ++++++++++++++ .../gmpnext/entities/scan_reports/__init__.py | 10 ++++ .../scan_reports/test_get_scan_report.py | 54 +++++++++++++++++++ .../gmpnext/entities/test_scan_reports.py | 13 +++++ 6 files changed, 147 insertions(+) create mode 100644 gvm/protocols/gmp/requests/next/_scan_report.py create mode 100644 tests/protocols/gmpnext/entities/scan_reports/__init__.py create mode 100644 tests/protocols/gmpnext/entities/scan_reports/test_get_scan_report.py create mode 100644 tests/protocols/gmpnext/entities/test_scan_reports.py diff --git a/gvm/protocols/gmp/_gmpnext.py b/gvm/protocols/gmp/_gmpnext.py index dc271e12..33841f61 100644 --- a/gvm/protocols/gmp/_gmpnext.py +++ b/gvm/protocols/gmp/_gmpnext.py @@ -30,6 +30,7 @@ ReportPorts, ReportTlsCertificates, ReportVulnerabilities, + ScanReports, Targets, Tasks, WebApplicationTargets, @@ -1642,3 +1643,31 @@ def get_targets( tasks=tasks, ) ) + + def get_scan_report( + self, + scan_report_id: EntityID, + *, + filter_string: str | None = None, + filter_id: str | None = None, + ) -> T: + """ "Request a structured summary of a single scan report. + + Args: + scan_report_id: UUID of an existing scan report. + filter_string: Filter term to apply to the report results. + filter_id: UUID of a saved filter to apply to the report results. + + Returns: + A request for the get_scan_report GMP command. + + Raises: + RequiredArgument: If scan_report_id is not provided. + """ + return self._send_request_and_transform_response( + ScanReports.get_scan_report( + scan_report_id=scan_report_id, + filter_string=filter_string, + filter_id=filter_id, + ) + ) diff --git a/gvm/protocols/gmp/requests/next/__init__.py b/gvm/protocols/gmp/requests/next/__init__.py index 570f20f6..e400a361 100644 --- a/gvm/protocols/gmp/requests/next/__init__.py +++ b/gvm/protocols/gmp/requests/next/__init__.py @@ -44,6 +44,7 @@ from gvm.protocols.gmp.requests.next._report_vulnerabilities import ( ReportVulnerabilities, ) +from gvm.protocols.gmp.requests.next._scan_report import ScanReports from gvm.protocols.gmp.requests.next._targets import AliveTest, Targets from gvm.protocols.gmp.requests.next._tasks import Tasks from gvm.protocols.gmp.requests.next._web_application_targets import ( @@ -184,6 +185,7 @@ "Results", "Roles", "ScanConfigs", + "ScanReports", "ScannerType", "Scanners", "Schedules", diff --git a/gvm/protocols/gmp/requests/next/_scan_report.py b/gvm/protocols/gmp/requests/next/_scan_report.py new file mode 100644 index 00000000..e62c432a --- /dev/null +++ b/gvm/protocols/gmp/requests/next/_scan_report.py @@ -0,0 +1,39 @@ +from gvm.errors import RequiredArgument +from gvm.protocols.core import Request +from gvm.protocols.gmp.requests import EntityID +from gvm.xml import XmlCommand + + +class ScanReports: + @classmethod + def get_scan_report( + cls, + scan_report_id: EntityID, + *, + filter_string: str | None = None, + filter_id: str | None = None, + ) -> Request: + """Request a structured summary of a single scan report. + + Args: + scan_report_id: UUID of an existing scan report. + filter_string: Filter term to apply to the report results. + filter_id: UUID of a saved filter to apply to the report results. + + Returns: + A request for the get_scan_report GMP command. + + Raises: + RequiredArgument: If scan_report_id is not provided. + """ + if not scan_report_id: + raise RequiredArgument( + function=cls.get_scan_report.__name__, + argument="scan_report_id", + ) + + cmd = XmlCommand("get_scan_report") + cmd.set_attribute("scan_report_id", str(scan_report_id)) + cmd.add_filter(filter_string, filter_id) + + return cmd diff --git a/tests/protocols/gmpnext/entities/scan_reports/__init__.py b/tests/protocols/gmpnext/entities/scan_reports/__init__.py new file mode 100644 index 00000000..585512c6 --- /dev/null +++ b/tests/protocols/gmpnext/entities/scan_reports/__init__.py @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2026 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +from .test_get_scan_report import ( + GmpGetScanReportTestMixin, +) + +__all__ = ("GmpGetScanReportTestMixin",) diff --git a/tests/protocols/gmpnext/entities/scan_reports/test_get_scan_report.py b/tests/protocols/gmpnext/entities/scan_reports/test_get_scan_report.py new file mode 100644 index 00000000..afe188d4 --- /dev/null +++ b/tests/protocols/gmpnext/entities/scan_reports/test_get_scan_report.py @@ -0,0 +1,54 @@ +# SPDX-FileCopyrightText: 2026 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +from gvm.errors import RequiredArgument + + +class GmpGetScanReportTestMixin: + def test_get_scan_report_without_id(self): + with self.assertRaises(RequiredArgument): + self.gmp.get_scan_report(None) + + with self.assertRaises(RequiredArgument): + self.gmp.get_scan_report("") + + def test_get_scan_report_with_id(self): + self.gmp.get_scan_report(scan_report_id="r1") + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_scan_report_with_filter_string(self): + self.gmp.get_scan_report( + scan_report_id="r1", + filter_string="name=foo", + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_scan_report_with_filter_id(self): + self.gmp.get_scan_report( + scan_report_id="r1", + filter_id="f1", + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_scan_report_with_filter_string_and_filter_id(self): + self.gmp.get_scan_report( + scan_report_id="r1", + filter_string="name=foo", + filter_id="f1", + ) + + self.connection.send.has_been_called_with( + b'' + ) diff --git a/tests/protocols/gmpnext/entities/test_scan_reports.py b/tests/protocols/gmpnext/entities/test_scan_reports.py new file mode 100644 index 00000000..d4fb2caa --- /dev/null +++ b/tests/protocols/gmpnext/entities/test_scan_reports.py @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2026 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +from ...gmpnext import GMPTestCase +from .scan_reports.test_get_scan_report import ( + GmpGetScanReportTestMixin, +) + + +class GmpGetScanReportTestCase(GmpGetScanReportTestMixin, GMPTestCase): + pass