Skip to content

Commit e778631

Browse files
authored
Merge pull request #1578 from jorris/ROK-814
Add a Conforma rule to check RPM origin for build deps of RPM builds
2 parents b78dafc + d5a5ffe commit e778631

File tree

5 files changed

+278
-0
lines changed

5 files changed

+278
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
= RPM Build Dependencies Package
2+
3+
Checks different properties of the CycloneDX SBOMs associated with the image being validated.
4+
5+
== Package Name
6+
7+
* `rpm_build_deps`
8+
9+
== Rules Included
10+
11+
[#rpm_build_deps__download_location_valid]
12+
=== link:#rpm_build_deps__download_location_valid[Builds have valid download locations]
13+
14+
Builds have valid download locations for RPM build dependencies
15+
16+
* Rule type: [rule-type-indicator warning]#WARNING#
17+
* WARNING message: `RPM build dependency source %s is not in the allowed list %v.`
18+
* Code: `rpm_build_deps.download_location_valid`
19+
* https://github.com/conforma/policy/blob/{page-origin-refhash}/policy/release/rpm_build_deps/rpm_build_deps.rego#L14[Source, window="_blank"]

antora/docs/modules/ROOT/pages/release_policy.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ Rules included:
232232
* xref:packages/release_git_branch.adoc#git_branch__git_branch[Git branch checks: Builds have a trusted target branch]
233233
* xref:packages/release_provenance_materials.adoc#provenance_materials__git_clone_source_matches_provenance[Provenance Materials: Git clone source matches materials provenance]
234234
* xref:packages/release_provenance_materials.adoc#provenance_materials__git_clone_task_found[Provenance Materials: Git clone task found]
235+
* xref:packages/release_rpm_build_deps.adoc#rpm_build_deps__download_location_valid[RPM Build Dependencies: Builds have valid download locations]
235236
* xref:packages/release_rpm_pipeline.adoc#rpm_pipeline__invalid_pipeline[RPM Pipeline: Task version invalid_pipeline]
236237
* xref:packages/release_rpm_repos.adoc#rpm_repos__ids_known[RPM Repos: All rpms have known repo ids]
237238
* xref:packages/release_rpm_repos.adoc#rpm_repos__rule_data_provided[RPM Repos: Known repo id list provided]
@@ -395,6 +396,9 @@ a| Policies to prevent releasing an image to quay that has a quay expiration dat
395396
| xref:packages/release_rhtap_multi_ci.adoc[rhtap_multi_ci]
396397
a| Checks for images built using an RHTAP build pipeline in either Jenkins, GitLab or GitHub. RHTAP pipelines are defined under https://github.com/redhat-appstudio/tssc-sample-templates/tree/main/skeleton/ci
397398

399+
| xref:packages/release_rpm_build_deps.adoc[rpm_build_deps]
400+
a| Checks different properties of the CycloneDX SBOMs associated with the image being validated.
401+
398402
| xref:packages/release_rpm_packages.adoc[rpm_packages]
399403
a| Rules used to verify different properties of specific RPM packages found in the SBOM of the image being validated.
400404

antora/docs/modules/ROOT/partials/release_policy_nav.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@
8484
*** xref:packages/release_rhtap_multi_ci.adoc[RHTAP Multi-CI]
8585
**** xref:packages/release_rhtap_multi_ci.adoc#rhtap_multi_ci__attestation_format[SLSA Provenance Attestation Format]
8686
**** xref:packages/release_rhtap_multi_ci.adoc#rhtap_multi_ci__attestation_found[SLSA Provenance Attestation Found]
87+
*** xref:packages/release_rpm_build_deps.adoc[RPM Build Dependencies]
88+
**** xref:packages/release_rpm_build_deps.adoc#rpm_build_deps__download_location_valid[Builds have valid download locations]
8789
*** xref:packages/release_rpm_packages.adoc[RPM Packages]
8890
**** xref:packages/release_rpm_packages.adoc#rpm_packages__unique_version[Unique Version]
8991
*** xref:packages/release_rpm_pipeline.adoc[RPM Pipeline]
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#
2+
# METADATA
3+
# title: RPM Build Dependencies
4+
# description: >-
5+
# Checks different properties of the CycloneDX SBOMs associated with the image being validated.
6+
#
7+
package rpm_build_deps
8+
9+
import rego.v1
10+
11+
import data.lib
12+
import data.lib.sbom
13+
14+
# METADATA
15+
# title: Builds have valid download locations
16+
# description: Builds have valid download locations for RPM build dependencies
17+
# custom:
18+
# short_name: download_location_valid
19+
# failure_msg: RPM build dependency source %s is not in the allowed list %v.
20+
# collections:
21+
# - redhat_rpms
22+
warn contains result if {
23+
some s in sbom.spdx_sboms
24+
some pkg in s.packages
25+
26+
# NOASSERTION is displayed in the SBOM for the RPMS that have been built
27+
valid_locations := array.concat(["NOASSERTION"], lib.rule_data("allowed_rpm_build_dependency_sources"))
28+
not matches_any(pkg.downloadLocation, valid_locations)
29+
result := lib.result_helper(rego.metadata.chain(), [pkg.downloadLocation, valid_locations])
30+
}
31+
32+
matches_any(branch, valid_locations) if {
33+
# some pattern in lib.rule_data("allowed_target_branch_patterns")
34+
some pattern in valid_locations
35+
regex.match(pattern, branch)
36+
}
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
#
2+
# METADATA
3+
# title: RPM Build Dependencies tests
4+
# description: >-
5+
# Tests for rpm_build_deps policy
6+
#
7+
package rpm_build_deps_test
8+
9+
import rego.v1
10+
11+
import data.lib
12+
import data.rpm_build_deps
13+
14+
# Test with valid download location - NOASSERTION (always allowed)
15+
test_valid_download_location_noassertion if {
16+
att := _sbom_attestation_with_download_location("NOASSERTION")
17+
lib.assert_empty(rpm_build_deps.warn) with input.attestations as [att]
18+
with data.rule_data.allowed_rpm_build_dependency_sources as _mock_allowed_locations
19+
}
20+
21+
# Test with valid download location - brewroot pattern
22+
test_valid_download_location_brewroot if {
23+
att := _sbom_attestation_with_download_location("https://download.devel.redhat.com/brewroot/repos/some-package.rpm")
24+
lib.assert_empty(rpm_build_deps.warn) with input.attestations as [att]
25+
with data.rule_data.allowed_rpm_build_dependency_sources as _mock_allowed_locations
26+
}
27+
28+
# Test with valid download location - codeload pattern
29+
test_valid_download_location_codeload if {
30+
att := _sbom_attestation_with_download_location("https://codeload.github.com/user/repo/tar.gz/v1.0.0")
31+
lib.assert_empty(rpm_build_deps.warn) with input.attestations as [att]
32+
with data.rule_data.allowed_rpm_build_dependency_sources as _mock_allowed_locations
33+
}
34+
35+
# Test with valid download location - pypi pattern
36+
test_valid_download_location_pypi if {
37+
att := _sbom_attestation_with_download_location("https://files.pythonhosted.org/packages/some-package-1.0.tar.gz")
38+
lib.assert_empty(rpm_build_deps.warn) with input.attestations as [att]
39+
with data.rule_data.allowed_rpm_build_dependency_sources as _mock_allowed_locations
40+
}
41+
42+
# Test with valid download location - maven central pattern
43+
test_valid_download_location_maven if {
44+
location := "https://repo.maven.apache.org/maven2/org/example/artifact/1.0/artifact-1.0.jar"
45+
att := _sbom_attestation_with_download_location(location)
46+
lib.assert_empty(rpm_build_deps.warn) with input.attestations as [att]
47+
with data.rule_data.allowed_rpm_build_dependency_sources as _mock_allowed_locations
48+
}
49+
50+
# Test with invalid download location - doesn't match any allowed pattern
51+
test_invalid_download_location if {
52+
invalid_location := "https://untrusted.example.com/package.rpm"
53+
att := _sbom_attestation_with_download_location(invalid_location)
54+
expected_locations := array.concat(["NOASSERTION"], _mock_allowed_locations)
55+
expected := {{
56+
"code": "rpm_build_deps.download_location_valid",
57+
"msg": sprintf(
58+
"RPM build dependency source %s is not in the allowed list %v.",
59+
[invalid_location, expected_locations],
60+
),
61+
}}
62+
lib.assert_equal_results(expected, rpm_build_deps.warn) with input.attestations as [att]
63+
with data.rule_data.allowed_rpm_build_dependency_sources as _mock_allowed_locations
64+
}
65+
66+
# Test with multiple packages - all valid
67+
test_multiple_packages_all_valid if {
68+
att := _sbom_attestation_with_multiple_packages([
69+
"NOASSERTION",
70+
"https://download.devel.redhat.com/brewroot/repos/package1.rpm",
71+
"https://codeload.github.com/org/repo/tar.gz/v2.0",
72+
])
73+
lib.assert_empty(rpm_build_deps.warn) with input.attestations as [att]
74+
with data.rule_data.allowed_rpm_build_dependency_sources as _mock_allowed_locations
75+
}
76+
77+
# Test with multiple packages - one invalid
78+
test_multiple_packages_one_invalid if {
79+
att := _sbom_attestation_with_multiple_packages([
80+
"NOASSERTION",
81+
"https://untrusted.example.com/package.rpm",
82+
"https://download.devel.redhat.com/brewroot/repos/package2.rpm",
83+
])
84+
results := rpm_build_deps.warn with input.attestations as [att]
85+
with data.rule_data.allowed_rpm_build_dependency_sources as _mock_allowed_locations
86+
count(results) == 1
87+
}
88+
89+
# Test with multiple packages - all invalid
90+
test_multiple_packages_all_invalid if {
91+
att := _sbom_attestation_with_multiple_packages([
92+
"https://untrusted1.example.com/package1.rpm",
93+
"https://untrusted2.example.com/package2.rpm",
94+
])
95+
results := rpm_build_deps.warn with input.attestations as [att]
96+
with data.rule_data.allowed_rpm_build_dependency_sources as _mock_allowed_locations
97+
count(results) == 2
98+
}
99+
100+
# Test with empty SBOM
101+
test_empty_sbom if {
102+
att := {"statement": {
103+
"predicateType": "https://spdx.dev/Document",
104+
"predicate": {
105+
"spdxVersion": "SPDX-2.3",
106+
"packages": [],
107+
},
108+
}}
109+
lib.assert_empty(rpm_build_deps.warn) with input.attestations as [att]
110+
with data.rule_data.allowed_rpm_build_dependency_sources as _mock_allowed_locations
111+
}
112+
113+
# Test with empty rule_data - should only allow NOASSERTION
114+
test_empty_rule_data_warns_urls if {
115+
att := _sbom_attestation_with_download_location("https://download.devel.redhat.com/brewroot/repos/package.rpm")
116+
results := rpm_build_deps.warn with input.attestations as [att]
117+
with data.rule_data.allowed_rpm_build_dependency_sources as []
118+
count(results) == 1
119+
}
120+
121+
# Test NOASSERTION is always allowed even with empty rule_data
122+
test_noassertion_allowed_with_empty_rule_data if {
123+
att := _sbom_attestation_with_download_location("NOASSERTION")
124+
lib.assert_empty(rpm_build_deps.warn) with input.attestations as [att]
125+
with data.rule_data.allowed_rpm_build_dependency_sources as []
126+
}
127+
128+
# Test with custom rule_data
129+
test_custom_rule_data if {
130+
custom_locations := ["^https://custom\\.example\\.com/.*", "^https://archive\\.example\\.org/.*"]
131+
att := _sbom_attestation_with_download_location("https://custom.example.com/packages/foo.rpm")
132+
lib.assert_empty(rpm_build_deps.warn) with input.attestations as [att]
133+
with data.rule_data.allowed_rpm_build_dependency_sources as custom_locations
134+
}
135+
136+
# Test matches_any function - valid with exact match
137+
test_matches_any_exact_match if {
138+
rpm_build_deps.matches_any("NOASSERTION", ["NOASSERTION"])
139+
}
140+
141+
# Test matches_any function - valid with regex pattern
142+
test_matches_any_regex_pattern if {
143+
rpm_build_deps.matches_any(
144+
"https://download.devel.redhat.com/brewroot/repos/package.rpm",
145+
["^https://download\\.devel\\.redhat\\.com/brewroot/repos/.*"],
146+
)
147+
}
148+
149+
# Test matches_any function - invalid
150+
test_matches_any_invalid if {
151+
not rpm_build_deps.matches_any("https://untrusted.example.com/package.rpm", _mock_allowed_locations)
152+
}
153+
154+
# Test matches_any with multiple patterns
155+
test_matches_any_multiple_patterns if {
156+
patterns := [
157+
"^https://download\\.devel\\.redhat\\.com/.*",
158+
"^https://codeload\\.github\\.com/.*",
159+
]
160+
rpm_build_deps.matches_any("https://codeload.github.com/user/repo/tar.gz/v1.0", patterns)
161+
}
162+
163+
# Helper function to create SBOM attestation with specific download location
164+
_sbom_attestation_with_download_location(location) := {"statement": {
165+
"predicateType": "https://spdx.dev/Document",
166+
"predicate": {
167+
"spdxVersion": "SPDX-2.3",
168+
"documentNamespace": "https://example.dev/spdxdocs/example-123",
169+
"dataLicense": "CC0-1.0",
170+
"SPDXID": "SPDXRef-DOCUMENT",
171+
"name": "test-sbom",
172+
"creationInfo": {
173+
"created": "2024-01-01T00:00:00Z",
174+
"creators": ["Tool: test"],
175+
},
176+
"packages": [{
177+
"SPDXID": "SPDXRef-Package-test",
178+
"name": "test-package",
179+
"versionInfo": "1.0.0",
180+
"downloadLocation": location,
181+
}],
182+
},
183+
}}
184+
185+
# Helper function to create SBOM attestation with multiple packages
186+
_sbom_attestation_with_multiple_packages(locations) := {"statement": {
187+
"predicateType": "https://spdx.dev/Document",
188+
"predicate": {
189+
"spdxVersion": "SPDX-2.3",
190+
"documentNamespace": "https://example.dev/spdxdocs/example-456",
191+
"dataLicense": "CC0-1.0",
192+
"SPDXID": "SPDXRef-DOCUMENT",
193+
"name": "test-sbom-multi",
194+
"creationInfo": {
195+
"created": "2024-01-01T00:00:00Z",
196+
"creators": ["Tool: test"],
197+
},
198+
"packages": [pkg |
199+
some i, location in locations
200+
pkg := {
201+
"SPDXID": sprintf("SPDXRef-Package-%d", [i]),
202+
"name": sprintf("package-%d", [i]),
203+
"versionInfo": "1.0.0",
204+
"downloadLocation": location,
205+
}
206+
],
207+
},
208+
}}
209+
210+
# Mock rule data - allowed source locations for testing
211+
# These patterns represent common trusted sources for RPM build dependencies
212+
_mock_allowed_locations := [
213+
"^https://download\\.devel\\.redhat\\.com/brewroot/repos/.*",
214+
"^https://codeload\\.github\\.com/.*",
215+
"^https://files\\.pythonhosted\\.org/.*",
216+
"^https://repo\\.maven\\.apache\\.org/maven2/.*",
217+
]

0 commit comments

Comments
 (0)