diff --git a/gvm/protocols/gmp/_gmpnext.py b/gvm/protocols/gmp/_gmpnext.py index 63b27c74..7584d896 100644 --- a/gvm/protocols/gmp/_gmpnext.py +++ b/gvm/protocols/gmp/_gmpnext.py @@ -8,7 +8,7 @@ from .._protocol import T from ._gmp227 import GMPv227 -from .requests.next import AgentInstallers +from .requests.next import AgentGroups, AgentInstallers, Agents class GMPNext(GMPv227[T]): @@ -78,3 +78,199 @@ def get_agent_installer_file(self, agent_installer_id: EntityID) -> T: return self._send_request_and_transform_response( AgentInstallers.get_agent_installer_file(agent_installer_id) ) + + def get_agents( + self, + *, + filter_string: Optional[str] = None, + filter_id: Optional[EntityID] = None, + details: Optional[bool] = None, + ) -> T: + """Request a list of agents. + + Args: + filter_string: Filter term to use for the query. + filter_id: UUID of an existing filter to use for the query. + details: Whether to include detailed agent info. + """ + return self._send_request_and_transform_response( + Agents.get_agents( + filter_string=filter_string, + filter_id=filter_id, + details=details, + ) + ) + + def modify_agents( + self, + agent_ids: list[EntityID], + *, + authorized: Optional[bool] = None, + min_interval: Optional[int] = None, + heartbeat_interval: Optional[int] = None, + schedule: Optional[str] = None, + comment: Optional[str] = None, + ) -> T: + """Modify multiple agents + + Args: + agent_ids: List of agent UUIDs to modify + authorized: Whether the agent is authorized + min_interval: Minimum scan interval + heartbeat_interval: Interval for sending heartbeats + schedule: Cron-style schedule for agent + comment: Comment for the agents + """ + return self._send_request_and_transform_response( + Agents.modify_agents( + agent_ids=agent_ids, + authorized=authorized, + min_interval=min_interval, + heartbeat_interval=heartbeat_interval, + schedule=schedule, + comment=comment, + ) + ) + + def delete_agents(self, agent_ids: list[EntityID]) -> T: + """Delete multiple agents + + Args: + agent_ids: List of agent UUIDs to delete + """ + return self._send_request_and_transform_response( + Agents.delete_agents(agent_ids=agent_ids) + ) + + def get_agent_groups( + self, + *, + filter_string: Optional[str] = None, + filter_id: Optional[EntityID] = None, + trash: Optional[bool] = None, + ) -> T: + """Request a list of agent groups. + + Args: + filter_string: Filter expression to use. + filter_id: UUID of a predefined filter. + trash: If True, return trashed agent groups. + + Returns: + Request object to fetch agent groups. + """ + return self._send_request_and_transform_response( + AgentGroups.get_agent_groups( + filter_string=filter_string, + filter_id=filter_id, + trash=trash, + ) + ) + + def get_agent_group(self, agent_group_id: EntityID) -> T: + """Request a single agent group by ID. + + Args: + agent_group_id: UUID of the agent group. + + Raises: + RequiredArgument: If agent_group_id is not provided. + + Returns: + Request object to fetch the specific agent group. + """ + return self._send_request_and_transform_response( + AgentGroups.get_agent_group( + agent_group_id=agent_group_id, + ) + ) + + def create_agent_group( + self, + name: str, + agent_ids: list[str], + *, + comment: Optional[str] = None, + ) -> T: + """Create a new agent group. + + Args: + name: Name of the new agent group. + agent_ids: List of agent UUIDs to include in the group (required). + comment: Optional comment for the group. + + Raises: + RequiredArgument: If name or agent_ids is not provided. + """ + return self._send_request_and_transform_response( + AgentGroups.create_agent_group( + name=name, + comment=comment, + agent_ids=agent_ids, + ) + ) + + def modify_agent_group( + self, + agent_group_id: EntityID, + *, + name: Optional[str] = None, + comment: Optional[str] = None, + agent_ids: Optional[list[str]] = None, + ) -> T: + """Modify an existing agent group. + + Args: + agent_group_id: UUID of the group to modify. + name: Optional new name for the group. + comment: Optional comment for the group. + agent_ids: Optional list of agent UUIDs to set for the group. + + Raises: + RequiredArgument: If agent_group_id is not provided. + """ + return self._send_request_and_transform_response( + AgentGroups.modify_agent_group( + agent_group_id=agent_group_id, + name=name, + comment=comment, + agent_ids=agent_ids, + ) + ) + + def delete_agent_group( + self, + agent_group_id: EntityID, + ultimate: bool = False, + ) -> T: + """Delete an existing agent group. + + Args: + agent_group_id: UUID of the group to delete. + ultimate: Whether to permanently delete or move to trashcan. + + Raises: + RequiredArgument: If agent_group_id is not provided. + """ + return self._send_request_and_transform_response( + AgentGroups.delete_agent_group( + agent_group_id=agent_group_id, + ultimate=ultimate, + ) + ) + + def clone_agent_group( + self, + agent_group_id: EntityID, + ) -> T: + """Clone an existing agent group + + Args: + agent_group_id: UUID of an existing agent group to clone from + + Returns: + Request: GMP command to create a new agent group based on a copy + """ + return self._send_request_and_transform_response( + AgentGroups.clone_agent_group(agent_group_id) + ) diff --git a/gvm/protocols/gmp/requests/next/__init__.py b/gvm/protocols/gmp/requests/next/__init__.py index e60c1a17..b42ae874 100644 --- a/gvm/protocols/gmp/requests/next/__init__.py +++ b/gvm/protocols/gmp/requests/next/__init__.py @@ -2,7 +2,9 @@ # # SPDX-License-Identifier: GPL-3.0-or-later +from gvm.protocols.gmp.requests.next._agent_groups import AgentGroups from gvm.protocols.gmp.requests.next._agent_installers import AgentInstallers +from gvm.protocols.gmp.requests.next._agents import Agents from .._entity_id import EntityID from .._version import Version @@ -77,7 +79,9 @@ ) __all__ = ( + "AgentGroups", "AgentInstallers", + "Agents", "Aggregates", "AggregateStatistic", "Alerts", diff --git a/gvm/protocols/gmp/requests/next/_agent_groups.py b/gvm/protocols/gmp/requests/next/_agent_groups.py new file mode 100644 index 00000000..0753ef23 --- /dev/null +++ b/gvm/protocols/gmp/requests/next/_agent_groups.py @@ -0,0 +1,193 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + +from typing import Optional + +from gvm.errors import RequiredArgument +from gvm.protocols.core import Request +from gvm.protocols.gmp.requests._entity_id import EntityID +from gvm.utils import to_bool +from gvm.xml import XmlCommand + + +class AgentGroups: + @classmethod + def create_agent_group( + cls, + name: str, + agent_ids: list[str], + *, + comment: Optional[str] = None, + ) -> Request: + """Create a new agent group. + + Args: + name: Name of the new agent group. + agent_ids: List of agent UUIDs to include in the group (required). + comment: Optional comment for the group. + + Raises: + RequiredArgument: If name or agent_ids is not provided. + """ + if not name: + raise RequiredArgument( + function=cls.create_agent_group.__name__, argument="name" + ) + + if not agent_ids: + raise RequiredArgument( + function=cls.create_agent_group.__name__, argument="agent_ids" + ) + + cmd = XmlCommand("create_agent_group") + cmd.add_element("name", name) + + if comment: + cmd.add_element("comment", comment) + + agents_element = cmd.add_element("agents") + for agent_id in agent_ids: + agents_element.add_element("agent", attrs={"id": agent_id}) + + return cmd + + @classmethod + def clone_agent_group(cls, agent_group_id: EntityID) -> Request: + """Clone an existing agent group + + Args: + agent_group_id: UUID of an existing agent group to clone from + + Returns: + Request: GMP command to create a new agent group based on a copy + """ + if not agent_group_id: + raise RequiredArgument( + function=cls.clone_agent_group.__name__, + argument="agent_group_id", + ) + + cmd = XmlCommand("create_agent_group") + cmd.add_element("copy", str(agent_group_id)) + + return cmd + + @classmethod + def modify_agent_group( + cls, + agent_group_id: EntityID, + *, + name: Optional[str] = None, + comment: Optional[str] = None, + agent_ids: Optional[list[str]] = None, + ) -> Request: + """Modify an existing agent group. + + Args: + agent_group_id: UUID of the group to modify. + name: Optional new name for the group. + comment: Optional comment for the group. + agent_ids: Optional list of agent UUIDs to set for the group. + + Raises: + RequiredArgument: If agent_group_id is not provided. + """ + if not agent_group_id: + raise RequiredArgument( + function=cls.modify_agent_group.__name__, + argument="agent_group_id", + ) + + cmd = XmlCommand("modify_agent_group") + cmd.set_attribute("agent_group_id", str(agent_group_id)) + + if name: + cmd.add_element("name", name) + + if comment: + cmd.add_element("comment", comment) + + if agent_ids: + agents_element = cmd.add_element("agents") + for agent_id in agent_ids: + agents_element.add_element("agent", attrs={"id": agent_id}) + + return cmd + + @classmethod + def delete_agent_group( + cls, + agent_group_id: EntityID, + *, + ultimate: Optional[bool] = False, + ) -> Request: + """Delete an existing agent group. + + Args: + agent_group_id: UUID of the group to delete. + ultimate: Whether to permanently delete or move to trashcan. + + Raises: + RequiredArgument: If agent_group_id is not provided. + """ + if not agent_group_id: + raise RequiredArgument( + function=cls.delete_agent_group.__name__, + argument="agent_group_id", + ) + + cmd = XmlCommand("delete_agent_group") + cmd.set_attribute("agent_group_id", str(agent_group_id)) + cmd.set_attribute("ultimate", to_bool(ultimate)) + + return cmd + + @classmethod + def get_agent_groups( + cls, + *, + filter_string: Optional[str] = None, + filter_id: Optional[EntityID] = None, + trash: Optional[bool] = None, + ) -> Request: + """Request a list of agent groups. + + Args: + filter_string: Filter expression to use. + filter_id: UUID of a predefined filter. + trash: If True, return trashed agent groups. + + Returns: + Request object to fetch agent groups. + """ + cmd = XmlCommand("get_agent_groups") + cmd.add_filter(filter_string, filter_id) + + if trash is not None: + cmd.set_attribute("trash", to_bool(trash)) + + return cmd + + @classmethod + def get_agent_group(cls, agent_group_id: EntityID) -> Request: + """Request a single agent group by ID. + + Args: + agent_group_id: UUID of the agent group. + + Raises: + RequiredArgument: If agent_group_id is not provided. + + Returns: + Request object to fetch the specific agent group. + """ + if not agent_group_id: + raise RequiredArgument( + function=cls.get_agent_group.__name__, argument="agent_group_id" + ) + + cmd = XmlCommand("get_agent_groups") + cmd.set_attribute("agent_group_id", str(agent_group_id)) + + return cmd diff --git a/gvm/protocols/gmp/requests/next/_agents.py b/gvm/protocols/gmp/requests/next/_agents.py new file mode 100644 index 00000000..47b7db96 --- /dev/null +++ b/gvm/protocols/gmp/requests/next/_agents.py @@ -0,0 +1,101 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + +from typing import Optional + +from gvm.errors import RequiredArgument +from gvm.protocols.core import Request +from gvm.protocols.gmp.requests._entity_id import EntityID +from gvm.utils import to_bool +from gvm.xml import XmlCommand + + +class Agents: + @classmethod + def get_agents( + cls, + *, + filter_string: Optional[str] = None, + filter_id: Optional[EntityID] = None, + details: Optional[bool] = None, + ) -> Request: + """Request a list of agents. + + Args: + filter_string: Filter term to use for the query. + filter_id: UUID of an existing filter to use for the query. + details: Whether to include detailed agent info. + """ + cmd = XmlCommand("get_agents") + cmd.add_filter(filter_string, filter_id) + + if details is not None: + cmd.set_attribute("details", to_bool(details)) + + return cmd + + @classmethod + def modify_agents( + cls, + agent_ids: list[EntityID], + *, + authorized: Optional[bool] = None, + min_interval: Optional[int] = None, + heartbeat_interval: Optional[int] = None, + schedule: Optional[str] = None, + comment: Optional[str] = None, + ) -> Request: + """Modify multiple agents + + Args: + agent_ids: List of agent UUIDs to modify + authorized: Whether the agent is authorized + min_interval: Minimum scan interval + heartbeat_interval: Interval for sending heartbeats + schedule: Cron-style schedule for agent + comment: Comment for the agents + """ + if not agent_ids: + raise RequiredArgument( + function=cls.modify_agents.__name__, argument="agent_ids" + ) + + cmd = XmlCommand("modify_agents") + xml_agents = cmd.add_element("agents") + + for agent_id in agent_ids: + xml_agents.add_element("agent", attrs={"id": agent_id}) + + if authorized is not None: + cmd.add_element("authorized", to_bool(authorized)) + if min_interval is not None: + cmd.add_element("min_interval", str(min_interval)) + if heartbeat_interval is not None: + cmd.add_element("heartbeat_interval", str(heartbeat_interval)) + if schedule: + cmd.add_element("schedule", schedule) + if comment: + cmd.add_element("comment", comment) + + return cmd + + @classmethod + def delete_agents(cls, agent_ids: list[EntityID]) -> Request: + """Delete multiple agents + + Args: + agent_ids: List of agent UUIDs to delete + """ + if not agent_ids: + raise RequiredArgument( + function=cls.delete_agents.__name__, argument="agent_ids" + ) + + cmd = XmlCommand("delete_agents") + xml_agents = cmd.add_element("agents") + + for agent_id in agent_ids: + xml_agents.add_element("agent", attrs={"id": agent_id}) + + return cmd diff --git a/tests/protocols/gmpnext/entities/agent_groups/__init__.py b/tests/protocols/gmpnext/entities/agent_groups/__init__.py new file mode 100644 index 00000000..7cb84d4c --- /dev/null +++ b/tests/protocols/gmpnext/entities/agent_groups/__init__.py @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later diff --git a/tests/protocols/gmpnext/entities/agent_groups/test_clone_agent_group.py b/tests/protocols/gmpnext/entities/agent_groups/test_clone_agent_group.py new file mode 100644 index 00000000..21af153f --- /dev/null +++ b/tests/protocols/gmpnext/entities/agent_groups/test_clone_agent_group.py @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + +from gvm.errors import RequiredArgument + + +class GmpCloneAgentGroupTestMixin: + def test_clone_agent_group(self): + self.gmp.clone_agent_group(agent_group_id="group-1") + + self.connection.send.has_been_called_with( + b"group-1" + ) + + def test_clone_agent_group_without_id(self): + with self.assertRaises(RequiredArgument): + self.gmp.clone_agent_group(agent_group_id=None) diff --git a/tests/protocols/gmpnext/entities/agent_groups/test_create_agent_group.py b/tests/protocols/gmpnext/entities/agent_groups/test_create_agent_group.py new file mode 100644 index 00000000..a6b9d1f5 --- /dev/null +++ b/tests/protocols/gmpnext/entities/agent_groups/test_create_agent_group.py @@ -0,0 +1,40 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + +from gvm.errors import RequiredArgument + + +class GmpCreateAgentGroupTestMixin: + def test_create_agent_group(self): + self.gmp.create_agent_group( + name="ExampleGroup", + agent_ids=["agent-1", "agent-2"], + comment="Sample comment", + ) + + self.connection.send.has_been_called_with( + b"" + b"ExampleGroup" + b"Sample comment" + b'' + b"" + ) + + def test_create_agent_group_without_name(self): + with self.assertRaises(RequiredArgument): + self.gmp.create_agent_group(name="", agent_ids=["agent-1"]) + + def test_create_agent_group_without_agents(self): + with self.assertRaises(RequiredArgument): + self.gmp.create_agent_group(name="Group", agent_ids=[]) + + def test_create_agent_group_without_comment(self): + self.gmp.create_agent_group(name="GroupX", agent_ids=["a1", "a2"]) + + self.connection.send.has_been_called_with( + b"" + b"GroupX" + b'' + b"" + ) diff --git a/tests/protocols/gmpnext/entities/agent_groups/test_delete_agent_group.py b/tests/protocols/gmpnext/entities/agent_groups/test_delete_agent_group.py new file mode 100644 index 00000000..70d9322e --- /dev/null +++ b/tests/protocols/gmpnext/entities/agent_groups/test_delete_agent_group.py @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + +from gvm.errors import RequiredArgument + + +class GmpDeleteAgentGroupTestMixin: + def test_delete_agent_group_soft(self): + self.gmp.delete_agent_group(agent_group_id="group-1", ultimate=False) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_delete_agent_group_hard(self): + self.gmp.delete_agent_group(agent_group_id="group-1", ultimate=True) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_delete_agent_group_without_id(self): + with self.assertRaises(RequiredArgument): + self.gmp.delete_agent_group(agent_group_id=None) diff --git a/tests/protocols/gmpnext/entities/agent_groups/test_get_agent_group.py b/tests/protocols/gmpnext/entities/agent_groups/test_get_agent_group.py new file mode 100644 index 00000000..a066dc1f --- /dev/null +++ b/tests/protocols/gmpnext/entities/agent_groups/test_get_agent_group.py @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + +from gvm.errors import RequiredArgument + + +class GmpGetAgentGroupTestMixin: + def test_get_agent_group(self): + self.gmp.get_agent_group(agent_group_id="group-1") + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_agent_group_without_id(self): + with self.assertRaises(RequiredArgument): + self.gmp.get_agent_group(agent_group_id=None) diff --git a/tests/protocols/gmpnext/entities/agent_groups/test_get_agent_groups.py b/tests/protocols/gmpnext/entities/agent_groups/test_get_agent_groups.py new file mode 100644 index 00000000..203a3417 --- /dev/null +++ b/tests/protocols/gmpnext/entities/agent_groups/test_get_agent_groups.py @@ -0,0 +1,43 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + + +class GmpGetAgentGroupsTestMixin: + def test_get_agent_groups(self): + self.gmp.get_agent_groups() + + self.connection.send.has_been_called_with(b"") + + def test_get_agent_groups_with_filter_string(self): + self.gmp.get_agent_groups(filter_string="name=group") + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_agent_groups_with_filter_id(self): + self.gmp.get_agent_groups(filter_id="filter-1") + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_agent_groups_with_trash(self): + self.gmp.get_agent_groups(trash=True) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_agent_groups_with_trash_false(self): + self.gmp.get_agent_groups(trash=False) + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_agent_groups_without_trash(self): + self.gmp.get_agent_groups() + + self.connection.send.has_been_called_with(b"") diff --git a/tests/protocols/gmpnext/entities/agent_groups/test_modify_agent_group.py b/tests/protocols/gmpnext/entities/agent_groups/test_modify_agent_group.py new file mode 100644 index 00000000..83aa3dbd --- /dev/null +++ b/tests/protocols/gmpnext/entities/agent_groups/test_modify_agent_group.py @@ -0,0 +1,69 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + +from gvm.errors import RequiredArgument + + +class GmpModifyAgentGroupTestMixin: + def test_modify_agent_group(self): + self.gmp.modify_agent_group( + agent_group_id="group-1", + name="NewName", + comment="Updated comment", + agent_ids=["agent-1", "agent-2"], + ) + + self.connection.send.has_been_called_with( + b'' + b"NewName" + b"Updated comment" + b'' + b"" + ) + + def test_modify_agent_group_without_id(self): + with self.assertRaises(RequiredArgument): + self.gmp.modify_agent_group(agent_group_id=None) + + def test_modify_agent_group_without_name(self): + self.gmp.modify_agent_group( + agent_group_id="group-1", + comment="Updated comment", + agent_ids=["agent-1", "agent-2"], + ) + + self.connection.send.has_been_called_with( + b'' + b"Updated comment" + b'' + b"" + ) + + def test_modify_agent_group_without_comment(self): + self.gmp.modify_agent_group( + agent_group_id="group-1", + name="NewName", + agent_ids=["agent-1", "agent-2"], + ) + + self.connection.send.has_been_called_with( + b'' + b"NewName" + b'' + b"" + ) + + def test_modify_agent_group_without_agent_ids(self): + self.gmp.modify_agent_group( + agent_group_id="group-1", + name="NewName", + comment="Updated comment", + ) + + self.connection.send.has_been_called_with( + b'' + b"NewName" + b"Updated comment" + b"" + ) diff --git a/tests/protocols/gmpnext/entities/agents/__init__.py b/tests/protocols/gmpnext/entities/agents/__init__.py new file mode 100644 index 00000000..7cb84d4c --- /dev/null +++ b/tests/protocols/gmpnext/entities/agents/__init__.py @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later diff --git a/tests/protocols/gmpnext/entities/agents/test_delete_agents.py b/tests/protocols/gmpnext/entities/agents/test_delete_agents.py new file mode 100644 index 00000000..c829de88 --- /dev/null +++ b/tests/protocols/gmpnext/entities/agents/test_delete_agents.py @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + +from gvm.errors import RequiredArgument + + +class GmpDeleteAgentsTestMixin: + def test_delete_agents(self): + self.gmp.delete_agents(agent_ids=["agent-123", "agent-456"]) + + self.connection.send.has_been_called_with( + b"" + b'' + b"" + ) + + def test_delete_agents_without_ids(self): + with self.assertRaises(RequiredArgument): + self.gmp.delete_agents(agent_ids=[]) diff --git a/tests/protocols/gmpnext/entities/agents/test_get_agents.py b/tests/protocols/gmpnext/entities/agents/test_get_agents.py new file mode 100644 index 00000000..e9a6866c --- /dev/null +++ b/tests/protocols/gmpnext/entities/agents/test_get_agents.py @@ -0,0 +1,32 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + + +class GmpGetAgentsTestMixin: + def test_get_agents(self): + self.gmp.get_agents() + + self.connection.send.has_been_called_with(b"") + + def test_get_agents_with_filter_string(self): + self.gmp.get_agents(filter_string="name=agent") + + self.connection.send.has_been_called_with( + b'' + ) + + def test_get_agents_with_filter_id(self): + self.gmp.get_agents(filter_id="f1") + + self.connection.send.has_been_called_with(b'') + + def test_get_agents_with_details_true(self): + self.gmp.get_agents(details=True) + + self.connection.send.has_been_called_with(b'') + + def test_get_agents_with_details_false(self): + self.gmp.get_agents(details=False) + + self.connection.send.has_been_called_with(b'') diff --git a/tests/protocols/gmpnext/entities/agents/test_modify_agents.py b/tests/protocols/gmpnext/entities/agents/test_modify_agents.py new file mode 100644 index 00000000..50777d93 --- /dev/null +++ b/tests/protocols/gmpnext/entities/agents/test_modify_agents.py @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: 2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later + +from gvm.errors import RequiredArgument + + +class GmpModifyAgentsTestMixin: + def test_modify_agents_basic(self): + self.gmp.modify_agents(agent_ids=["agent-123"]) + + self.connection.send.has_been_called_with( + b"" + b'' + b"" + ) + + def test_modify_agents_with_all_fields(self): + self.gmp.modify_agents( + agent_ids=["agent-123", "agent-456"], + authorized=True, + min_interval=300, + heartbeat_interval=600, + schedule="@every 6h", + comment="Updated agents", + ) + + self.connection.send.has_been_called_with( + b"" + b'' + b"1" + b"300" + b"600" + b"@every 6h" + b"Updated agents" + b"" + ) + + def test_modify_agents_without_ids(self): + with self.assertRaises(RequiredArgument): + self.gmp.modify_agents(agent_ids=[]) diff --git a/tests/protocols/gmpnext/entities/test_agent_group.py b/tests/protocols/gmpnext/entities/test_agent_group.py new file mode 100644 index 00000000..77f4b9b6 --- /dev/null +++ b/tests/protocols/gmpnext/entities/test_agent_group.py @@ -0,0 +1,48 @@ +# SPDX-FileCopyrightText: 2023-2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +from ...gmpnext import GMPTestCase +from .agent_groups.test_clone_agent_group import ( + GmpCloneAgentGroupTestMixin, +) +from .agent_groups.test_create_agent_group import ( + GmpCreateAgentGroupTestMixin, +) +from .agent_groups.test_delete_agent_group import ( + GmpDeleteAgentGroupTestMixin, +) +from .agent_groups.test_get_agent_group import ( + GmpGetAgentGroupTestMixin, +) +from .agent_groups.test_get_agent_groups import ( + GmpGetAgentGroupsTestMixin, +) +from .agent_groups.test_modify_agent_group import ( + GmpModifyAgentGroupTestMixin, +) + + +class GMPGetAgentGroupsTestCase(GmpGetAgentGroupsTestMixin, GMPTestCase): + pass + + +class GMPGetAgentGroupTestCase(GmpGetAgentGroupTestMixin, GMPTestCase): + pass + + +class GMPCreateAgentGroupTestCase(GmpCreateAgentGroupTestMixin, GMPTestCase): + pass + + +class GMPCloneAgentGroupTestCase(GmpCloneAgentGroupTestMixin, GMPTestCase): + pass + + +class GMPModifyAgentGroupTestCase(GmpModifyAgentGroupTestMixin, GMPTestCase): + pass + + +class GMPDeleteAgentGroupTestCase(GmpDeleteAgentGroupTestMixin, GMPTestCase): + pass diff --git a/tests/protocols/gmpnext/entities/test_agents.py b/tests/protocols/gmpnext/entities/test_agents.py new file mode 100644 index 00000000..accf9e5f --- /dev/null +++ b/tests/protocols/gmpnext/entities/test_agents.py @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: 2023-2025 Greenbone AG +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +from ...gmpnext import GMPTestCase +from .agents.test_delete_agents import ( + GmpDeleteAgentsTestMixin, +) +from .agents.test_get_agents import ( + GmpGetAgentsTestMixin, +) +from .agents.test_modify_agents import ( + GmpModifyAgentsTestMixin, +) + + +class GMPGetAgentsTestCase(GmpGetAgentsTestMixin, GMPTestCase): + pass + + +class GMPModifyAgentsTestCase(GmpModifyAgentsTestMixin, GMPTestCase): + pass + + +class GMPDeleteAgentsTestCase(GmpDeleteAgentsTestMixin, GMPTestCase): + pass