Skip to content

Commit edf7fdf

Browse files
committed
Handle matrix tasks result digest lists correctly
There's a check that requires that all test tasks verify that they did test the image being validated. To do this the tasks produce a task result that must contain the digest of the image. Some tests tasks are now moving to run as a Tekton matrix task, so they split up and run as separate tasks for each arch being tested. This means we end up with more than one task visible in the attestation, and hence one particular task result might not include the digest of specific image being tested, because it was actually tested in one of the other similar matrix tasks. Work around the problem by doing some massaging of the task result list to combine the digest lists in the task results from similar matrix tasks into one combined digest list, and then referencing that in the policy check instead of the raw list. Claude created the test coverage. Ref: https://issues.redhat.com/browse/KONFLUX-9576 Co-authored-by: Claude 4 Sonnet
1 parent b4a65f3 commit edf7fdf

File tree

3 files changed

+53
-7
lines changed

3 files changed

+53
-7
lines changed

policy/release/lib/attestations.rego

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ taskrun_att_build_types := {
3535
# with test_ is treated as though it was a test.)
3636
task_test_result_name := "TEST_OUTPUT"
3737

38-
task_test_image_result_name := "IMAGES_PROCESSED"
39-
4038
slsa_provenance_attestations := [att |
4139
some att in input.attestations
4240
att.statement.predicateType in {slsa_provenance_predicate_type_v1, slsa_provenance_predicate_type_v02}
@@ -122,8 +120,6 @@ unmarshal(raw) := value if {
122120
# First find results using the new task result name
123121
results_from_tests := results_named(task_test_result_name)
124122

125-
images_processed_results_from_tests := results_named(task_test_image_result_name)
126-
127123
# Check for a task by name. Return the task if found
128124
task_in_pipelinerun(name) := task if {
129125
some task in tasks_from_pipelinerun

policy/release/test/test.rego

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@ deny contains result if {
257257
img := image.parse(input.image.ref)
258258
img_digest := img.digest
259259

260-
some task in lib.images_processed_results_from_tests
260+
some task in _grouped_processed_results_from_tests
261+
261262
not img_digest in object.get(task.value, ["image", "digests"], [])
262263
result := lib.result_helper_with_term(
263264
rego.metadata.chain(),
@@ -266,6 +267,36 @@ deny contains result if {
266267
)
267268
}
268269

270+
# For a multi-arch matrix task we get records of multiple tasks with
271+
# the same name and bundle. Combine digest lists from each them into
272+
# one single list otherwise we get violations for matrix test tasks.
273+
#
274+
# We're making the assumption that there's no reason, other than matrix
275+
# tasks, we would see the same task with the same name more than once
276+
# in the pipelinerun.
277+
#
278+
_grouped_processed_results_from_tests contains result if {
279+
images_processed_results := lib.results_named(_task_test_image_result_name)
280+
281+
some r1 in images_processed_results
282+
283+
combined_digest_list := [digest |
284+
some r2 in images_processed_results
285+
r2.name == r1.name
286+
r2.bundle == r2.bundle
287+
some digest in r2.value.image.digests
288+
]
289+
290+
# There is also a "pullspec" attribute alongside the "digests"
291+
# attribute in the original task result. I think it's identical
292+
# for each of the matrix tasks, so we could put it back in, but
293+
# we don't need it for the policy check so let's leave it out.
294+
295+
result := object.union(r1, {"value": {"image": {"digests": combined_digest_list}}})
296+
}
297+
298+
_task_test_image_result_name := "IMAGES_PROCESSED"
299+
269300
_did_result(test, results, _) if {
270301
test.result in results
271302
}

policy/release/test/test_test.rego

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ test_wrong_attestation_type if {
448448
test_all_image_processed if {
449449
# regal ignore:line-length
450450
digests_processed := {"image": {"digests": ["sha256:4e388ab32b10dc8dbc7e28144f552830adc74787c1e2c0824032078a79f227fb"]}}
451-
pipeline_run := lib_test.att_mock_helper_ref(lib.task_test_image_result_name, digests_processed, "success_23", _bundle)
451+
pipeline_run := lib_test.att_mock_helper_ref("IMAGES_PROCESSED", digests_processed, "success_23", _bundle)
452452
attestations := [
453453
pipeline_run,
454454
lib_test.att_mock_helper_ref(lib.task_test_result_name, {"result": "SUCCESS"}, "errored_1", _bundle),
@@ -460,7 +460,7 @@ test_all_image_processed if {
460460

461461
test_all_images_not_processed if {
462462
digests_processed := {"image": {"digests": ["sha256:wrongDigest"]}}
463-
pipeline_run := lib_test.att_mock_helper_ref(lib.task_test_image_result_name, digests_processed, "success_23", _bundle)
463+
pipeline_run := lib_test.att_mock_helper_ref("IMAGES_PROCESSED", digests_processed, "success_23", _bundle)
464464

465465
attestations := [
466466
pipeline_run,
@@ -476,6 +476,25 @@ test_all_images_not_processed if {
476476
with input.image.ref as _bundle
477477
}
478478

479+
test_all_images_matrix_tasks if {
480+
# Matrix task scenario: same task name and bundle but different digests processed by each instance
481+
digests_task1 := {"image": {"digests": ["sha256:4e388ab32b10dc8dbc7e28144f552830adc74787c1e2c0824032078a79f227fb"]}}
482+
digests_task2 := {"image": {"digests": ["sha256:otherDigest"]}}
483+
484+
matrix_task1 := lib_test.att_mock_helper_ref("IMAGES_PROCESSED", digests_task1, "matrix-test", _bundle)
485+
matrix_task2 := lib_test.att_mock_helper_ref("IMAGES_PROCESSED", digests_task2, "matrix-test", _bundle)
486+
487+
attestations := [
488+
matrix_task1,
489+
matrix_task2,
490+
lib_test.att_mock_helper_ref(lib.task_test_result_name, {"result": "SUCCESS"}, "matrix-test", _bundle),
491+
]
492+
493+
# Should pass because the grouped results combine digests from both matrix task instances
494+
lib.assert_empty(test.deny) with input.attestations as attestations
495+
with input.image.ref as _bundle
496+
}
497+
479498
test_rule_data_provided if {
480499
d := {
481500
"supported_tests_results": [

0 commit comments

Comments
 (0)