Skip to content

Commit d3ecda7

Browse files
authored
Merge pull request #626 from open-component-model/zkdev-mv-func
Mv function from cc-utils
2 parents 044496b + 7b927bc commit d3ecda7

File tree

2 files changed

+70
-3
lines changed

2 files changed

+70
-3
lines changed

cli/_bdba.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import tabulate
88

99
import cnudie.access
10-
import oci
1110
import ocm
1211
import ocm.iter
1312
import tarutil
@@ -155,7 +154,7 @@ def iter_resource_scans() -> collections.abc.Generator[odg.model.ArtefactMetadat
155154
access = resource_node.resource.access
156155

157156
if access.type is ocm.AccessType.OCI_REGISTRY:
158-
content_iterator = oci.image_layers_as_tarfile_generator(
157+
content_iterator = ocm_util.image_layers_as_tarfile_generator(
159158
image_reference=access.imageReference,
160159
oci_client=oci_client,
161160
include_config_blob=False,

ocm_util.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import collections.abc
22
import logging
3+
import tarfile
34

45
import cnudie.access
56
import cnudie.retrieve_async
@@ -183,7 +184,7 @@ def iter_content_for_resource_node(
183184
access = resource_node.resource.access
184185

185186
if access.type is ocm.AccessType.OCI_REGISTRY:
186-
return oci.image_layers_as_tarfile_generator(
187+
return image_layers_as_tarfile_generator(
187188
image_reference=access.imageReference,
188189
oci_client=oci_client,
189190
include_config_blob=False,
@@ -225,3 +226,70 @@ def iter_content_for_resource_node(
225226

226227
else:
227228
raise RuntimeError(f'Unsupported access type: {access.type}')
229+
230+
231+
def image_layers_as_tarfile_generator(
232+
image_reference: str,
233+
oci_client: oci.client.Client,
234+
chunk_size=tarfile.RECORDSIZE,
235+
include_config_blob=True,
236+
fallback_to_first_subimage_if_index=False,
237+
) -> collections.abc.Generator[bytes, None, None]:
238+
'''
239+
returns a generator yielding a tar-archive with the passed oci-image's layer-blobs as
240+
members. This is somewhat similar to the result of a `docker save` with the notable difference
241+
that the cfg-blob is discarded.
242+
This function is useful to e.g. upload file system contents of an oci-container-image to some
243+
scanning-tool (provided it supports the extraction of tar-archives)
244+
If include_config_blob is set to False the config blob will be ignored.
245+
246+
If fallback_to_first_subimage_if_index is set to True, in case of oci-image-manifest-list the
247+
first sub-manifest is taken.
248+
'''
249+
manifest = oci_client.manifest(
250+
image_reference=image_reference,
251+
accept=oci.model.MimeTypes.prefer_multiarch,
252+
)
253+
254+
image_reference = oci.model.OciImageReference.to_image_ref(image_reference)
255+
256+
if fallback_to_first_subimage_if_index and isinstance(manifest, oci.model.OciImageManifestList):
257+
logger.warn(
258+
f'image-index handling not fully implemented - will only scan first image, '
259+
f'{image_reference=}, {manifest.mediaType=}'
260+
)
261+
manifest_ref = manifest.manifests[0]
262+
manifest = oci_client.manifest(
263+
image_reference=f'{image_reference.ref_without_tag}@{manifest_ref.digest}',
264+
)
265+
266+
blob_refs = manifest.blobs() if include_config_blob else manifest.layers
267+
268+
if not include_config_blob:
269+
logger.debug('skipping config blob')
270+
271+
def resolve_blob(
272+
blob_ref: oci.model.OciBlobRef,
273+
image_reference: str,
274+
) -> ioutil.BlobDescriptor:
275+
content = oci_client.blob(
276+
image_reference=image_reference,
277+
digest=blob_ref.digest,
278+
stream=True,
279+
).iter_content(chunk_size=chunk_size)
280+
281+
return ioutil.BlobDescriptor(
282+
content=content,
283+
size=blob_ref.size,
284+
name=f'{blob_ref.digest}.tar',
285+
)
286+
287+
return tarutil.concat_blobs_as_tarstream(
288+
blobs=(
289+
resolve_blob(
290+
blob_ref=blob_ref,
291+
image_reference=image_reference,
292+
)
293+
for blob_ref in blob_refs
294+
),
295+
)

0 commit comments

Comments
 (0)