Skip to content

Commit

Permalink
Merge pull request #1212 from kosciCZ/add-allowed-package-sources
Browse files Browse the repository at this point in the history
Add allowed package sources policy
  • Loading branch information
lcarva authored Nov 18, 2024
2 parents d246a4a + d4be578 commit fe6de9f
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 0 deletions.
15 changes: 15 additions & 0 deletions antora/docs/modules/ROOT/pages/release_policy.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Rules included:
* xref:release_policy.adoc#rpm_repos__rule_data_provided[RPM Repos: Known repo id list provided]
* xref:release_policy.adoc#rpm_signature__rule_data_provided[RPM Signature: Rule data provided]
* xref:release_policy.adoc#sbom_cyclonedx__allowed_package_external_references[SBOM CycloneDX: Allowed package external references]
* xref:release_policy.adoc#sbom_cyclonedx__allowed_package_sources[SBOM CycloneDX: Allowed package sources]
* xref:release_policy.adoc#sbom_cyclonedx__disallowed_package_attributes[SBOM CycloneDX: Disallowed package attributes]
* xref:release_policy.adoc#sbom_cyclonedx__disallowed_package_external_references[SBOM CycloneDX: Disallowed package external references]
* xref:release_policy.adoc#sbom__disallowed_packages_provided[SBOM: Disallowed packages list is provided]
Expand Down Expand Up @@ -142,6 +143,7 @@ Rules included:
* xref:release_policy.adoc#rpm_signature__rule_data_provided[RPM Signature: Rule data provided]
* xref:release_policy.adoc#sbom_cyclonedx__allowed[SBOM CycloneDX: Allowed]
* xref:release_policy.adoc#sbom_cyclonedx__allowed_package_external_references[SBOM CycloneDX: Allowed package external references]
* xref:release_policy.adoc#sbom_cyclonedx__allowed_package_sources[SBOM CycloneDX: Allowed package sources]
* xref:release_policy.adoc#sbom_cyclonedx__disallowed_package_attributes[SBOM CycloneDX: Disallowed package attributes]
* xref:release_policy.adoc#sbom_cyclonedx__disallowed_package_external_references[SBOM CycloneDX: Disallowed package external references]
* xref:release_policy.adoc#sbom_cyclonedx__valid[SBOM CycloneDX: Valid]
Expand Down Expand Up @@ -1149,6 +1151,19 @@ Confirm the CycloneDX SBOM contains only packages with explicitly allowed extern
* Code: `sbom_cyclonedx.allowed_package_external_references`
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/release/sbom_cyclonedx/sbom_cyclonedx.rego#L89[Source, window="_blank"]

[#sbom_cyclonedx__allowed_package_sources]
=== link:#sbom_cyclonedx__allowed_package_sources[Allowed package sources]

For each of the components fetched by Cachi2 which define externalReferences of type distribution, verify they are allowed based on the allowed_package_sources rule data key. By default, allowed_package_sources is empty, which means no components with such references are allowed.

*Solution*: Update the image to not use a package from a disallowed source.

* Rule type: [rule-type-indicator failure]#FAILURE#
* FAILURE message: `Package %s fetched by cachi2 was sourced from %q which is not allowed`
* Code: `sbom_cyclonedx.allowed_package_sources`
* Effective from: `2024-12-15T00:00:00Z`
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/release/sbom_cyclonedx/sbom_cyclonedx.rego#L151[Source, window="_blank"]

[#sbom_cyclonedx__disallowed_package_attributes]
=== link:#sbom_cyclonedx__disallowed_package_attributes[Disallowed package attributes]

Expand Down
1 change: 1 addition & 0 deletions antora/docs/modules/ROOT/partials/release_policy_nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
*** xref:release_policy.adoc#sbom_cyclonedx_package[SBOM CycloneDX]
**** xref:release_policy.adoc#sbom_cyclonedx__allowed[Allowed]
**** xref:release_policy.adoc#sbom_cyclonedx__allowed_package_external_references[Allowed package external references]
**** xref:release_policy.adoc#sbom_cyclonedx__allowed_package_sources[Allowed package sources]
**** xref:release_policy.adoc#sbom_cyclonedx__disallowed_package_attributes[Disallowed package attributes]
**** xref:release_policy.adoc#sbom_cyclonedx__disallowed_package_external_references[Disallowed package external references]
**** xref:release_policy.adoc#sbom_cyclonedx__valid[Valid]
Expand Down
34 changes: 34 additions & 0 deletions policy/lib/sbom/sbom.rego
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,38 @@ rule_data_errors contains error if {
}
}

# Verify allowed_package_sources is array of purl/regex list pairs
rule_data_errors contains error if {
some e in j.validate_schema(
lib.rule_data(rule_data_allowed_package_sources_key),
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {"type": "string"},
"patterns": {
"type": "array",
"items": {
"type": "string",
"format": "regex",
},
},
},
"required": ["type", "patterns"],
"additionalProperties": false,
},
},
)

error := {
# regal ignore:line-length
"message": sprintf("Rule data %s has unexpected format: %s", [rule_data_allowed_package_sources_key, e.message]),
"severity": e.severity,
}
}

_sbom_cyclonedx_image_path := "root/buildinfo/content_manifests/sbom-cyclonedx.json"

_sbom_spdx_image_path := "root/buildinfo/content_manifests/sbom-spdx.json"
Expand All @@ -266,3 +298,5 @@ rule_data_attributes_key := "disallowed_attributes"
rule_data_allowed_external_references_key := "allowed_external_references"

rule_data_disallowed_external_references_key := "disallowed_external_references"

rule_data_allowed_package_sources_key := "allowed_package_sources"
25 changes: 25 additions & 0 deletions policy/release/sbom/sbom_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ test_rule_data_validation if {
{"type": "distribution", "url": "badurl"},
{"invalid": "foo"},
],
lib.sbom.rule_data_allowed_package_sources_key: [
{"type": "generic", "patterns": ["["]},
{"invalid": "foo"},
],
}

expected := {
Expand Down Expand Up @@ -193,6 +197,26 @@ test_rule_data_validation if {
"msg": "Rule data allowed_external_references has unexpected format: 1: url is required",
"severity": "failure",
},
{
"code": "sbom.disallowed_packages_provided",
"msg": "Rule data allowed_package_sources has unexpected format: 0.patterns.0: Does not match format 'regex'",
"severity": "failure",
},
{
"code": "sbom.disallowed_packages_provided",
"msg": "Rule data allowed_package_sources has unexpected format: 1: Additional property invalid is not allowed",
"severity": "warning",
},
{
"code": "sbom.disallowed_packages_provided",
"msg": "Rule data allowed_package_sources has unexpected format: 1: patterns is required",
"severity": "failure",
},
{
"code": "sbom.disallowed_packages_provided",
"msg": "Rule data allowed_package_sources has unexpected format: 1: type is required",
"severity": "failure",
},
{
"code": "sbom.disallowed_packages_provided",
# regal ignore:line-length
Expand Down Expand Up @@ -227,6 +251,7 @@ test_rule_data_validation if {
with data.rule_data as {
lib.sbom.rule_data_packages_key: [],
lib.sbom.rule_data_attributes_key: [],
lib.sbom.rule_data_allowed_package_sources_key: [],
}
}

Expand Down
55 changes: 55 additions & 0 deletions policy/release/sbom_cyclonedx/sbom_cyclonedx.rego
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,61 @@ deny contains result if {
result := lib.result_helper_with_term(rego.metadata.chain(), [id, reference.url, reference.type, msg], id)
}

# METADATA
# title: Allowed package sources
# description: >-
# For each of the components fetched by Cachi2 which define externalReferences of type
# distribution, verify they are allowed based on the allowed_package_sources rule data
# key. By default, allowed_package_sources is empty, which means no components with such
# references are allowed.
# custom:
# short_name: allowed_package_sources
# failure_msg: Package %s fetched by cachi2 was sourced from %q which is not allowed
# solution: Update the image to not use a package from a disallowed source.
# collections:
# - redhat
# - policy_data
# effective_on: 2024-12-15T00:00:00Z
deny contains result if {
some s in sbom.cyclonedx_sboms
some component in s.components

# only look at components that define an externalReferences of type `distribution`
some reference in component.externalReferences
reference.type == "distribution"

# only look at components fetched by cachi2
some properties in component.properties
properties.name == "cachi2:found_by"
properties.value == "cachi2"

purl := component.purl
parsed_purl := ec.purl.parse(purl)

# patterns are either those defined by the rule for a given purl type, or empty by default
allowed_data := lib.rule_data(sbom.rule_data_allowed_package_sources_key)
patterns := _get_purl_allowed_patterns(parsed_purl.type, allowed_data)
distribution_url := object.get(reference, "url", "")

# only progress past this point if no matches were found
not _url_matches_any_pattern(distribution_url, patterns)

result := lib.result_helper_with_term(rego.metadata.chain(), [purl, distribution_url], purl)
}

# get allowed pattens for given purl type, or empty list if not defined
_get_purl_allowed_patterns(purl_type, allowed_rule_data) := patterns if {
some allowed in allowed_rule_data
purl_type == allowed.type
patterns := allowed.patterns
} else := []

# see if any pattern matches given url
_url_matches_any_pattern(url, patterns) if {
some pattern in patterns
regex.match(pattern, url)
}

# _with_effective_on annotates the result with the item's effective_on attribute. If the item does
# not have the attribute, result is returned unmodified.
_with_effective_on(result, item) := new_result if {
Expand Down
95 changes: 95 additions & 0 deletions policy/release/sbom_cyclonedx/sbom_cyclonedx_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,101 @@ test_external_references_disallowed_no_purl if {
}]}
}

test_allowed_package_sources if {
expected := {{
"code": "sbom_cyclonedx.allowed_package_sources",
"term": "pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz",
# regal ignore:line-length
"msg": `Package pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz fetched by cachi2 was sourced from "https://openssl.org/source/openssl-1.1.0g.tar.gz" which is not allowed`,
}}

att := json.patch(_sbom_attestation, [
{
"op": "add",
"path": "/statement/predicate/components/-",
"value": {
"type": "file",
"name": "openssl",
"purl": "pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz",
"properties": [{
"name": "cachi2:found_by",
"value": "cachi2",
}],
"externalReferences": [{"type": "distribution", "url": "https://openssl.org/source/openssl-1.1.0g.tar.gz"}],
},
},
{
"op": "add",
"path": "/statement/predicate/components/-",
"value": {
"type": "library",
"name": "batik-anim",
"purl": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom",
"properties": [{
"name": "cachi2:found_by",
"value": "cachi2",
}],
# regal ignore:line-length
"externalReferences": [{"type": "distribution", "url": "https://repo.maven.apache.org/maven2/org/apache/xmlgraphics/batik-anim/1.9.1/batik-anim-1.9.1.pom"}],
},
},
{
"op": "add",
"path": "/statement/predicate/components/-",
"value": {
"type": "file",
"name": "unrelated",
"purl": "pkg:generic/unrelated",
"externalReferences": [{"type": "distribution", "url": "https://irrelevant.org"}],
},
},
])

lib.assert_equal_results(expected, sbom_cyclonedx.deny) with input.attestations as [att]
with data.rule_data as {sbom.rule_data_allowed_package_sources_key: [
{
"type": "maven",
"patterns": [".*apache.org.*", ".*example.com.*"],
},
{
"type": "generic",
"patterns": [".*apache.org.*", ".*example.com.*"],
},
]}
}

test_allowed_package_sources_no_rule_defined if {
expected := {{
"code": "sbom_cyclonedx.allowed_package_sources",
"term": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom",
# regal ignore:line-length
"msg": `Package pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom fetched by cachi2 was sourced from "https://repo.maven.apache.org/maven2/org/apache/xmlgraphics/batik-anim/1.9.1/batik-anim-1.9.1.pom" which is not allowed`,
}}

att := json.patch(_sbom_attestation, [{
"op": "add",
"path": "/statement/predicate/components/-",
"value": {
"type": "library",
"name": "batik-anim",
"purl": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom",
"properties": [{
"name": "cachi2:found_by",
"value": "cachi2",
}],
# regal ignore:line-length
"externalReferences": [{"type": "distribution", "url": "https://repo.maven.apache.org/maven2/org/apache/xmlgraphics/batik-anim/1.9.1/batik-anim-1.9.1.pom"}],
},
}])

# rule data is defined only for purl of type generic
lib.assert_equal_results(expected, sbom_cyclonedx.deny) with input.attestations as [att]
with data.rule_data as {sbom.rule_data_allowed_package_sources_key: [{
"type": "generic",
"patterns": [".*example.com.*"],
}]}
}

test_attributes_not_allowed_no_properties if {
att := json.patch(_sbom_attestation, [{
"op": "remove",
Expand Down

0 comments on commit fe6de9f

Please sign in to comment.