Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 119 additions & 1 deletion gvm/protocols/gmp/_gmpnext.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from .._protocol import T
from ._gmp227 import GMPv227
from .requests.next import AgentGroups, AgentInstallers, Agents
from .requests.next import AgentGroups, AgentInstallers, Agents, OCIImageTargets


class GMPNext(GMPv227[T]):
Expand Down Expand Up @@ -274,3 +274,121 @@ def clone_agent_group(
return self._send_request_and_transform_response(
AgentGroups.clone_agent_group(agent_group_id)
)

def create_oci_image_target(
self,
name: str,
image_references: list[str],
*,
comment: Optional[str] = None,
credential_id: Optional[EntityID] = None,
) -> T:
"""Create a new OCI image target

Args:
name: Name of the OCI image target
image_references: List of OCI image URLs to scan
comment: Comment for the target
credential_id: UUID of a credential to use on target
"""
return self._send_request_and_transform_response(
OCIImageTargets.create_oci_image_target(
name=name,
image_references=image_references,
comment=comment,
credential_id=credential_id,
)
)

def modify_oci_image_target(
self,
oci_image_target_id: EntityID,
*,
name: Optional[str] = None,
comment: Optional[str] = None,
image_references: Optional[list[str]] = None,
credential_id: Optional[EntityID] = None,
) -> T:
"""Modify an existing OCI image target.

Args:
oci_image_target_id: UUID of target to modify.
comment: Comment on target.
name: Name of target.
image_references: List of OCI image URLs to scan.
credential_id: UUID of credential to use on target.
"""
return self._send_request_and_transform_response(
OCIImageTargets.modify_oci_image_target(
oci_image_target_id,
name=name,
comment=comment,
image_references=image_references,
credential_id=credential_id,
)
)

def clone_oci_image_target(self, oci_image_target_id: EntityID) -> T:
"""Clone an existing OCI image target.

Args:
oci_image_target_id: UUID of an existing OCI image target to clone.
"""
return self._send_request_and_transform_response(
OCIImageTargets.clone_oci_image_target(oci_image_target_id)
)

def delete_oci_image_target(
self, oci_image_target_id: EntityID, *, ultimate: Optional[bool] = False
) -> T:
"""Delete an existing OCI image target.

Args:
oci_image_target_id: UUID of an existing OCI image target to delete.
ultimate: Whether to remove entirely or to the trashcan.
"""
return self._send_request_and_transform_response(
OCIImageTargets.delete_oci_image_target(
oci_image_target_id, ultimate=ultimate
)
)

def get_oci_image_target(
self, oci_image_target_id: EntityID, *, tasks: Optional[bool] = None
) -> T:
"""Request a single OCI image target.

Args:
oci_image_target_id: UUID of the OCI image target to request.
tasks: Whether to include list of tasks that use the target
"""
return self._send_request_and_transform_response(
OCIImageTargets.get_oci_image_target(
oci_image_target_id, tasks=tasks
)
)

def get_oci_image_targets(
self,
*,
filter_string: Optional[str] = None,
filter_id: Optional[EntityID] = None,
trash: Optional[bool] = None,
tasks: Optional[bool] = None,
) -> T:
"""Request a list of OCI image targets.

Args:
filter_string: Filter term to use for the query.
filter_id: UUID of an existing filter to use for the query.
trash: Whether to include targets in the trashcan.
tasks: Whether to include list of tasks that use the target.
"""
return self._send_request_and_transform_response(
OCIImageTargets.get_oci_image_targets(
filter_string=filter_string,
filter_id=filter_id,
trash=trash,
tasks=tasks,
)
)
2 changes: 2 additions & 0 deletions gvm/protocols/gmp/requests/next/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
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 gvm.protocols.gmp.requests.next._oci_image_targets import OCIImageTargets

from .._entity_id import EntityID
from .._version import Version
Expand Down Expand Up @@ -113,6 +114,7 @@
"InfoType",
"Notes",
"Nvts",
"OCIImageTargets",
"OperatingSystems",
"Overrides",
"Permissions",
Expand Down
186 changes: 186 additions & 0 deletions gvm/protocols/gmp/requests/next/_oci_image_targets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# 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, to_comma_list
from gvm.xml import XmlCommand


class OCIImageTargets:
@classmethod
def create_oci_image_target(
cls,
name: str,
image_references: list[str],
*,
comment: Optional[str] = None,
credential_id: Optional[EntityID] = None,
) -> Request:
"""Create a new OCI image target

Args:
name: Name of the target
image_references: List of OCI image URLs to scan
comment: Comment for the target
credential_id: UUID of a credential to use on target
"""
if not name:
raise RequiredArgument(
function=cls.create_oci_image_target.__name__, argument="name"
)

if not image_references:
raise RequiredArgument(
function=cls.create_oci_image_target.__name__,
argument="image_references",
)

cmd = XmlCommand("create_oci_image_target")
cmd.add_element("name", name)
cmd.add_element("image_references", to_comma_list(image_references))

if comment:
cmd.add_element("comment", comment)

if credential_id:
cmd.add_element("credential", attrs={"id": str(credential_id)})

return cmd

@classmethod
def modify_oci_image_target(
cls,
oci_image_target_id: EntityID,
*,
name: Optional[str] = None,
comment: Optional[str] = None,
image_references: Optional[list[str]] = None,
credential_id: Optional[EntityID] = None,
) -> Request:
"""Modify an existing target.

Args:
oci_image_target_id: UUID of target to modify.
comment: Comment on target.
name: Name of target.
image_references: List of OCI image URLs.
credential_id: UUID of credential to use on target.
"""
if not oci_image_target_id:
raise RequiredArgument(
function=cls.modify_oci_image_target.__name__,
argument="oci_image_target_id",
)

cmd = XmlCommand("modify_oci_image_target")
cmd.set_attribute("oci_image_target_id", str(oci_image_target_id))

if comment:
cmd.add_element("comment", comment)

if name:
cmd.add_element("name", name)

if image_references:
cmd.add_element("image_references", to_comma_list(image_references))

if credential_id:
cmd.add_element("credential", attrs={"id": str(credential_id)})

return cmd

@classmethod
def clone_oci_image_target(cls, oci_image_target_id: EntityID) -> Request:
"""Clone an existing OCI image target.

Args:
oci_image_target_id: UUID of an existing target to clone.
"""
if not oci_image_target_id:
raise RequiredArgument(
function=cls.clone_oci_image_target.__name__,
argument="oci_image_target_id",
)

cmd = XmlCommand("create_oci_image_target")
cmd.add_element("copy", str(oci_image_target_id))
return cmd

@classmethod
def delete_oci_image_target(
cls, oci_image_target_id: EntityID, *, ultimate: Optional[bool] = False
) -> Request:
"""Delete an existing OCI image target.

Args:
oci_image_target_id: UUID of an existing target to delete.
ultimate: Whether to remove entirely or to the trashcan.
"""
if not oci_image_target_id:
raise RequiredArgument(
function=cls.delete_oci_image_target.__name__,
argument="oci_image_target_id",
)

cmd = XmlCommand("delete_oci_image_target")
cmd.set_attribute("oci_image_target_id", str(oci_image_target_id))
cmd.set_attribute("ultimate", to_bool(ultimate))
return cmd

@classmethod
def get_oci_image_target(
cls, oci_image_target_id: EntityID, *, tasks: Optional[bool] = None
) -> Request:
"""Request a single OCI Image target.

Args:
oci_image_target_id: UUID of the target to request.
tasks: Whether to include list of tasks that use the target
"""
if not oci_image_target_id:
raise RequiredArgument(
function=cls.get_oci_image_target.__name__,
argument="oci_image_target_id",
)

cmd = XmlCommand("get_oci_image_targets")
cmd.set_attribute("oci_image_target_id", str(oci_image_target_id))

if tasks is not None:
cmd.set_attribute("tasks", to_bool(tasks))

return cmd

@classmethod
def get_oci_image_targets(
cls,
*,
filter_string: Optional[str] = None,
filter_id: Optional[EntityID] = None,
trash: Optional[bool] = None,
tasks: Optional[bool] = None,
) -> Request:
"""Request a list of OCI image targets.

Args:
filter_string: Filter term to use for the query.
filter_id: UUID of an existing filter to use for the query.
trash: Whether to include targets in the trashcan.
tasks: Whether to include list of tasks that use the target.
"""
cmd = XmlCommand("get_oci_image_targets")
cmd.add_filter(filter_string, filter_id)

if trash is not None:
cmd.set_attribute("trash", to_bool(trash))

if tasks is not None:
cmd.set_attribute("tasks", to_bool(tasks))

return cmd
20 changes: 20 additions & 0 deletions tests/protocols/gmpnext/entities/oci_image_targets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2025 Greenbone AG
#
# SPDX-License-Identifier: GPL-3.0-or-later
#

from .test_clone_oci_image_target import GmpCloneOCIImageTargetTestMixin
from .test_create_oci_image_target import GmpCreateOCIImageTargetTestMixin
from .test_delete_oci_image_target import GmpDeleteOCIImageTargetTestMixin
from .test_get_oci_image_target import GmpGetOCIImageTargetTestMixin
from .test_get_oci_image_targets import GmpGetOCIImageTargetsTestMixin
from .test_modify_oci_image_target import GmpModifyOCIImageTargetTestMixin

__all__ = (
"GmpCloneOCIImageTargetTestMixin",
"GmpCreateOCIImageTargetTestMixin",
"GmpDeleteOCIImageTargetTestMixin",
"GmpGetOCIImageTargetTestMixin",
"GmpGetOCIImageTargetsTestMixin",
"GmpModifyOCIImageTargetTestMixin",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SPDX-FileCopyrightText: 2025 Greenbone AG
#
# SPDX-License-Identifier: GPL-3.0-or-later
#

from gvm.errors import RequiredArgument


class GmpCloneOCIImageTargetTestMixin:
TARGET_ID = "00000000-0000-0000-0000-000000000000"

def test_clone(self):
self.gmp.clone_oci_image_target(self.TARGET_ID)

self.connection.send.has_been_called_with(
"<create_oci_image_target>"
f"<copy>{self.TARGET_ID}</copy>"
"</create_oci_image_target>".encode("utf-8")
)

def test_missing_id(self):
with self.assertRaises(RequiredArgument):
self.gmp.clone_oci_image_target("")

with self.assertRaises(RequiredArgument):
self.gmp.clone_oci_image_target(None)
Loading