diff --git a/gvm/protocols/gmp/_gmpnext.py b/gvm/protocols/gmp/_gmpnext.py index bd498816d..dc271e12d 100644 --- a/gvm/protocols/gmp/_gmpnext.py +++ b/gvm/protocols/gmp/_gmpnext.py @@ -306,6 +306,29 @@ def sync_agents(self) -> T: """Trigger agents synchronization from all agent controllers.""" return self._send_request_and_transform_response(Agents.sync_agents()) + def get_agent_support_bundle( + self, + agent_id: EntityID, + days: int = 0, + ) -> T: + """Request a support bundle for an agent. + + Args: + agent_id: ID of the agent to get the support bundle for. + days: Number of days of logs to include. If None, zero is sent so the + Agent Controller uses its configured default. + + Raises: + RequiredArgument: If agent_id is missing. + ValueError: If days is negative. + """ + return self._send_request_and_transform_response( + Agents.get_agent_support_bundle( + agent_id, + days=days, + ) + ) + def create_credential_store_credential( self, name: str, diff --git a/gvm/protocols/gmp/requests/next/_agents.py b/gvm/protocols/gmp/requests/next/_agents.py index b9fdc4121..361caef6e 100644 --- a/gvm/protocols/gmp/requests/next/_agents.py +++ b/gvm/protocols/gmp/requests/next/_agents.py @@ -431,3 +431,36 @@ def modify_agent_control_scan_config( def sync_agents(cls) -> Request: """Trigger agents synchronization from all agent controllers.""" return XmlCommand("sync_agents") + + @classmethod + def get_agent_support_bundle( + cls, + agent_id: EntityID, + *, + days: int = 0, + ) -> Request: + """Request a support bundle for an agent. + + Args: + agent_id: ID of the agent to get the support bundle for. + days: Number of days of logs to include. If None, zero is sent so the + Agent Controller uses its configured default. + + Raises: + RequiredArgument: If agent_id is missing. + ValueError: If days is negative. + """ + if not agent_id: + raise RequiredArgument( + function=cls.get_agent_support_bundle.__name__, + argument="agent_id", + ) + + if days < 0: + raise ValueError("days must be greater than or equal to zero") + + cmd = XmlCommand("get_agent_support_bundle") + cmd.set_attribute("agent_uuid", str(agent_id)) + cmd.set_attribute("days", str(days)) + + return cmd diff --git a/tests/protocols/gmpnext/entities/agents/test_get_agent_support_bundle.py b/tests/protocols/gmpnext/entities/agents/test_get_agent_support_bundle.py new file mode 100644 index 000000000..359a20fc1 --- /dev/null +++ b/tests/protocols/gmpnext/entities/agents/test_get_agent_support_bundle.py @@ -0,0 +1,56 @@ +# SPDX-FileCopyrightText: 2026 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + +from gvm.errors import RequiredArgument + + +class GmpGetAgentSupportBundleTestMixin: + def test_get_agent_support_bundle(self): + self.gmp.get_agent_support_bundle( + agent_id="agent-123", + days=7, + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_agent_support_bundle_without_days_uses_zero(self): + self.gmp.get_agent_support_bundle( + agent_id="agent-123", + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_agent_support_bundle_with_zero_days(self): + self.gmp.get_agent_support_bundle( + agent_id="agent-123", + days=0, + ) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_agent_support_bundle_without_agent_id(self): + with self.assertRaises(RequiredArgument): + self.gmp.get_agent_support_bundle( + agent_id=None, + days=7, + ) + + with self.assertRaises(RequiredArgument): + self.gmp.get_agent_support_bundle( + agent_id="", + days=7, + ) + + def test_get_agent_support_bundle_with_negative_days(self): + with self.assertRaises(ValueError): + self.gmp.get_agent_support_bundle( + agent_id="agent-123", + days=-1, + ) diff --git a/tests/protocols/gmpnext/entities/test_agents.py b/tests/protocols/gmpnext/entities/test_agents.py index 16d983476..8299e5491 100644 --- a/tests/protocols/gmpnext/entities/test_agents.py +++ b/tests/protocols/gmpnext/entities/test_agents.py @@ -7,6 +7,9 @@ from .agents.test_delete_agents import ( GmpDeleteAgentsTestMixin, ) +from .agents.test_get_agent_support_bundle import ( + GmpGetAgentSupportBundleTestMixin, +) from .agents.test_get_agents import ( GmpGetAgentsTestMixin, ) @@ -39,3 +42,9 @@ class GMPModifyAgentControllerScanConfigTestCase( class GMPSyncAgentsTestCase(GmpSyncAgentsTestMixin, GMPTestCase): pass + + +class GmpGetAgentSupportBundleTestCase( + GmpGetAgentSupportBundleTestMixin, GMPTestCase +): + pass diff --git a/uv.lock b/uv.lock index 8edf42ff5..1589d94e8 100644 --- a/uv.lock +++ b/uv.lock @@ -1267,7 +1267,7 @@ wheels = [ [[package]] name = "python-gvm" -version = "27.3.2.dev1" +version = "27.4.1.dev1" source = { editable = "." } dependencies = [ { name = "httpx", extra = ["http2"] },