-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Add beta.packages rego package
- Loading branch information
Showing
8 changed files
with
303 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# | ||
# METADATA | ||
# description: >- | ||
# Checks the CycloneDX SBOMs associated with the image being validated do not include packages | ||
# that have been deemed not allowed. | ||
# NOTE: The policy rules in this package will eventually move to the release.sbom_cyclonedx | ||
# package once the required ec.purl.parse rego function is widely available. | ||
# | ||
package policy.beta.packages | ||
|
||
import future.keywords.contains | ||
import future.keywords.if | ||
import future.keywords.in | ||
|
||
import data.lib | ||
import data.lib.sbom | ||
|
||
# METADATA | ||
# title: Allowed | ||
# description: >- | ||
# Confirm the CycloneDX SBOM contains only allowed packages. By default all packages are allowed. | ||
# Use the "disallowed_packages" rule data key to provide a list of disallowed packages. | ||
# custom: | ||
# short_name: allowed | ||
# failure_msg: "Package is not allowed: %s" | ||
# solution: >- | ||
# Update the image to not use a disallowed package. | ||
# collections: | ||
# - redhat | ||
# | ||
deny contains result if { | ||
some s in sbom.cyclonedx_sboms | ||
some component in s.components | ||
_contains(component.purl, lib.rule_data("disallowed_packages")) | ||
result := lib.result_helper(rego.metadata.chain(), [component.purl]) | ||
} | ||
|
||
_contains(needle, haystack) if { | ||
needle_purl := ec.purl.parse(needle) | ||
|
||
some hay in haystack | ||
hay_purl := ec.purl.parse(hay.purl) | ||
|
||
needle_purl.type == hay_purl.type | ||
needle_purl.namespace == hay_purl.namespace | ||
needle_purl.name == hay_purl.name | ||
_matches_version(needle_purl.version, hay) | ||
} else := false | ||
|
||
_matches_version(version, matcher) if { | ||
matcher.format in {"semverv", "semver"} | ||
matcher.min != "" | ||
matcher.max != "" | ||
semver.compare(_to_semver(version), _to_semver(matcher.min)) != -1 | ||
semver.compare(_to_semver(version), _to_semver(matcher.max)) != 1 | ||
} else if { | ||
matcher.format in {"semverv", "semver"} | ||
matcher.min != "" | ||
object.get(matcher, "max", "") == "" | ||
semver.compare(_to_semver(version), _to_semver(matcher.min)) != -1 | ||
} else if { | ||
matcher.format in {"semverv", "semver"} | ||
matcher.max != "" | ||
object.get(matcher, "min", "") == "" | ||
semver.compare(_to_semver(version), _to_semver(matcher.max)) != 1 | ||
} else := false | ||
|
||
_to_semver(v) := trim_prefix(v, "v") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
package policy.beta.packages_test | ||
|
||
import future.keywords.if | ||
import future.keywords.in | ||
|
||
import data.lib | ||
import data.policy.beta.packages | ||
|
||
test_allowed_by_default if { | ||
assert_allowed("pkg:golang/k8s.io/client-go@v0.28.3", []) | ||
} | ||
|
||
test_not_allowed_with_min if { | ||
disallowed_packages := [{ | ||
"purl": "pkg:golang/k8s.io/client-go", | ||
"format": "semverv", | ||
"min": "v50.28.3", | ||
}] | ||
|
||
# Much lower than min version | ||
assert_allowed("pkg:golang/k8s.io/client-go@v0.29.4", disallowed_packages) | ||
|
||
# Lower than min version | ||
assert_allowed("pkg:golang/k8s.io/client-go@v50.28.2", disallowed_packages) | ||
|
||
# Exact match to min version | ||
assert_not_allowed("pkg:golang/k8s.io/client-go@v50.28.3", disallowed_packages) | ||
|
||
# Higher than min version | ||
assert_not_allowed("pkg:golang/k8s.io/client-go@v50.28.4", disallowed_packages) | ||
|
||
# Much higher than min version | ||
assert_not_allowed("pkg:golang/k8s.io/client-go@v99.99.99", disallowed_packages) | ||
} | ||
|
||
test_not_allowed_with_max if { | ||
disallowed_packages := [{ | ||
"purl": "pkg:golang/k8s.io/client-go", | ||
"format": "semverv", | ||
"max": "v50.28.3", | ||
}] | ||
|
||
# Much lower than max version | ||
assert_not_allowed("pkg:golang/k8s.io/client-go@v0.29.4", disallowed_packages) | ||
|
||
# Lower than max version | ||
assert_not_allowed("pkg:golang/k8s.io/client-go@v50.28.2", disallowed_packages) | ||
|
||
# Exact match to max version | ||
assert_not_allowed("pkg:golang/k8s.io/client-go@v50.28.3", disallowed_packages) | ||
|
||
# Higher than max version | ||
assert_allowed("pkg:golang/k8s.io/client-go@v50.28.4", disallowed_packages) | ||
|
||
# Much higher than max version | ||
assert_allowed("pkg:golang/k8s.io/client-go@v99.99.99", disallowed_packages) | ||
} | ||
|
||
test_not_allowed_with_min_max if { | ||
disallowed_packages := [{ | ||
"purl": "pkg:golang/k8s.io/client-go", | ||
"format": "semverv", | ||
"min": "v50.20.2", | ||
"max": "v50.28.3", | ||
}] | ||
|
||
# Much lower than min version | ||
assert_allowed("pkg:golang/k8s.io/client-go@v0.29.4", disallowed_packages) | ||
|
||
# Lower than min version | ||
assert_allowed("pkg:golang/k8s.io/client-go@v50.20.1", disallowed_packages) | ||
|
||
# Exact match to min version | ||
assert_not_allowed("pkg:golang/k8s.io/client-go@v50.20.2", disallowed_packages) | ||
|
||
# Mid-range | ||
assert_not_allowed("pkg:golang/k8s.io/client-go@v50.24.9", disallowed_packages) | ||
|
||
# Exact match to max version | ||
assert_not_allowed("pkg:golang/k8s.io/client-go@v50.28.3", disallowed_packages) | ||
|
||
# Higher than max version | ||
assert_allowed("pkg:golang/k8s.io/client-go@v50.28.4", disallowed_packages) | ||
|
||
# Much higher than max version | ||
assert_allowed("pkg:golang/k8s.io/client-go@v99.99.99", disallowed_packages) | ||
} | ||
|
||
assert_allowed(purl, disallowed_packages) if { | ||
att := json.patch(_sbom_attestation, [{ | ||
"op": "add", | ||
"path": "/statement/predicate/components/0/purl", | ||
"value": purl, | ||
}]) | ||
lib.assert_empty(packages.deny) with input.attestations as [att] | ||
with data.rule_data.disallowed_packages as disallowed_packages | ||
} | ||
|
||
assert_not_allowed(purl, disallowed_packages) if { | ||
expected := {{ | ||
"code": "packages.allowed", | ||
"msg": sprintf("Package is not allowed: %s", [purl]), | ||
}} | ||
att := json.patch(_sbom_attestation, [{ | ||
"op": "add", | ||
"path": "/statement/predicate/components/0/purl", | ||
"value": purl, | ||
}]) | ||
lib.assert_equal_results(packages.deny, expected) with input.attestations as [att] | ||
with data.rule_data.disallowed_packages as disallowed_packages | ||
} | ||
|
||
_sbom_attestation := {"statement": { | ||
"predicateType": "https://cyclonedx.org/bom", | ||
"predicate": { | ||
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json", | ||
"bomFormat": "CycloneDX", | ||
"specVersion": "1.5", | ||
"serialNumber": "urn:uuid:cf1a2c3d-bcf8-45c4-9d0f-b2b59a0753f0", | ||
"version": 1, | ||
"metadata": { | ||
"timestamp": "2023-11-20T17:32:41Z", | ||
"tools": [{ | ||
"vendor": "anchore", | ||
"name": "syft", | ||
"version": "0.96.0", | ||
}], | ||
"component": { | ||
"bom-ref": "158c8a990fbd4038", | ||
"type": "file", | ||
"name": "/var/lib/containers/storage/vfs/dir/dfd74fe178f4ea0472b5569bff38a4df69d05e7a81b538c98d731566aec15a69", | ||
}, | ||
}, | ||
"components": [{ | ||
# regal ignore:line-length | ||
"bom-ref": "pkg:rpm/rhel/coreutils-single@8.32-34.el9?arch=x86_64&upstream=coreutils-8.32-34.el9.src.rpm&distro=rhel-9.3&package-id=f4f4e3cc2a6d9c37", | ||
"type": "library", | ||
"publisher": "Red Hat, Inc.", | ||
"name": "coreutils-single", | ||
"version": "8.32-34.el9", | ||
"licenses": [{"license": {"name": "GPLv3+"}}], | ||
"cpe": "cpe:2.3:a:coreutils-single:coreutils-single:8.32-34.el9:*:*:*:*:*:*:*", | ||
# regal ignore:line-length | ||
"purl": "pkg:rpm/rhel/coreutils-single@8.32-34.el9?arch=x86_64&upstream=coreutils-8.32-34.el9.src.rpm&distro=rhel-9.3", | ||
}], | ||
}, | ||
}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package lib.sbom | ||
|
||
import future.keywords.in | ||
|
||
cyclonedx_sboms := array.concat(_cyclonedx_sboms_from_image, _cyclonedx_sboms_from_attestations) | ||
|
||
_cyclonedx_sboms_from_image := [sbom | | ||
some path in ["root/buildinfo/content_manifests/sbom-cyclonedx.json"] | ||
sbom := input.image.files[path] | ||
] | ||
|
||
_cyclonedx_sboms_from_attestations := [sbom | | ||
some att in input.attestations | ||
statement := att.statement | ||
|
||
# https://cyclonedx.org/specification/overview/#recognized-predicate-type | ||
statement.predicateType == "https://cyclonedx.org/bom" | ||
sbom := statement.predicate | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package lib.sbom_test | ||
|
||
import future.keywords.if | ||
import future.keywords.in | ||
|
||
import data.lib | ||
import data.lib.sbom | ||
|
||
test_cyclonedx_sboms if { | ||
attestations := [ | ||
{"statement": { | ||
"predicateType": "https://cyclonedx.org/bom", | ||
"predicate": "sbom from attestation", | ||
}}, | ||
{"statement": { | ||
"predicateType": "https://example.org/boom", | ||
"predicate": "not an sbom", | ||
}}, | ||
] | ||
image := {"files": { | ||
"root/buildinfo/content_manifests/sbom-cyclonedx.json": "sbom from image", | ||
"root/foo": "not an sbom", | ||
}} | ||
expected := ["sbom from image", "sbom from attestation"] | ||
lib.assert_equal(sbom.cyclonedx_sboms, expected) with input.attestations as attestations | ||
with input.image as image | ||
} |
Oops, something went wrong.