Skip to content

Commit 225663d

Browse files
authored
Merge pull request #1251 from arewm/ec-965
feat(ec-965): verify a set of pullspecs related to an image
2 parents 29cc1f4 + 1f2e55d commit 225663d

File tree

5 files changed

+155
-10
lines changed

5 files changed

+155
-10
lines changed

README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,11 @@ Create a `policy.yaml` file in your local `ec-cli` repo with something like:
123123
---
124124
sources:
125125
- policy:
126-
- <path-to>/ec-policies/policy/lib
127-
- <path-to>/ec-policies/policy/release
128-
data:
129-
- oci::quay.io/konflux-ci/tekton-catalog/data-acceptable-bundles:latest
130-
- github.com/release-engineering/rhtap-ec-policy//data
126+
- <path-to>/ec-policies/policy/lib
127+
- <path-to>/ec-policies/policy/release
128+
data:
129+
- oci::quay.io/konflux-ci/tekton-catalog/data-acceptable-bundles:latest
130+
- github.com/release-engineering/rhtap-ec-policy//data
131131

132132
Run the locally built `ec-cli` command
133133

antora/docs/modules/ROOT/pages/release_policy.adoc

+15-2
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ Rules included:
130130
* xref:release_policy.adoc#olm__required_olm_features_annotations_provided[OLM: Required OLM feature annotations list provided]
131131
* xref:release_policy.adoc#olm__subscriptions_annotation_format[OLM: Subscription annotation has expected value]
132132
* xref:release_policy.adoc#olm__inaccessible_snapshot_references[OLM: Unable to access images in the input snapshot]
133+
* xref:release_policy.adoc#olm__inaccessible_related_images[OLM: Unable to access related images for a component]
133134
* xref:release_policy.adoc#olm__unmapped_references[OLM: Unmapped images in OLM bundle]
134135
* xref:release_policy.adoc#olm__unpinned_references[OLM: Unpinned images in OLM bundle]
135136
* xref:release_policy.adoc#olm__unpinned_snapshot_references[OLM: Unpinned images in input snapshot]
@@ -798,7 +799,7 @@ Each image referenced by the OLM bundle should match an entry in the list of pre
798799
* FAILURE message: `The %q CSV image reference is not from an allowed registry.`
799800
* Code: `olm.allowed_registries`
800801
* Effective from: `2024-09-01T00:00:00Z`
801-
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/release/olm/olm.rego#L219[Source, window="_blank"]
802+
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/release/olm/olm.rego#L256[Source, window="_blank"]
802803

803804
[#olm__required_olm_features_annotations_provided]
804805
=== link:#olm__required_olm_features_annotations_provided[Required OLM feature annotations list provided]
@@ -836,6 +837,18 @@ Check the input snapshot and make sure all the images are accessible.
836837
* Effective from: `2024-08-15T00:00:00Z`
837838
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/release/olm/olm.rego#L156[Source, window="_blank"]
838839

840+
[#olm__inaccessible_related_images]
841+
=== link:#olm__inaccessible_related_images[Unable to access related images for a component]
842+
843+
Check the input image for the presence of related images. Ensure that all images are accessible.
844+
845+
*Solution*: Ensure all related images are available. The related images are defined by an file containing a json array attached to the validated image. The digest of the attached file is pulled from the RELATED_IMAGES_DIGEST result.
846+
847+
* Rule type: [rule-type-indicator failure]#FAILURE#
848+
* FAILURE message: `The %q related image reference is not accessible.`
849+
* Code: `olm.inaccessible_related_images`
850+
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/release/olm/olm.rego#L178[Source, window="_blank"]
851+
839852
[#olm__unmapped_references]
840853
=== link:#olm__unmapped_references[Unmapped images in OLM bundle]
841854

@@ -847,7 +860,7 @@ Check the OLM bundle image for the presence of unmapped image references. Unmapp
847860
* FAILURE message: `The %q CSV image reference is not in the snapshot or accessible.`
848861
* Code: `olm.unmapped_references`
849862
* Effective from: `2024-08-15T00:00:00Z`
850-
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/release/olm/olm.rego#L178[Source, window="_blank"]
863+
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/release/olm/olm.rego#L215[Source, window="_blank"]
851864

852865
[#olm__unpinned_references]
853866
=== link:#olm__unpinned_references[Unpinned images in OLM bundle]

antora/docs/modules/ROOT/partials/release_policy_nav.adoc

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
**** xref:release_policy.adoc#olm__required_olm_features_annotations_provided[Required OLM feature annotations list provided]
6161
**** xref:release_policy.adoc#olm__subscriptions_annotation_format[Subscription annotation has expected value]
6262
**** xref:release_policy.adoc#olm__inaccessible_snapshot_references[Unable to access images in the input snapshot]
63+
**** xref:release_policy.adoc#olm__inaccessible_related_images[Unable to access related images for a component]
6364
**** xref:release_policy.adoc#olm__unmapped_references[Unmapped images in OLM bundle]
6465
**** xref:release_policy.adoc#olm__unpinned_references[Unpinned images in OLM bundle]
6566
**** xref:release_policy.adoc#olm__unpinned_snapshot_references[Unpinned images in input snapshot]

policy/release/olm/olm.rego

+71
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,43 @@ deny contains result if {
175175
result := lib.result_helper_with_term(rego.metadata.chain(), [component.containerImage], component.containerImage)
176176
}
177177

178+
# METADATA
179+
# title: Unable to access related images for a component
180+
# description: >-
181+
# Check the input image for the presence of related images.
182+
# Ensure that all images are accessible.
183+
# custom:
184+
# short_name: inaccessible_related_images
185+
# failure_msg: The %q related image reference is not accessible.
186+
# solution: >-
187+
# Ensure all related images are available. The related images are defined by
188+
# an file containing a json array attached to the validated image. The digest
189+
# of the attached file is pulled from the RELATED_IMAGES_DIGEST result.
190+
# collections:
191+
# - redhat
192+
deny contains result if {
193+
_release_restrictions_apply
194+
195+
snapshot_components := input.snapshot.components
196+
component_images_digests := [component_image.digest |
197+
some component in snapshot_components
198+
component_image := image.parse(component.containerImage)
199+
]
200+
201+
some related_images in _related_images(input.image)
202+
203+
unmatched_image_refs := [related |
204+
some related in related_images
205+
not related.digest in component_images_digests
206+
]
207+
208+
some unmatched_image in unmatched_image_refs
209+
unmatched_ref := sprintf("%s@%s", [unmatched_image.repo, unmatched_image.digest])
210+
not ec.oci.descriptor(unmatched_ref)
211+
212+
result := lib.result_helper_with_term(rego.metadata.chain(), [unmatched_ref], unmatched_ref)
213+
}
214+
178215
# METADATA
179216
# title: Unmapped images in OLM bundle
180217
# description: >-
@@ -249,6 +286,36 @@ deny contains result if {
249286
result := lib.result_helper_with_term(rego.metadata.chain(), [img_str], img.ref.repo)
250287
}
251288

289+
# Extracts the related images attached to the image. The RELATED_IMAGES_DIGEST result
290+
# contains the digest of a referring image manifest containing the related image json
291+
# array. We need to find the blob sha in order to download the related images.
292+
_related_images(tested_image) := [e |
293+
some imgs in [[r |
294+
input_image := image.parse(tested_image.ref)
295+
296+
some related in lib.results_named(_related_images_result_name)
297+
result_digest := object.union(input_image, {"digest": sprintf("%s", [trim_space(related.value)])})
298+
related_image_ref := image.str(result_digest)
299+
related_image_manifest := ec.oci.image_manifest(related_image_ref)
300+
301+
some layer in related_image_manifest.layers
302+
layer.mediaType == _related_images_oci_mime_type
303+
related_image_blob := object.union(input_image, {"digest": layer.digest})
304+
related_image_blob_ref := image.str(related_image_blob)
305+
306+
raw_related_images := json.unmarshal(ec.oci.blob(related_image_blob_ref))
307+
308+
some related_ref in raw_related_images
309+
r := {
310+
"path": "relatedImage",
311+
"ref": image.parse(related_ref),
312+
}
313+
]]
314+
some i in imgs
315+
316+
e := {"ref": i.ref, "path": i.path}
317+
]
318+
252319
_name(o) := n if {
253320
n := o.name
254321
} else := "unnamed"
@@ -446,3 +513,7 @@ _image_registry_allowed(image_repo, allowed_prefixes) if {
446513
some allowed_prefix in allowed_prefixes
447514
startswith(image_repo, allowed_prefix)
448515
}
516+
517+
_related_images_result_name := "RELATED_IMAGES_DIGEST"
518+
519+
_related_images_oci_mime_type := "application/vnd.konflux-ci.attached-artifact.related-images+json"

policy/release/olm/olm_test.rego

+63-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package olm_test
33
import rego.v1
44

55
import data.lib
6+
import data.lib.tekton_test
7+
import data.lib_test
68
import data.olm
79

810
pinned := "registry.io/repository/image@sha256:cafe"
@@ -377,13 +379,30 @@ test_unmapped_references_in_operator if {
377379
lib.assert_equal_results(olm.deny, expected) with input.snapshot.components as [component1]
378380
with input.image.files as {"manifests/csv.yaml": manifest}
379381
with data.rule_data as {"pipeline_intention": "release", "allowed_registry_prefixes": ["registry.io"]}
380-
with ec.oci.image_manifest as mock_ec_oci_image_manifest
382+
with ec.oci.image_manifest as _mock_image_manifest
383+
with ec.oci.descriptor as mock_ec_oci_image_descriptor
381384
with input.image.config.Labels as {olm.manifestv1: "manifests/"}
382385
}
383386

384-
mock_ec_oci_image_manifest("registry.io/repository/image@sha256:cafe") := `{"config": {"digest": "sha256:cafe"}}`
387+
test_inaccessible_related_images if {
388+
expected_deny := {{
389+
"code": "olm.inaccessible_related_images",
390+
"msg": "The \"registry.io/repository/image2@sha256:tea\" related image reference is not accessible.",
391+
"term": "registry.io/repository/image2@sha256:tea",
392+
}}
393+
394+
lib.assert_equal_results(olm.deny, expected_deny) with data.rule_data.pipeline_intention as "release"
395+
with input.snapshot.components as [component1]
396+
with input.attestations as _with_related_images
397+
with input.image.ref as "registry.io/repository/image@sha256:image_digest"
398+
with ec.oci.image_manifest as _mock_image_manifest
399+
with ec.oci.blob as _mock_blob
400+
with ec.oci.descriptor as mock_ec_oci_image_descriptor
401+
}
402+
403+
mock_ec_oci_image_descriptor("registry.io/repository/image3@sha256:coffee") := `{"config": {"digest": "sha256:coffee"}}`
385404

386-
mock_ec_oci_image_manifest("registry.io/repository/image2@sha256:tea") := false
405+
mock_ec_oci_image_descriptor("registry.io/repository/image2@sha256:tea") := false
387406

388407
test_olm_ci_pipeline if {
389408
# Make sure no violations are thrown if it isn't a release pipeline
@@ -427,3 +446,44 @@ test_unallowed_registries if {
427446
with input.image.config.Labels as {olm.manifestv1: "manifests/"}
428447
with input.image.files as {"manifests/csv.yaml": manifest}
429448
}
449+
450+
_related_images := [pinned, pinned2, "registry.io/repository/image3@sha256:coffee"]
451+
452+
_manifests := {
453+
"registry.io/repository/image@sha256:related_digest": {"layers": [{
454+
"mediaType": olm._related_images_oci_mime_type,
455+
"digest": "sha256:related_blob_digest",
456+
}]},
457+
"registry.io/repository/image@sha256:cafe": {"config": {"digest": "sha256:cafe"}},
458+
}
459+
460+
_blobs := {"registry.io/repository/image@sha256:related_blob_digest": json.marshal(_related_images)}
461+
462+
_mock_image_manifest(ref) := _manifests[ref]
463+
464+
_mock_blob(ref) := _blobs[ref]
465+
466+
_bundle := "registry.img/spam@sha256:4e388ab32b10dc8dbc7e28144f552830adc74787c1e2c0824032078a79f227fb"
467+
468+
_with_related_images := _attestations_with_attachment("sha256:related_digest")
469+
470+
_attestations_with_attachment(attachment) := attestations if {
471+
slsav1_task_with_result := tekton_test.slsav1_task_result_ref(
472+
"validate-fbc",
473+
[{
474+
"name": olm._related_images_result_name,
475+
"type": "string",
476+
"value": attachment,
477+
}],
478+
)
479+
480+
attestations := [
481+
lib_test.att_mock_helper_ref(
482+
olm._related_images_result_name,
483+
attachment,
484+
"validate-fbc",
485+
_bundle,
486+
),
487+
lib_test.mock_slsav1_attestation_with_tasks([tekton_test.slsav1_task_bundle(slsav1_task_with_result, _bundle)]),
488+
]
489+
}

0 commit comments

Comments
 (0)