From 5b432c8620e5389ba75c5f8f1cd915b54ae6f98d Mon Sep 17 00:00:00 2001 From: ozgen Date: Fri, 8 May 2026 10:23:01 +0200 Subject: [PATCH 1/3] add: add get_report_vulns GMP request Implement the get_report_vulns GMP request command. Add unit tests to verify required arguments, filters, pagination handling, and details output. --- gvm/protocols/gmp/_gmpnext.py | 31 +++++++++++ gvm/protocols/gmp/requests/next/__init__.py | 4 ++ .../gmp/requests/next/_report_vulns.py | 46 ++++++++++++++++ .../report_vulns/test_get_report_vulns.py | 55 +++++++++++++++++++ .../gmpnext/entities/test_report_vulns.py | 13 +++++ 5 files changed, 149 insertions(+) create mode 100644 gvm/protocols/gmp/requests/next/_report_vulns.py create mode 100644 tests/protocols/gmpnext/entities/report_vulns/test_get_report_vulns.py create mode 100644 tests/protocols/gmpnext/entities/test_report_vulns.py diff --git a/gvm/protocols/gmp/_gmpnext.py b/gvm/protocols/gmp/_gmpnext.py index bd55f222..dd85d606 100644 --- a/gvm/protocols/gmp/_gmpnext.py +++ b/gvm/protocols/gmp/_gmpnext.py @@ -27,6 +27,7 @@ ReportOperatingSystems, ReportPorts, ReportTlsCertificates, + ReportVulns, Tasks, ) from .requests.v224 import HostsOrdering @@ -1234,3 +1235,33 @@ def get_report_errors( details=details, ) ) + + def get_report_vulns( + self, + report_id: EntityID, + *, + filter_string: str | None = None, + filter_id: str | None = None, + ignore_pagination: bool | None = None, + details: bool | None = True, + ) -> T: + """Request vulnerabilities of a single report. + + Args: + report_id: UUID of an existing report. + filter_string: Filter term to use to filter results in the report + filter_id: UUID of filter to use to filter results in the report + ignore_pagination: Whether to ignore the filter terms "first" and + "rows". + details: Request additional report vulnerability information details. + Defaults to True. + """ + return self._send_request_and_transform_response( + ReportVulns.get_report_vulns( + report_id=report_id, + filter_string=filter_string, + filter_id=filter_id, + ignore_pagination=ignore_pagination, + details=details, + ) + ) diff --git a/gvm/protocols/gmp/requests/next/__init__.py b/gvm/protocols/gmp/requests/next/__init__.py index 569761bb..ac75c55a 100644 --- a/gvm/protocols/gmp/requests/next/__init__.py +++ b/gvm/protocols/gmp/requests/next/__init__.py @@ -38,6 +38,9 @@ from gvm.protocols.gmp.requests.next._report_tls_certificates import ( ReportTlsCertificates, ) +from gvm.protocols.gmp.requests.next._report_vulns import ( + ReportVulns, +) from gvm.protocols.gmp.requests.next._tasks import Tasks from .._entity_id import EntityID @@ -168,6 +171,7 @@ "ReportOperatingSystems", "ReportPorts", "ReportTlsCertificates", + "ReportVulns", "Reports", "ResourceNames", "ResourceType", diff --git a/gvm/protocols/gmp/requests/next/_report_vulns.py b/gvm/protocols/gmp/requests/next/_report_vulns.py new file mode 100644 index 00000000..5114e40a --- /dev/null +++ b/gvm/protocols/gmp/requests/next/_report_vulns.py @@ -0,0 +1,46 @@ +from gvm.errors import RequiredArgument +from gvm.protocols.core import Request +from gvm.protocols.gmp.requests import EntityID +from gvm.utils import to_bool +from gvm.xml import XmlCommand + + +class ReportVulns: + @classmethod + def get_report_vulns( + cls, + report_id: EntityID, + *, + filter_string: str | None = None, + filter_id: str | None = None, + ignore_pagination: bool | None = None, + details: bool | None = True, + ) -> Request: + """Request vulnerabilities of a single report. + + Args: + report_id: UUID of an existing report. + filter_string: Filter term to use to filter results in the report + filter_id: UUID of filter to use to filter results in the report + ignore_pagination: Whether to ignore the filter terms "first" and + "rows". + details: Request additional report vulnerability information details. + Defaults to True. + """ + cmd = XmlCommand("get_report_vulns") + + if not report_id: + raise RequiredArgument( + function=cls.get_report_vulns.__name__, argument="report_id" + ) + + cmd.set_attribute("report_id", str(report_id)) + + cmd.add_filter(filter_string, filter_id) + + if ignore_pagination is not None: + cmd.set_attribute("ignore_pagination", to_bool(ignore_pagination)) + + cmd.set_attribute("details", to_bool(details)) + + return cmd diff --git a/tests/protocols/gmpnext/entities/report_vulns/test_get_report_vulns.py b/tests/protocols/gmpnext/entities/report_vulns/test_get_report_vulns.py new file mode 100644 index 00000000..55d7fd8e --- /dev/null +++ b/tests/protocols/gmpnext/entities/report_vulns/test_get_report_vulns.py @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2026 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +from gvm.errors import RequiredArgument + + +class GmpGetReportVulnsTestMixin: + def test_get_report_vulns_without_id(self): + with self.assertRaises(RequiredArgument): + self.gmp.get_report_vulns(None) + + with self.assertRaises(RequiredArgument): + self.gmp.get_report_vulns("") + + def test_get_report_vulns_with_filter_string(self): + self.gmp.get_report_vulns(report_id="r1", filter_string="name=foo") + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_report_vulns_with_filter_id(self): + self.gmp.get_report_vulns(report_id="r1", filter_id="f1") + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_report_vulns_with_ignore_pagination(self): + self.gmp.get_report_vulns(report_id="r1", ignore_pagination=True) + + self.connection.send.has_been_called_with( + b'' + ) + + self.gmp.get_report_vulns(report_id="r1", ignore_pagination=False) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_report_vulns_with_details(self): + self.gmp.get_report_vulns(report_id="r1", details=True) + + self.connection.send.has_been_called_with( + b'' + ) + + self.gmp.get_report_vulns(report_id="r1", details=False) + + self.connection.send.has_been_called_with( + b'' + ) diff --git a/tests/protocols/gmpnext/entities/test_report_vulns.py b/tests/protocols/gmpnext/entities/test_report_vulns.py new file mode 100644 index 00000000..66b3e6f8 --- /dev/null +++ b/tests/protocols/gmpnext/entities/test_report_vulns.py @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2026 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +from ...gmpnext import GMPTestCase +from .report_vulns.test_get_report_vulns import ( + GmpGetReportVulnsTestMixin, +) + + +class GmpGetReportVulnsTestCase(GmpGetReportVulnsTestMixin, GMPTestCase): + pass From 18cc96b52b5c9cca83cff72294a645fa26319fc4 Mon Sep 17 00:00:00 2001 From: ozgen Date: Fri, 8 May 2026 10:26:44 +0200 Subject: [PATCH 2/3] fix: update uv.lock file for linting issues --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index c8c2ee9e..969592a7 100644 --- a/uv.lock +++ b/uv.lock @@ -1267,7 +1267,7 @@ wheels = [ [[package]] name = "python-gvm" -version = "27.0.3.dev1" +version = "27.1.1.dev1" source = { editable = "." } dependencies = [ { name = "httpx", extra = ["http2"] }, From e0f6af3d224b723e2dce4ff35015ef21a40824c9 Mon Sep 17 00:00:00 2001 From: ozgen Date: Fri, 8 May 2026 10:51:37 +0200 Subject: [PATCH 3/3] change: rename vuns to vulnerabilities for clarity --- gvm/protocols/gmp/_gmpnext.py | 6 ++--- gvm/protocols/gmp/requests/next/__init__.py | 6 ++--- ...rt_vulns.py => _report_vulnerabilities.py} | 7 +++--- .../test_get_report_vulnerabilities.py} | 24 ++++++++++++------- .../entities/test_report_vulnerabilities.py | 15 ++++++++++++ .../gmpnext/entities/test_report_vulns.py | 13 ---------- 6 files changed, 40 insertions(+), 31 deletions(-) rename gvm/protocols/gmp/requests/next/{_report_vulns.py => _report_vulnerabilities.py} (89%) rename tests/protocols/gmpnext/entities/{report_vulns/test_get_report_vulns.py => report_vulnerabilities/test_get_report_vulnerabilities.py} (65%) create mode 100644 tests/protocols/gmpnext/entities/test_report_vulnerabilities.py delete mode 100644 tests/protocols/gmpnext/entities/test_report_vulns.py diff --git a/gvm/protocols/gmp/_gmpnext.py b/gvm/protocols/gmp/_gmpnext.py index dd85d606..83768976 100644 --- a/gvm/protocols/gmp/_gmpnext.py +++ b/gvm/protocols/gmp/_gmpnext.py @@ -27,7 +27,7 @@ ReportOperatingSystems, ReportPorts, ReportTlsCertificates, - ReportVulns, + ReportVulnerabilities, Tasks, ) from .requests.v224 import HostsOrdering @@ -1236,7 +1236,7 @@ def get_report_errors( ) ) - def get_report_vulns( + def get_report_vulnerabilities( self, report_id: EntityID, *, @@ -1257,7 +1257,7 @@ def get_report_vulns( Defaults to True. """ return self._send_request_and_transform_response( - ReportVulns.get_report_vulns( + ReportVulnerabilities.get_report_vulnerabilities( report_id=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 ac75c55a..71c2cd28 100644 --- a/gvm/protocols/gmp/requests/next/__init__.py +++ b/gvm/protocols/gmp/requests/next/__init__.py @@ -38,8 +38,8 @@ from gvm.protocols.gmp.requests.next._report_tls_certificates import ( ReportTlsCertificates, ) -from gvm.protocols.gmp.requests.next._report_vulns import ( - ReportVulns, +from gvm.protocols.gmp.requests.next._report_vulnerabilities import ( + ReportVulnerabilities, ) from gvm.protocols.gmp.requests.next._tasks import Tasks @@ -171,7 +171,7 @@ "ReportOperatingSystems", "ReportPorts", "ReportTlsCertificates", - "ReportVulns", + "ReportVulnerabilities", "Reports", "ResourceNames", "ResourceType", diff --git a/gvm/protocols/gmp/requests/next/_report_vulns.py b/gvm/protocols/gmp/requests/next/_report_vulnerabilities.py similarity index 89% rename from gvm/protocols/gmp/requests/next/_report_vulns.py rename to gvm/protocols/gmp/requests/next/_report_vulnerabilities.py index 5114e40a..a5a9b18a 100644 --- a/gvm/protocols/gmp/requests/next/_report_vulns.py +++ b/gvm/protocols/gmp/requests/next/_report_vulnerabilities.py @@ -5,9 +5,9 @@ from gvm.xml import XmlCommand -class ReportVulns: +class ReportVulnerabilities: @classmethod - def get_report_vulns( + def get_report_vulnerabilities( cls, report_id: EntityID, *, @@ -31,7 +31,8 @@ def get_report_vulns( if not report_id: raise RequiredArgument( - function=cls.get_report_vulns.__name__, argument="report_id" + function=cls.get_report_vulnerabilities.__name__, + argument="report_id", ) cmd.set_attribute("report_id", str(report_id)) diff --git a/tests/protocols/gmpnext/entities/report_vulns/test_get_report_vulns.py b/tests/protocols/gmpnext/entities/report_vulnerabilities/test_get_report_vulnerabilities.py similarity index 65% rename from tests/protocols/gmpnext/entities/report_vulns/test_get_report_vulns.py rename to tests/protocols/gmpnext/entities/report_vulnerabilities/test_get_report_vulnerabilities.py index 55d7fd8e..a823ce61 100644 --- a/tests/protocols/gmpnext/entities/report_vulns/test_get_report_vulns.py +++ b/tests/protocols/gmpnext/entities/report_vulnerabilities/test_get_report_vulnerabilities.py @@ -6,49 +6,55 @@ from gvm.errors import RequiredArgument -class GmpGetReportVulnsTestMixin: +class GmpGetReportVulnerabilitiesTestMixin: def test_get_report_vulns_without_id(self): with self.assertRaises(RequiredArgument): - self.gmp.get_report_vulns(None) + self.gmp.get_report_vulnerabilities(None) with self.assertRaises(RequiredArgument): - self.gmp.get_report_vulns("") + self.gmp.get_report_vulnerabilities("") def test_get_report_vulns_with_filter_string(self): - self.gmp.get_report_vulns(report_id="r1", filter_string="name=foo") + self.gmp.get_report_vulnerabilities( + report_id="r1", filter_string="name=foo" + ) self.connection.send.has_been_called_with( b'' ) def test_get_report_vulns_with_filter_id(self): - self.gmp.get_report_vulns(report_id="r1", filter_id="f1") + self.gmp.get_report_vulnerabilities(report_id="r1", filter_id="f1") self.connection.send.has_been_called_with( b'' ) def test_get_report_vulns_with_ignore_pagination(self): - self.gmp.get_report_vulns(report_id="r1", ignore_pagination=True) + self.gmp.get_report_vulnerabilities( + report_id="r1", ignore_pagination=True + ) self.connection.send.has_been_called_with( b'' ) - self.gmp.get_report_vulns(report_id="r1", ignore_pagination=False) + self.gmp.get_report_vulnerabilities( + report_id="r1", ignore_pagination=False + ) self.connection.send.has_been_called_with( b'' ) def test_get_report_vulns_with_details(self): - self.gmp.get_report_vulns(report_id="r1", details=True) + self.gmp.get_report_vulnerabilities(report_id="r1", details=True) self.connection.send.has_been_called_with( b'' ) - self.gmp.get_report_vulns(report_id="r1", details=False) + self.gmp.get_report_vulnerabilities(report_id="r1", details=False) self.connection.send.has_been_called_with( b'' diff --git a/tests/protocols/gmpnext/entities/test_report_vulnerabilities.py b/tests/protocols/gmpnext/entities/test_report_vulnerabilities.py new file mode 100644 index 00000000..19f99928 --- /dev/null +++ b/tests/protocols/gmpnext/entities/test_report_vulnerabilities.py @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2026 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +from ...gmpnext import GMPTestCase +from .report_vulnerabilities.test_get_report_vulnerabilities import ( + GmpGetReportVulnerabilitiesTestMixin, +) + + +class GmpGetReportVulnerabilitiesTestCase( + GmpGetReportVulnerabilitiesTestMixin, GMPTestCase +): + pass diff --git a/tests/protocols/gmpnext/entities/test_report_vulns.py b/tests/protocols/gmpnext/entities/test_report_vulns.py deleted file mode 100644 index 66b3e6f8..00000000 --- a/tests/protocols/gmpnext/entities/test_report_vulns.py +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-FileCopyrightText: 2026 Greenbone AG -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -from ...gmpnext import GMPTestCase -from .report_vulns.test_get_report_vulns import ( - GmpGetReportVulnsTestMixin, -) - - -class GmpGetReportVulnsTestCase(GmpGetReportVulnsTestMixin, GMPTestCase): - pass