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