Skip to content

Commit 5ea55f6

Browse files
Add: Added GMP commands for OCI image targets
1 parent 590f0fa commit 5ea55f6

File tree

11 files changed

+649
-1
lines changed

11 files changed

+649
-1
lines changed

gvm/protocols/gmp/_gmpnext.py

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from .._protocol import T
1010
from ._gmp227 import GMPv227
11-
from .requests.next import AgentInstallers
11+
from .requests.next import AgentInstallers, OCIImageTargets
1212

1313

1414
class GMPNext(GMPv227[T]):
@@ -78,3 +78,121 @@ def get_agent_installer_file(self, agent_installer_id: EntityID) -> T:
7878
return self._send_request_and_transform_response(
7979
AgentInstallers.get_agent_installer_file(agent_installer_id)
8080
)
81+
82+
def create_oci_image_target(
83+
self,
84+
name: str,
85+
*,
86+
image_references: list[str],
87+
comment: Optional[str] = None,
88+
credential_id: Optional[EntityID] = None,
89+
) -> T:
90+
"""Create a new OCI image target
91+
92+
Args:
93+
name: Name of the OCI image target
94+
image_references: List of OCI image URLs to scan
95+
comment: Comment for the target
96+
credential_id: UUID of a credential to use on target
97+
"""
98+
return self._send_request_and_transform_response(
99+
OCIImageTargets.create_oci_image_target(
100+
name=name,
101+
image_references=image_references,
102+
comment=comment,
103+
credential_id=credential_id,
104+
)
105+
)
106+
107+
def modify_oci_image_target(
108+
self,
109+
oci_image_target_id: EntityID,
110+
*,
111+
name: Optional[str] = None,
112+
comment: Optional[str] = None,
113+
image_references: Optional[list[str]] = None,
114+
credential_id: Optional[EntityID] = None,
115+
) -> T:
116+
"""Modify an existing OCI image target.
117+
118+
Args:
119+
oci_image_target_id: UUID of target to modify.
120+
comment: Comment on target.
121+
name: Name of target.
122+
image_references: List of OCI image URLs to scan.
123+
credential_id: UUID of credential to use on target.
124+
"""
125+
return self._send_request_and_transform_response(
126+
OCIImageTargets.modify_oci_image_target(
127+
oci_image_target_id,
128+
name=name,
129+
comment=comment,
130+
image_references=image_references,
131+
credential_id=credential_id,
132+
)
133+
)
134+
135+
def clone_oci_image_target(self, oci_image_target_id: EntityID) -> T:
136+
"""Clone an existing OCI image target.
137+
138+
Args:
139+
oci_image_target_id: UUID of an existing OCI image target to clone.
140+
"""
141+
return self._send_request_and_transform_response(
142+
OCIImageTargets.clone_oci_image_target(oci_image_target_id)
143+
)
144+
145+
def delete_oci_image_target(
146+
self, oci_image_target_id: EntityID, *, ultimate: Optional[bool] = False
147+
) -> T:
148+
"""Delete an existing OCI image target.
149+
150+
Args:
151+
oci_image_target_id: UUID of an existing OCI image target to delete.
152+
ultimate: Whether to remove entirely or to the trashcan.
153+
"""
154+
return self._send_request_and_transform_response(
155+
OCIImageTargets.delete_oci_image_target(
156+
oci_image_target_id, ultimate=ultimate
157+
)
158+
)
159+
160+
def get_oci_image_target(
161+
self, oci_image_target_id: EntityID, *, tasks: Optional[bool] = None
162+
) -> T:
163+
"""Request a single OCI image target.
164+
165+
Args:
166+
oci_image_target_id: UUID of the OCI image target to request.
167+
tasks: Whether to include list of tasks that use the target
168+
"""
169+
return self._send_request_and_transform_response(
170+
OCIImageTargets.get_oci_image_target(
171+
oci_image_target_id, tasks=tasks
172+
)
173+
)
174+
175+
def get_oci_image_targets(
176+
self,
177+
*,
178+
filter_string: Optional[str] = None,
179+
filter_id: Optional[EntityID] = None,
180+
trash: Optional[bool] = None,
181+
tasks: Optional[bool] = None,
182+
) -> T:
183+
"""Request a list of OCI image targets.
184+
185+
Args:
186+
filter_string: Filter term to use for the query.
187+
filter_id: UUID of an existing filter to use for the query.
188+
trash: Whether to include targets in the trashcan.
189+
tasks: Whether to include list of tasks that use the target.
190+
"""
191+
return self._send_request_and_transform_response(
192+
OCIImageTargets.get_oci_image_targets(
193+
filter_string=filter_string,
194+
filter_id=filter_id,
195+
trash=trash,
196+
tasks=tasks,
197+
)
198+
)

gvm/protocols/gmp/requests/next/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# SPDX-License-Identifier: GPL-3.0-or-later
44

55
from gvm.protocols.gmp.requests.next._agent_installers import AgentInstallers
6+
from gvm.protocols.gmp.requests.next._oci_image_targets import OCIImageTargets
67

78
from .._entity_id import EntityID
89
from .._version import Version
@@ -109,6 +110,7 @@
109110
"InfoType",
110111
"Notes",
111112
"Nvts",
113+
"OCIImageTargets",
112114
"OperatingSystems",
113115
"Overrides",
114116
"Permissions",
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# SPDX-FileCopyrightText: 2025 Greenbone AG
2+
#
3+
# SPDX-License-Identifier: GPL-3.0-or-later
4+
#
5+
6+
from typing import Optional
7+
8+
from gvm.errors import RequiredArgument
9+
from gvm.protocols.core import Request
10+
from gvm.protocols.gmp.requests._entity_id import EntityID
11+
from gvm.utils import to_bool, to_comma_list
12+
from gvm.xml import XmlCommand
13+
14+
15+
class OCIImageTargets:
16+
@classmethod
17+
def create_oci_image_target(
18+
cls,
19+
name: str,
20+
*,
21+
image_references: list[str],
22+
comment: Optional[str] = None,
23+
credential_id: Optional[EntityID] = None,
24+
) -> Request:
25+
"""Create a new OCI image target
26+
27+
Args:
28+
name: Name of the target
29+
image_references: List of OCI image URLs to scan
30+
comment: Comment for the target
31+
credential_id: UUID of a credential to use on target
32+
"""
33+
if not name:
34+
raise RequiredArgument(
35+
function=cls.create_oci_image_target.__name__, argument="name"
36+
)
37+
38+
if not image_references:
39+
raise RequiredArgument(
40+
function=cls.create_oci_image_target.__name__,
41+
argument="image_references",
42+
)
43+
44+
cmd = XmlCommand("create_oci_image_target")
45+
cmd.add_element("name", name)
46+
cmd.add_element("image_references", to_comma_list(image_references))
47+
48+
if comment:
49+
cmd.add_element("comment", comment)
50+
51+
if credential_id:
52+
cmd.add_element("credential", attrs={"id": str(credential_id)})
53+
54+
return cmd
55+
56+
@classmethod
57+
def modify_oci_image_target(
58+
cls,
59+
oci_image_target_id: EntityID,
60+
*,
61+
name: Optional[str] = None,
62+
comment: Optional[str] = None,
63+
image_references: Optional[list[str]] = None,
64+
credential_id: Optional[EntityID] = None,
65+
) -> Request:
66+
"""Modify an existing target.
67+
68+
Args:
69+
oci_image_target_id: UUID of target to modify.
70+
comment: Comment on target.
71+
name: Name of target.
72+
image_references: List of OCI image URLs.
73+
credential_id: UUID of credential to use on target.
74+
"""
75+
if not oci_image_target_id:
76+
raise RequiredArgument(
77+
function=cls.modify_oci_image_target.__name__,
78+
argument="oci_image_target_id",
79+
)
80+
81+
cmd = XmlCommand("modify_oci_image_target")
82+
cmd.set_attribute("oci_image_target_id", str(oci_image_target_id))
83+
84+
if comment:
85+
cmd.add_element("comment", comment)
86+
87+
if name:
88+
cmd.add_element("name", name)
89+
90+
if image_references:
91+
cmd.add_element("image_references", to_comma_list(image_references))
92+
93+
if credential_id:
94+
cmd.add_element("credential", attrs={"id": str(credential_id)})
95+
96+
return cmd
97+
98+
@classmethod
99+
def clone_oci_image_target(cls, oci_image_target_id: EntityID) -> Request:
100+
"""Clone an existing OCI image target.
101+
102+
Args:
103+
oci_image_target_id: UUID of an existing target to clone.
104+
"""
105+
if not oci_image_target_id:
106+
raise RequiredArgument(
107+
function=cls.clone_oci_image_target.__name__,
108+
argument="oci_image_target_id",
109+
)
110+
111+
cmd = XmlCommand("create_oci_image_target")
112+
cmd.add_element("copy", str(oci_image_target_id))
113+
return cmd
114+
115+
@classmethod
116+
def delete_oci_image_target(
117+
cls, oci_image_target_id: EntityID, *, ultimate: Optional[bool] = False
118+
) -> Request:
119+
"""Delete an existing OCI image target.
120+
121+
Args:
122+
oci_image_target_id: UUID of an existing target to delete.
123+
ultimate: Whether to remove entirely or to the trashcan.
124+
"""
125+
if not oci_image_target_id:
126+
raise RequiredArgument(
127+
function=cls.delete_oci_image_target.__name__,
128+
argument="oci_image_target_id",
129+
)
130+
131+
cmd = XmlCommand("delete_oci_image_target")
132+
cmd.set_attribute("oci_image_target_id", str(oci_image_target_id))
133+
cmd.set_attribute("ultimate", to_bool(ultimate))
134+
return cmd
135+
136+
@classmethod
137+
def get_oci_image_target(
138+
cls, oci_image_target_id: EntityID, *, tasks: Optional[bool] = None
139+
) -> Request:
140+
"""Request a single OCI Image target.
141+
142+
Args:
143+
oci_image_target_id: UUID of the target to request.
144+
tasks: Whether to include list of tasks that use the target
145+
"""
146+
if not oci_image_target_id:
147+
raise RequiredArgument(
148+
function=cls.get_oci_image_target.__name__,
149+
argument="oci_image_target_id",
150+
)
151+
152+
cmd = XmlCommand("get_oci_image_targets")
153+
cmd.set_attribute("oci_image_target_id", str(oci_image_target_id))
154+
155+
if tasks is not None:
156+
cmd.set_attribute("tasks", to_bool(tasks))
157+
158+
return cmd
159+
160+
@classmethod
161+
def get_oci_image_targets(
162+
cls,
163+
*,
164+
filter_string: Optional[str] = None,
165+
filter_id: Optional[EntityID] = None,
166+
trash: Optional[bool] = None,
167+
tasks: Optional[bool] = None,
168+
) -> Request:
169+
"""Request a list of OCI image targets.
170+
171+
Args:
172+
filter_string: Filter term to use for the query.
173+
filter_id: UUID of an existing filter to use for the query.
174+
trash: Whether to include targets in the trashcan.
175+
tasks: Whether to include list of tasks that use the target.
176+
"""
177+
cmd = XmlCommand("get_oci_image_targets")
178+
cmd.add_filter(filter_string, filter_id)
179+
180+
if trash is not None:
181+
cmd.set_attribute("trash", to_bool(trash))
182+
183+
if tasks is not None:
184+
cmd.set_attribute("tasks", to_bool(tasks))
185+
186+
return cmd
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# SPDX-FileCopyrightText: 2025 Greenbone AG
2+
#
3+
# SPDX-License-Identifier: GPL-3.0-or-later
4+
#
5+
6+
from .test_clone_oci_image_target import GmpCloneOCIImageTargetTestMixin
7+
from .test_create_oci_image_target import GmpCreateOCIImageTargetTestMixin
8+
from .test_delete_oci_image_target import GmpDeleteOCIImageTargetTestMixin
9+
from .test_get_oci_image_target import GmpGetOCIImageTargetTestMixin
10+
from .test_get_oci_image_targets import GmpGetOCIImageTargetsTestMixin
11+
from .test_modify_oci_image_target import GmpModifyOCIImageTargetTestMixin
12+
13+
__all__ = (
14+
"GmpCloneOCIImageTargetTestMixin",
15+
"GmpCreateOCIImageTargetTestMixin",
16+
"GmpDeleteOCIImageTargetTestMixin",
17+
"GmpGetOCIImageTargetTestMixin",
18+
"GmpGetOCIImageTargetsTestMixin",
19+
"GmpModifyOCIImageTargetTestMixin",
20+
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# SPDX-FileCopyrightText: 2025 Greenbone AG
2+
#
3+
# SPDX-License-Identifier: GPL-3.0-or-later
4+
#
5+
6+
from gvm.errors import RequiredArgument
7+
8+
9+
class GmpCloneOCIImageTargetTestMixin:
10+
TARGET_ID = "00000000-0000-0000-0000-000000000000"
11+
12+
def test_clone(self):
13+
self.gmp.clone_oci_image_target(self.TARGET_ID)
14+
15+
self.connection.send.has_been_called_with(
16+
"<create_oci_image_target>"
17+
f"<copy>{self.TARGET_ID}</copy>"
18+
"</create_oci_image_target>".encode("utf-8")
19+
)
20+
21+
def test_missing_id(self):
22+
with self.assertRaises(RequiredArgument):
23+
self.gmp.clone_oci_image_target("")
24+
25+
with self.assertRaises(RequiredArgument):
26+
self.gmp.clone_oci_image_target(None)

0 commit comments

Comments
 (0)