Skip to content

Commit

Permalink
Merge pull request #1116 from lcarva/EC-794
Browse files Browse the repository at this point in the history
Verify Task definitions contain a certain result
  • Loading branch information
lcarva authored Aug 28, 2024
2 parents 3629b60 + a6bd2a8 commit 1797b7c
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 0 deletions.
2 changes: 2 additions & 0 deletions antora/docs/modules/ROOT/pages/release_policy.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ Rules included:
* xref:release_policy.adoc#slsa_provenance_available__allowed_predicate_types_provided[SLSA - Provenance - Available: Allowed predicate types provided]
* xref:release_policy.adoc#slsa_source_correlated__rule_data_provided[SLSA - Verification model - Source: Rule data provided]
* xref:release_policy.adoc#schedule__rule_data_provided[Schedule related checks: Rule data provided]
* xref:release_policy.adoc#results__rule_data_provided[Tekton Task result: Rule data provided]
* xref:release_policy.adoc#test__rule_data_provided[Test: Rule data provided]

| [#redhat]`redhat`
Expand Down Expand Up @@ -174,6 +175,7 @@ Rules included:
* xref:release_policy.adoc#tasks__required_tasks_list_provided[Tasks: Required tasks list was provided]
* xref:release_policy.adoc#tasks__successful_pipeline_tasks[Tasks: Successful pipeline tasks]
* xref:release_policy.adoc#tasks__unsupported[Tasks: Task version unsupported]
* xref:release_policy.adoc#results__rule_data_provided[Tekton Task result: Rule data provided]
* xref:release_policy.adoc#test__test_all_images[Test: Image digest is present in IMAGES_PROCESSED result]
* xref:release_policy.adoc#test__no_failed_informative_tests[Test: No informative tests failed]
* xref:release_policy.adoc#test__no_erred_tests[Test: No tests erred]
Expand Down
30 changes: 30 additions & 0 deletions antora/docs/modules/ROOT/pages/task_policy.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,36 @@ Make sure to use the date format in RFC3339 format in the "build.appstudio.redha
* Code: `annotation.expires_on_format`
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/task/annotations.rego#L14[Source, window="_blank"]
[#results_package]
== link:#results_package[Tekton Task result]
Verify Tekton Task definitions provide expected results.
* Package name: `results`
* Package full path: `policy.task.results`
[#results__required]
=== link:#results__required[Required result defined]
Verify if Task defines the required result. This is controlled by the `required_task_results` rule data key. By default this is empty making this rule a no-op.
* Rule type: [rule-type-indicator failure]#FAILURE#
* FAILURE message: `%s`
* Code: `results.required`
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/task/results.rego#L12[Source, window="_blank"]
[#results__rule_data_provided]
=== link:#results__rule_data_provided[Rule data provided]
Confirm the expected `required_task_results` rule data key has been provided in the expected format.
*Solution*: If provided, ensure the rule data is in the expected format.
* Rule type: [rule-type-indicator failure]#FAILURE#
* FAILURE message: `%s`
* Code: `results.rule_data_provided`
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/task/results.rego#L26[Source, window="_blank"]
[#kind_package]
== link:#kind_package[Tekton task kind checks]
Expand Down
3 changes: 3 additions & 0 deletions antora/docs/modules/ROOT/partials/task_policy_nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
*** xref:task_policy.adoc#step_image_registries__step_images_permitted[Step images come from permitted registry]
** xref:task_policy.adoc#annotation_package[Tekton Task annotations]
*** xref:task_policy.adoc#annotation__expires_on_format[Task definition uses expires-on annotation in RFC3339 format]
** xref:task_policy.adoc#results_package[Tekton Task result]
*** xref:task_policy.adoc#results__required[Required result defined]
*** xref:task_policy.adoc#results__rule_data_provided[Rule data provided]
** xref:task_policy.adoc#kind_package[Tekton task kind checks]
*** xref:task_policy.adoc#kind__kind_present[Kind field is present in task definition]
*** xref:task_policy.adoc#kind__expected_kind[Task definition has expected kind]
Expand Down
78 changes: 78 additions & 0 deletions policy/task/results.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#
# METADATA
# title: Tekton Task result
# description: Verify Tekton Task definitions provide expected results.
#
package policy.task.results

import rego.v1

import data.lib

# METADATA
# title: Required result defined
# description: >-
# Verify if Task defines the required result. This is controlled by the `required_task_results`
# rule data key. By default this is empty making this rule a no-op.
# custom:
# short_name: required
# failure_msg: '%s'
#
deny contains result if {
some err in errors
result := lib.result_helper(rego.metadata.chain(), [err])
}

# METADATA
# title: Rule data provided
# description: >-
# Confirm the expected `required_task_results` rule data key has been provided in the expected
# format.
# custom:
# short_name: rule_data_provided
# failure_msg: '%s'
# solution: If provided, ensure the rule data is in the expected format.
# collections:
# - redhat
# - policy_data
#
deny contains result if {
some error in _rule_data_errors
result := lib.result_helper(rego.metadata.chain(), [error])
}

errors contains err if {
some required in lib.rule_data(_rule_data_key)
input.metadata.name == required.task
found := [result |
some result in input.spec.results
result.name == required.result
]
count(found) == 0
err := sprintf("%q result not found in %q Task", [required.result, required.task])
}

_rule_data_errors contains err if {
schema := {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": {
"type": "object",
"properties": {
"task": {"type": "string"},
"result": {"type": "string"},
},
"additionalProperties": false,
"required": ["task", "result"],
},
"uniqueItems": true,
}

# match_schema expects either a marshaled JSON resource (String) or an Object. It doesn't
# handle an Array directly.
value := json.marshal(lib.rule_data(_rule_data_key))
some violation in json.match_schema(value, schema)[1]
err := sprintf("Rule data %s has unexpected format: %s", [_rule_data_key, violation.error])
}

_rule_data_key := "required_task_results"
87 changes: 87 additions & 0 deletions policy/task/results_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package policy.task.results_test

import rego.v1

import data.lib
import data.policy.task.results

test_all_good if {
lib.assert_empty(results.deny) with input as _mock_task
with data.rule_data as _rule_data
}

test_required_result_defined if {
expected := {{
"code": "results.required",
"msg": "\"GRILLED\" result not found in \"bacon\" Task",
}}

lib.assert_equal_results(results.deny, expected) with data.rule_data as _rule_data
with input as json.patch(_mock_task, [{
"op": "add",
"path": "spec/results",
"value": [],
}])

lib.assert_equal_results(results.deny, expected) with data.rule_data as _rule_data
with input as json.remove(_mock_task, ["spec/results"])

lib.assert_equal_results(results.deny, expected) with data.rule_data as _rule_data
with input as json.remove(_mock_task, ["spec/results/0"])
}

test_rule_data_provided if {
d := {"required_task_results": [
# Wrong type
1,
# Duplicated items
{"task": "task1", "result": "result1"},
{"task": "task1", "result": "result1"},
# Additional properties
{"task": "task2", "result": "result2", "foo": "bar"},
# Bad type for task
{"task": 3, "result": "result3"},
# Bad type for result
{"task": "task4", "result": 4},
]}

expected := {
{
"code": "results.rule_data_provided",
"msg": "Rule data required_task_results has unexpected format: 0: Invalid type. Expected: object, given: integer",
},
{
"code": "results.rule_data_provided",
"msg": "Rule data required_task_results has unexpected format: (Root): array items[1,2] must be unique",
},
{
"code": "results.rule_data_provided",
"msg": "Rule data required_task_results has unexpected format: 3: Additional property foo is not allowed",
},
{
"code": "results.rule_data_provided",
# regal ignore:line-length
"msg": "Rule data required_task_results has unexpected format: 4.task: Invalid type. Expected: string, given: integer",
},
{
"code": "results.rule_data_provided",
# regal ignore:line-length
"msg": "Rule data required_task_results has unexpected format: 5.result: Invalid type. Expected: string, given: integer",
},
}

lib.assert_equal_results(results.deny, expected) with input as _mock_task
with data.rule_data as d
}

_mock_task := {
"apiVersion": "tekton.dev/v1",
"kind": "Task",
"metadata": {"name": "bacon"},
"spec": {"results": [
{"name": "GRILLED"},
{"name": "SCENT"},
]},
}

_rule_data := {"required_task_results": [{"task": "bacon", "result": "GRILLED"}]}

0 comments on commit 1797b7c

Please sign in to comment.