diff --git a/gvm/protocols/gmp/_gmpnext.py b/gvm/protocols/gmp/_gmpnext.py index 11605f46..c9b55dd1 100644 --- a/gvm/protocols/gmp/_gmpnext.py +++ b/gvm/protocols/gmp/_gmpnext.py @@ -1813,6 +1813,56 @@ def export_scan_report( ) ) + def export_audit_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 an audit 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 audit 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_audit_report GMP command. + + Raises: + RequiredArgument: If report_id or format_id is not provided. + """ + return self._send_request_and_transform_response( + AuditReport.export_audit_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, + ) + ) + def get_report_exports( self, ) -> T: diff --git a/gvm/protocols/gmp/requests/next/_audit_report.py b/gvm/protocols/gmp/requests/next/_audit_report.py index 67a92a19..46ee7902 100644 --- a/gvm/protocols/gmp/requests/next/_audit_report.py +++ b/gvm/protocols/gmp/requests/next/_audit_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_audit_report( cmd.add_filter(filter_string, filter_id) return cmd + + @classmethod + def export_audit_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 an audit 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 audit 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_audit_report GMP command. + + Raises: + RequiredArgument: If report_id is not provided. + """ + if not report_id: + raise RequiredArgument( + function=cls.export_audit_report.__name__, + argument="report_id", + ) + + cmd = XmlCommand("export_audit_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/audit_report/__init__.py b/tests/protocols/gmpnext/entities/audit_report/__init__.py index 13df4618..f7e2ed9a 100644 --- a/tests/protocols/gmpnext/entities/audit_report/__init__.py +++ b/tests/protocols/gmpnext/entities/audit_report/__init__.py @@ -3,6 +3,9 @@ # SPDX-License-Identifier: GPL-3.0-or-later # +from .test_export_audit_report import ( + GmpExportAuditReportTestMixin, +) from .test_get_audit_report import ( GmpGetAuditReportTestMixin, ) @@ -11,6 +14,7 @@ ) __all__ = ( + "GmpExportAuditReportTestMixin", "GmpGetAuditReportLegacyTestMixin", "GmpGetAuditReportTestMixin", ) diff --git a/tests/protocols/gmpnext/entities/audit_report/test_export_audit_report.py b/tests/protocols/gmpnext/entities/audit_report/test_export_audit_report.py new file mode 100644 index 00000000..e02daf25 --- /dev/null +++ b/tests/protocols/gmpnext/entities/audit_report/test_export_audit_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 GmpExportAuditReportTestMixin: + def test_export_audit_report_without_report_id(self): + with self.assertRaises(RequiredArgument): + self.gmp.export_audit_report(None, format_id="f1") + + with self.assertRaises(RequiredArgument): + self.gmp.export_audit_report("", format_id="f1") + + def test_export_audit_report(self): + self.gmp.export_audit_report( + report_id="r1", + format_id="f1", + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_export_audit_report_with_config_id(self): + self.gmp.export_audit_report( + report_id="r1", + format_id="f1", + config_id="c1", + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_export_audit_report_with_filter_string(self): + self.gmp.export_audit_report( + report_id="r1", + format_id="f1", + filter_string="compliance_levels=yniu", + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_export_audit_report_with_ignore_pagination(self): + self.gmp.export_audit_report( + report_id="r1", + format_id="f1", + ignore_pagination=True, + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_export_audit_report_with_lean(self): + self.gmp.export_audit_report( + report_id="r1", + format_id="f1", + lean=True, + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_export_audit_report_with_notes_details(self): + self.gmp.export_audit_report( + report_id="r1", + format_id="f1", + notes_details=True, + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_export_audit_report_with_overrides_details(self): + self.gmp.export_audit_report( + report_id="r1", + format_id="f1", + overrides_details=True, + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_export_audit_report_with_result_tags(self): + self.gmp.export_audit_report( + report_id="r1", + format_id="f1", + result_tags=True, + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_export_audit_report_with_all_arguments(self): + self.gmp.export_audit_report( + report_id="r1", + format_id="f1", + config_id="c1", + filter_string="compliance_levels=yniu", + 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_audit_report.py b/tests/protocols/gmpnext/entities/test_audit_report.py index b77d3608..35dd4730 100644 --- a/tests/protocols/gmpnext/entities/test_audit_report.py +++ b/tests/protocols/gmpnext/entities/test_audit_report.py @@ -5,6 +5,7 @@ from ...gmpnext import GMPTestCase from ...gmpnext.entities.audit_report import ( + GmpExportAuditReportTestMixin, GmpGetAuditReportLegacyTestMixin, GmpGetAuditReportTestMixin, ) @@ -18,3 +19,7 @@ class GmpGetAuditReportLegacyTestCase( GmpGetAuditReportLegacyTestMixin, GMPTestCase ): pass + + +class GmpExportAuditReportTestCase(GmpExportAuditReportTestMixin, GMPTestCase): + pass