diff --git a/gvm/protocols/gmp/_gmpnext.py b/gvm/protocols/gmp/_gmpnext.py
index a77d649d..357c236e 100644
--- a/gvm/protocols/gmp/_gmpnext.py
+++ b/gvm/protocols/gmp/_gmpnext.py
@@ -1758,3 +1758,53 @@ def get_audit_report_legacy(
ignore_pagination=ignore_pagination,
details=details,
)
+
+ def export_scan_report(
+ self,
+ report_id: EntityID,
+ format_id: EntityID,
+ *,
+ config_id: EntityID | None = None,
+ filter_string: str | None = None,
+ ignore_pagination: bool = False,
+ lean: bool = False,
+ notes_details: bool = False,
+ overrides_details: bool = False,
+ result_tags: bool = False,
+ ) -> T:
+ """Request an asynchronous export of a scan report.
+
+ If an identical export is already pending or running, the existing
+ report export is returned instead of creating a duplicate.
+
+ Args:
+ report_id: UUID of the scan report to export.
+ format_id: UUID of the report format to apply.
+ config_id: UUID of an optional report configuration.
+ filter_string: Filter term to apply while generating the report.
+ ignore_pagination: Whether pagination settings in the filter
+ should be ignored.
+ lean: Whether lean report data should be generated.
+ notes_details: Whether note details should be included.
+ overrides_details: Whether override details should be included.
+ result_tags: Whether result tags should be included.
+
+ Returns:
+ A request for the export_scan_report GMP command.
+
+ Raises:
+ RequiredArgument: If report_id or format_id is not provided.
+ """
+ return self._send_request_and_transform_response(
+ ScanReports.export_scan_report(
+ report_id=report_id,
+ format_id=format_id,
+ config_id=config_id,
+ filter_string=filter_string,
+ ignore_pagination=ignore_pagination,
+ lean=lean,
+ notes_details=notes_details,
+ overrides_details=overrides_details,
+ result_tags=result_tags,
+ )
+ )
diff --git a/gvm/protocols/gmp/requests/next/_scan_report.py b/gvm/protocols/gmp/requests/next/_scan_report.py
index e62c432a..b7c13589 100644
--- a/gvm/protocols/gmp/requests/next/_scan_report.py
+++ b/gvm/protocols/gmp/requests/next/_scan_report.py
@@ -1,6 +1,7 @@
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
@@ -37,3 +38,76 @@ def get_scan_report(
cmd.add_filter(filter_string, filter_id)
return cmd
+
+ @classmethod
+ def export_scan_report(
+ cls,
+ report_id: EntityID,
+ format_id: EntityID,
+ *,
+ config_id: EntityID | None = None,
+ filter_string: str | None = None,
+ ignore_pagination: bool = False,
+ lean: bool = False,
+ notes_details: bool = False,
+ overrides_details: bool = False,
+ result_tags: bool = False,
+ ) -> Request:
+ """Request an asynchronous export of a scan report.
+
+ If an identical export is already pending or running, the existing
+ report export is returned instead of creating a duplicate.
+
+ Args:
+ report_id: UUID of the scan report to export.
+ format_id: UUID of the report format to apply.
+ config_id: UUID of an optional report configuration.
+ filter_string: Filter term to apply while generating the report.
+ ignore_pagination: Whether pagination settings in the filter
+ should be ignored.
+ lean: Whether lean report data should be generated.
+ notes_details: Whether note details should be included.
+ overrides_details: Whether override details should be included.
+ result_tags: Whether result tags should be included.
+
+ Returns:
+ A request for the export_scan_report GMP command.
+
+ Raises:
+ RequiredArgument: If report_id is not provided.
+ """
+ if not report_id:
+ raise RequiredArgument(
+ function=cls.export_scan_report.__name__,
+ argument="report_id",
+ )
+
+ cmd = XmlCommand("export_scan_report")
+ cmd.set_attribute("report_id", str(report_id))
+ cmd.set_attribute("format_id", str(format_id))
+
+ if config_id:
+ cmd.set_attribute("config_id", str(config_id))
+
+ if filter_string is not None:
+ cmd.set_attribute("filter", filter_string)
+
+ cmd.set_attribute(
+ "ignore_pagination",
+ to_bool(ignore_pagination),
+ )
+ cmd.set_attribute("lean", to_bool(lean))
+ cmd.set_attribute(
+ "notes_details",
+ to_bool(notes_details),
+ )
+ cmd.set_attribute(
+ "overrides_details",
+ to_bool(overrides_details),
+ )
+ cmd.set_attribute(
+ "result_tags",
+ to_bool(result_tags),
+ )
+
+ return cmd
diff --git a/tests/protocols/gmpnext/entities/scan_reports/__init__.py b/tests/protocols/gmpnext/entities/scan_reports/__init__.py
index 585512c6..de5bb5e4 100644
--- a/tests/protocols/gmpnext/entities/scan_reports/__init__.py
+++ b/tests/protocols/gmpnext/entities/scan_reports/__init__.py
@@ -3,8 +3,14 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
+from .test_export_scan_report import (
+ GmpExportScanReportTestMixin,
+)
from .test_get_scan_report import (
GmpGetScanReportTestMixin,
)
-__all__ = ("GmpGetScanReportTestMixin",)
+__all__ = (
+ "GmpExportScanReportTestMixin",
+ "GmpGetScanReportTestMixin",
+)
diff --git a/tests/protocols/gmpnext/entities/scan_reports/test_export_scan_report.py b/tests/protocols/gmpnext/entities/scan_reports/test_export_scan_report.py
new file mode 100644
index 00000000..5a5660fc
--- /dev/null
+++ b/tests/protocols/gmpnext/entities/scan_reports/test_export_scan_report.py
@@ -0,0 +1,138 @@
+# SPDX-FileCopyrightText: 2026 Greenbone AG
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+from gvm.errors import RequiredArgument
+
+
+class GmpExportScanReportTestMixin:
+ def test_export_scan_report_without_report_id(self):
+ with self.assertRaises(RequiredArgument):
+ self.gmp.export_scan_report(None, format_id="f1")
+
+ with self.assertRaises(RequiredArgument):
+ self.gmp.export_scan_report("", format_id="f1")
+
+ def test_export_scan_report(self):
+ self.gmp.export_scan_report(
+ report_id="r1",
+ format_id="f1",
+ )
+
+ self.connection.send.has_been_called_with(
+ b''
+ )
+
+ def test_export_scan_report_with_config_id(self):
+ self.gmp.export_scan_report(
+ report_id="r1",
+ format_id="f1",
+ config_id="c1",
+ )
+
+ self.connection.send.has_been_called_with(
+ b''
+ )
+
+ def test_export_scan_report_with_filter_string(self):
+ self.gmp.export_scan_report(
+ report_id="r1",
+ format_id="f1",
+ filter_string="levels=hml",
+ )
+
+ self.connection.send.has_been_called_with(
+ b''
+ )
+
+ def test_export_scan_report_with_ignore_pagination(self):
+ self.gmp.export_scan_report(
+ report_id="r1",
+ format_id="f1",
+ ignore_pagination=True,
+ )
+
+ self.connection.send.has_been_called_with(
+ b''
+ )
+
+ def test_export_scan_report_with_lean(self):
+ self.gmp.export_scan_report(
+ report_id="r1",
+ format_id="f1",
+ lean=True,
+ )
+
+ self.connection.send.has_been_called_with(
+ b''
+ )
+
+ def test_export_scan_report_with_notes_details(self):
+ self.gmp.export_scan_report(
+ report_id="r1",
+ format_id="f1",
+ notes_details=True,
+ )
+
+ self.connection.send.has_been_called_with(
+ b''
+ )
+
+ def test_export_scan_report_with_overrides_details(self):
+ self.gmp.export_scan_report(
+ report_id="r1",
+ format_id="f1",
+ overrides_details=True,
+ )
+
+ self.connection.send.has_been_called_with(
+ b''
+ )
+
+ def test_export_scan_report_with_result_tags(self):
+ self.gmp.export_scan_report(
+ report_id="r1",
+ format_id="f1",
+ result_tags=True,
+ )
+
+ self.connection.send.has_been_called_with(
+ b''
+ )
+
+ def test_export_scan_report_with_all_arguments(self):
+ self.gmp.export_scan_report(
+ report_id="r1",
+ format_id="f1",
+ config_id="c1",
+ filter_string="levels=hml",
+ ignore_pagination=True,
+ lean=True,
+ notes_details=True,
+ overrides_details=True,
+ result_tags=True,
+ )
+
+ 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
index d4fb2caa..9a889296 100644
--- a/tests/protocols/gmpnext/entities/test_scan_reports.py
+++ b/tests/protocols/gmpnext/entities/test_scan_reports.py
@@ -4,10 +4,15 @@
#
from ...gmpnext import GMPTestCase
-from .scan_reports.test_get_scan_report import (
+from .scan_reports import (
+ GmpExportScanReportTestMixin,
GmpGetScanReportTestMixin,
)
class GmpGetScanReportTestCase(GmpGetScanReportTestMixin, GMPTestCase):
pass
+
+
+class GmpExportScanReportTestCase(GmpExportScanReportTestMixin, GMPTestCase):
+ pass