diff --git a/policy/lib/statement.rego b/policy/lib/statement.rego deleted file mode 100644 index 57f652e37..000000000 --- a/policy/lib/statement.rego +++ /dev/null @@ -1,11 +0,0 @@ -package lib - -import future.keywords.if - -# statement returns the statement for the given attestation. This is a stop gap until -# https://github.com/enterprise-contract/ec-policies/issues/756 is addressed. A good place for this -# function would be in attestations.rego. However, this function is also used in dependencies of -# attestations.rego which would cause circular imports and make everyone sad. -statement(att) := statement if { - statement := att.statement -} else := att diff --git a/policy/lib/statement_test.rego b/policy/lib/statement_test.rego deleted file mode 100644 index 68229e6e6..000000000 --- a/policy/lib/statement_test.rego +++ /dev/null @@ -1,11 +0,0 @@ -package lib_test - -import future.keywords.if - -import data.lib - -test_statement if { - stmt := {"predicateType": "spam"} - lib.assert_equal(stmt, lib.statement(stmt)) - lib.assert_equal(stmt, lib.statement({"statement": stmt})) -} diff --git a/policy/lib/tekton/pipeline.rego b/policy/lib/tekton/pipeline.rego index 45969d162..403fa911a 100644 --- a/policy/lib/tekton/pipeline.rego +++ b/policy/lib/tekton/pipeline.rego @@ -4,7 +4,6 @@ import future.keywords.contains import future.keywords.if import future.keywords.in -import data.lib import data.lib.time as ectime pipeline_label := "pipelines.openshift.io/runtime" @@ -38,10 +37,10 @@ pipeline_label_selector(pipeline) := value if { value := build_task(pipeline).invocation.environment.labels[task_label] } else := value if { # PipelineRun labels found in the SLSA Provenance v1.0 - value := lib.statement(pipeline).predicate.buildDefinition.internalParameters.labels[pipeline_label] + value := pipeline.statement.predicate.buildDefinition.internalParameters.labels[pipeline_label] } else := value if { # PipelineRun labels found in the SLSA Provenance v0.2 - value := lib.statement(pipeline).predicate.invocation.environment.labels[pipeline_label] + value := pipeline.statement.predicate.invocation.environment.labels[pipeline_label] } else := value if { # Labels from a Tekton Pipeline definition value := pipeline.metadata.labels[pipeline_label] diff --git a/policy/lib/tekton/task.rego b/policy/lib/tekton/task.rego index 0811953dc..4c515b0b9 100644 --- a/policy/lib/tekton/task.rego +++ b/policy/lib/tekton/task.rego @@ -4,7 +4,6 @@ import future.keywords.contains import future.keywords.if import future.keywords.in -import data.lib import data.lib.refs import data.lib.time as ectime @@ -39,7 +38,7 @@ _slsa_task(task) if { # _maybe_tasks returns a set of potential tasks. # Handle tasks from a PipelineRun attestation. -_maybe_tasks(attestation) := lib.statement(attestation).predicate.buildConfig.tasks +_maybe_tasks(attestation) := attestation.statement.predicate.buildConfig.tasks # Handle tasks from a Pipeline definition. _maybe_tasks(pipeline) := _tasks if { @@ -53,7 +52,7 @@ _maybe_tasks(pipeline) := _tasks if { # handle tasks from a slsav1 attestation _maybe_tasks(slsav1) := _tasks if { - deps := lib.statement(slsav1).predicate.buildDefinition.resolvedDependencies + deps := slsav1.statement.predicate.buildDefinition.resolvedDependencies _tasks := {json.unmarshal(base64.decode(dep.content)) | some dep in deps _slsav1_tekton(dep) diff --git a/policy/lib/tekton/task_test.rego b/policy/lib/tekton/task_test.rego index 2ae013774..bcb3e43fc 100644 --- a/policy/lib/tekton/task_test.rego +++ b/policy/lib/tekton/task_test.rego @@ -27,7 +27,7 @@ test_tasks_from_attestation if { git_clone := {"name": "ignored", "ref": {"name": "git-clone"}} buildah := {"name": "ignored", "ref": {"name": "buildah"}} - attestation := {"predicate": {"buildConfig": {"tasks": [git_clone, buildah]}}} + attestation := {"statement": {"predicate": {"buildConfig": {"tasks": [git_clone, buildah]}}}} expected := {git_clone, buildah} lib.assert_equal(expected, tkn.tasks(attestation)) } @@ -42,14 +42,14 @@ test_tasks_from_slsav1_tekton_attestation if { "content": content, } - attestation := { + attestation := {"statement": { "predicateType": "https://slsa.dev/provenance/v1", "predicate": {"buildDefinition": { "buildType": "https://tekton.dev/chains/v2/slsa-tekton", "externalParameters": {"runSpec": {"pipelineSpec": {}}}, "resolvedDependencies": [task], }}, - } + }} expected := {{ "params": [ { @@ -120,14 +120,14 @@ test_tasks_from_slsav1_tekton_mixture_attestation if { "content": task3, } - attestation := {"predicate": {"buildDefinition": { + attestation := {"statement": {"predicate": {"buildDefinition": { "buildType": "https://tekton.dev/chains/v2/slsa-tekton", "resolvedDependencies": [ git_init, git_init_pipeline, git_init_bad, ], - }}} + }}}} expected := { { "params": [ @@ -181,10 +181,10 @@ test_tasks_from_slsav1_attestation if { "uri": "oci://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init", "digest": {"sha256": "28ff94e63e4058afc3f15b4c11c08cf3b54fa91faa646a4bbac90380cd7158df"}, } - attestation := {"predicate": {"buildDefinition": { + attestation := {"statement": {"predicate": {"buildDefinition": { "buildType": "https://tekton.dev/chains/v2/slsa-tekton", "resolvedDependencies": [git_init], - }}} + }}}} lib.assert_equal(set(), tkn.tasks(attestation)) } @@ -253,7 +253,7 @@ test_tasks_from_attestation_with_spam if { {"ref": {"name": "summary", "kind": "Task", "bundle": _bundle}}, } - attestation := {"predicate": {"buildConfig": {"tasks": expected_tasks}}} + attestation := {"statement": {"predicate": {"buildConfig": {"tasks": expected_tasks}}}} lib.assert_equal(expected_tasks, tkn.tasks(attestation)) @@ -309,19 +309,19 @@ test_build_task if { test_build_task_not_found if { missing_image_url := json.patch(_good_attestation, [{ "op": "add", - "path": "/predicate/buildConfig/tasks/0/results/0/name", + "path": "/statement/predicate/buildConfig/tasks/0/results/0/name", "value": "IMAGE_URL_SKIP", }]) not tkn.build_task(missing_image_url) missing_image_digest := json.patch(_good_attestation, [{ "op": "add", - "path": "/predicate/buildConfig/tasks/0/results/1/name", + "path": "/statement/predicate/buildConfig/tasks/0/results/1/name", "value": "IMAGE_DIGEST_SKIP", }]) not tkn.build_task(missing_image_digest) - missing_results := json.remove(_good_attestation, ["/predicate/buildConfig/tasks/0/results"]) + missing_results := json.remove(_good_attestation, ["/statement/predicate/buildConfig/tasks/0/results"]) not tkn.build_task(missing_results) } @@ -333,19 +333,19 @@ test_git_clone_task if { test_git_clone_task_not_found if { missing_url := json.patch(_good_attestation, [{ "op": "add", - "path": "/predicate/buildConfig/tasks/1/results/0/name", + "path": "/statement/predicate/buildConfig/tasks/1/results/0/name", "value": "you-argh-el", }]) not tkn.git_clone_task(missing_url) missing_commit := json.patch(_good_attestation, [{ "op": "add", - "path": "/predicate/buildConfig/tasks/1/results/1/name", + "path": "/statement/predicate/buildConfig/tasks/1/results/1/name", "value": "bachelor", }]) not tkn.git_clone_task(missing_commit) - missing_results := json.remove(_good_attestation, ["/predicate/buildConfig/tasks/1/results"]) + missing_results := json.remove(_good_attestation, ["/statement/predicate/buildConfig/tasks/1/results"]) not tkn.git_clone_task(missing_results) } @@ -449,10 +449,10 @@ _good_git_clone_task := { "ref": {"kind": "Task", "name": "git-clone", "bundle": _bundle}, } -_good_attestation := {"predicate": { +_good_attestation := {"statement": {"predicate": { "buildType": lib.tekton_pipeline_run, "buildConfig": {"tasks": [_good_build_task, _good_git_clone_task]}, -}} +}}} slsav1_attestation_local_spec := { "params": [ diff --git a/policy/release/attestation_type.rego b/policy/release/attestation_type.rego index 11348ff8e..12bd4ef03 100644 --- a/policy/release/attestation_type.rego +++ b/policy/release/attestation_type.rego @@ -30,7 +30,7 @@ import data.lib # deny contains result if { some att in lib.pipelinerun_attestations - att_type := att._type + att_type := att.statement._type not att_type in lib.rule_data("known_attestation_types") result := lib.result_helper(rego.metadata.chain(), [att_type]) } diff --git a/policy/release/attestation_type_test.rego b/policy/release/attestation_type_test.rego index e202c3a60..c5a4bf22a 100644 --- a/policy/release/attestation_type_test.rego +++ b/policy/release/attestation_type_test.rego @@ -47,9 +47,9 @@ test_deny_deprecated_policy_attestation_format { "code": "attestation_type.deprecated_policy_attestation_format", "msg": "Deprecated policy attestation format found", }} - attestations := [{ + attestations := [{"statement": { "_type": good_type, "predicate": {"buildType": lib.tekton_pipeline_run}, - }] + }}] lib.assert_equal_results(attestation_type.deny, expected) with input.attestations as attestations } diff --git a/policy/release/external_parameters.rego b/policy/release/external_parameters.rego index c6334038c..74a438545 100644 --- a/policy/release/external_parameters.rego +++ b/policy/release/external_parameters.rego @@ -26,12 +26,14 @@ import data.lib # deny contains result if { some provenance in lib.pipelinerun_attestations + param_names := {name | - some p in provenance.predicate.buildDefinition.externalParameters.runSpec.params + some p in provenance.statement.predicate.buildDefinition.externalParameters.runSpec.params p.value != "" name := p.name } expected_names := {n | some n in lib.rule_data("pipeline_run_params")} + expected_names != param_names result := lib.result_helper(rego.metadata.chain(), [param_names, expected_names]) } @@ -48,7 +50,7 @@ deny contains result if { deny contains result if { some provenance in lib.pipelinerun_attestations shared_workspaces := {w | - some w in provenance.predicate.buildDefinition.externalParameters.runSpec.workspaces + some w in provenance.statement.predicate.buildDefinition.externalParameters.runSpec.workspaces w.persistentVolumeClaim } count(shared_workspaces) > 0 diff --git a/policy/release/lib/attestations.rego b/policy/release/lib/attestations.rego index 16f17aa84..f53d98784 100644 --- a/policy/release/lib/attestations.rego +++ b/policy/release/lib/attestations.rego @@ -3,7 +3,6 @@ package lib import future.keywords.if import future.keywords.in -import data.lib import data.lib.tkn tekton_pipeline_run := "tekton.dev/v1beta1/PipelineRun" @@ -49,33 +48,32 @@ pipelinerun_attestations := att if { att := array.concat(v1_0, v0_2) } -pipelinerun_slsa_provenance02 := [statement | +pipelinerun_slsa_provenance02 := [att | some att in input.attestations - statement := lib.statement(att) - statement.predicate.buildType in pipelinerun_att_build_types + att.statement.predicate.buildType in pipelinerun_att_build_types ] # TODO: Make this work with pipelinerun_attestations above so policy rules can be # written for either. -pipelinerun_slsa_provenance_v1 := [statement | +pipelinerun_slsa_provenance_v1 := [att | some att in input.attestations - statement := lib.statement(att) - statement.predicateType == "https://slsa.dev/provenance/v1" + att.statement.predicateType == "https://slsa.dev/provenance/v1" - statement.predicate.buildDefinition.buildType in slsav1_pipelinerun_att_build_types + att.statement.predicate.buildDefinition.buildType in slsav1_pipelinerun_att_build_types # TODO: Workaround to distinguish between taskrun and pipelinerun attestations - spec_keys := object.keys(statement.predicate.buildDefinition.externalParameters.runSpec) + spec_keys := object.keys(att.statement.predicate.buildDefinition.externalParameters.runSpec) + pipeline_keys := {"pipelineRef", "pipelineSpec"} + count(pipeline_keys - spec_keys) != count(pipeline_keys) ] # These ones we don't care about any more -taskrun_attestations := [statement | +taskrun_attestations := [att | some att in input.attestations - statement := lib.statement(att) - statement.predicate.buildType in taskrun_att_build_types + att.statement.predicate.buildType in taskrun_att_build_types ] tasks_from_pipelinerun := [task | diff --git a/policy/release/lib/attestations_test.rego b/policy/release/lib/attestations_test.rego index f7b815175..14aedae61 100644 --- a/policy/release/lib/attestations_test.rego +++ b/policy/release/lib/attestations_test.rego @@ -165,7 +165,7 @@ test_tasks_from_pipelinerun { test_pr_attestations { lib.assert_equal( - [mock_pr_att.statement, mock_pr_att_legacy.statement], + [mock_pr_att, mock_pr_att_legacy], lib.pipelinerun_attestations, ) with input.attestations as [ mock_tr_att, @@ -175,18 +175,6 @@ test_pr_attestations { garbage_att, ] - # Deprecate format should still work for now - lib.assert_equal( - [mock_pr_att.statement, mock_pr_att_legacy.statement], - lib.pipelinerun_attestations, - ) with input.attestations as [ - mock_tr_att.statement, - mock_tr_att_legacy.statement, - mock_pr_att.statement, - mock_pr_att_legacy.statement, - garbage_att.statement, - ] - lib.assert_equal([], lib.pipelinerun_attestations) with input.attestations as [ mock_tr_att, mock_tr_att_legacy, @@ -243,28 +231,17 @@ test_pipelinerun_slsa_provenance_v1 { "value": {"taskRef": {}}, }]), ] - expected := [provenance_with_pr_spec.statement, provenance_with_pr_ref.statement] + expected := [provenance_with_pr_spec, provenance_with_pr_ref] lib.assert_equal(expected, lib.pipelinerun_slsa_provenance_v1) with input.attestations as attestations - - # Deprecated format should still work for now - old_attestations := [att.statement | some att in attestations] - lib.assert_equal(expected, lib.pipelinerun_slsa_provenance_v1) with input.attestations as old_attestations } test_tr_attestations { - lib.assert_equal([mock_tr_att.statement], lib.taskrun_attestations) with input.attestations as [ + lib.assert_equal([mock_tr_att], lib.taskrun_attestations) with input.attestations as [ mock_tr_att, mock_pr_att, garbage_att, ] - # Deprecated format should still work for now - lib.assert_equal([mock_tr_att.statement], lib.taskrun_attestations) with input.attestations as [ - mock_tr_att.statement, - mock_pr_att.statement, - garbage_att.statement, - ] - lib.assert_equal([], lib.taskrun_attestations) with input.attestations as [mock_pr_att, garbage_att] } diff --git a/policy/release/provenance_materials.rego b/policy/release/provenance_materials.rego index 3ee9794ef..71f38b266 100644 --- a/policy/release/provenance_materials.rego +++ b/policy/release/provenance_materials.rego @@ -61,7 +61,7 @@ deny contains result if { commit := tkn.task_result(t, "commit") materials := [m | - some m in attestation.predicate.materials + some m in attestation.statement.predicate.materials m.uri == url m.digest.sha1 == commit ] diff --git a/policy/release/sbom_spdx.rego b/policy/release/sbom_spdx.rego index 413516915..f9e09f5ae 100644 --- a/policy/release/sbom_spdx.rego +++ b/policy/release/sbom_spdx.rego @@ -92,9 +92,8 @@ deny contains result if { _sboms := [sbom | some att in input.attestations - statement := att.statement - statement.predicateType == "https://spdx.dev/Document" - sbom := _predicate(statement) + att.statement.predicateType == "https://spdx.dev/Document" + sbom := _predicate(att) ] # _is_valid is true if the given SPDX SBOM has certain fields. This is @@ -108,9 +107,9 @@ _is_valid(sbom) if { is_array(sbom.packages) } -# _predicate returns the predicate from the given statement. If the +# _predicate returns the predicate from the given attestation. If the # predicate is JSON marshaled, it is unmarshaled. -_predicate(statement) := predicate if { - json.is_valid(statement.predicate) - predicate := json.unmarshal(statement.predicate) -} else := statement.predicate +_predicate(att) := predicate if { + json.is_valid(att.statement.predicate) + predicate := json.unmarshal(att.statement.predicate) +} else := att.statement.predicate diff --git a/policy/release/slsa_build_build_service.rego b/policy/release/slsa_build_build_service.rego index 482153127..0e4d8e832 100644 --- a/policy/release/slsa_build_build_service.rego +++ b/policy/release/slsa_build_build_service.rego @@ -37,7 +37,7 @@ import data.lib # deny contains result if { some att in lib.pipelinerun_attestations - not att.predicate.builder.id + not att.statement.predicate.builder.id result := lib.result_helper(rego.metadata.chain(), []) } @@ -63,7 +63,7 @@ deny contains result if { deny contains result if { allowed_builder_ids := lib.rule_data("allowed_builder_ids") some att in lib.pipelinerun_attestations - builder_id := att.predicate.builder.id + builder_id := att.statement.predicate.builder.id not builder_id in allowed_builder_ids result := lib.result_helper(rego.metadata.chain(), [builder_id]) } diff --git a/policy/release/slsa_build_scripted_build.rego b/policy/release/slsa_build_scripted_build.rego index 6fa491ef8..9b17225ad 100644 --- a/policy/release/slsa_build_scripted_build.rego +++ b/policy/release/slsa_build_scripted_build.rego @@ -95,7 +95,7 @@ deny contains result if { some attestation in lib.pipelinerun_attestations build_task := tkn.build_task(attestation) - some subject in attestation.subject + some subject in attestation.statement.subject subject_image_ref := concat("@", [subject.name, subject_digest(subject)]) result_image_ref := concat("@", [ diff --git a/policy/release/slsa_provenance_available.rego b/policy/release/slsa_provenance_available.rego index 07e8452d1..d450f457b 100644 --- a/policy/release/slsa_provenance_available.rego +++ b/policy/release/slsa_provenance_available.rego @@ -41,6 +41,9 @@ import data.lib deny contains result if { some att in lib.pipelinerun_attestations allowed_predicate_types := lib.rule_data("allowed_predicate_types") - not att.predicateType in allowed_predicate_types - result := lib.result_helper(rego.metadata.chain(), [att.predicateType, concat(", ", allowed_predicate_types)]) + not att.statement.predicateType in allowed_predicate_types + result := lib.result_helper( + rego.metadata.chain(), + [att.statement.predicateType, concat(", ", allowed_predicate_types)], + ) } diff --git a/policy/release/slsa_source_correlated.rego b/policy/release/slsa_source_correlated.rego index 6adbce6cd..1f5bef40b 100644 --- a/policy/release/slsa_source_correlated.rego +++ b/policy/release/slsa_source_correlated.rego @@ -150,7 +150,7 @@ _expected_sources contains expected_source if { # SLSA Provenance v0.2 _source_references contains ref if { some att in lib.pipelinerun_attestations - some material in att.predicate.materials + some material in att.statement.predicate.materials some digest_alg in object.keys(material.digest) some supported_vcs_type in lib.rule_data("supported_vcs") @@ -170,7 +170,7 @@ _source_references contains ref if { some att in lib.pipelinerun_slsa_provenance_v1 # regal ignore:prefer-snake-case - some dep in att.predicate.buildDefinition.resolvedDependencies + some dep in att.statement.predicate.buildDefinition.resolvedDependencies some digest_alg in object.keys(dep.digest) some supported_vcs_type in lib.rule_data("supported_vcs") diff --git a/policy/release/slsa_source_version_controlled.rego b/policy/release/slsa_source_version_controlled.rego index b7f5de709..e791713e8 100644 --- a/policy/release/slsa_source_version_controlled.rego +++ b/policy/release/slsa_source_version_controlled.rego @@ -112,7 +112,7 @@ deny contains result if { materials contains material if { some attestation in lib.pipelinerun_attestations - some material in attestation.predicate.materials + some material in attestation.statement.predicate.materials material.uri material.digest.sha1 } diff --git a/policy/release/step_image_registries_test.rego b/policy/release/step_image_registries_test.rego index 73b88a0b4..627ff6f1d 100644 --- a/policy/release/step_image_registries_test.rego +++ b/policy/release/step_image_registries_test.rego @@ -66,7 +66,7 @@ test_unexpected_image_ref if { lib.assert_equal_results(step_image_registries.deny, {{ "code": "step_image_registries.task_step_images_permitted", "msg": sprintf("Step 0 in task 'mytask' has disallowed image ref '%s'", [unexpected_image]), - }}) with input.attestations as mock_data(unexpected_image) + }}) with input.attestations as [mock_data(unexpected_image)] } test_step_image_registry_prefix_list_found if {