Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions antora/docs/modules/ROOT/pages/packages/release_maven_repos.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
= All maven artifacts have known repository URLs Package

Each Maven package listed in an SBOM must specify the repository URL that it comes from, and that URL must be present in the list of known and permitted Maven repositories. If no URL is specified, the package is assumed to come from Maven Central.

== Package Name

* `maven_repos`

== Rules Included

[#maven_repos__deny_unpermitted_urls]
=== link:#maven_repos__deny_unpermitted_urls[Known Repository URLs]

Each Maven package listed in an SBOM must specify the repository URL that it comes from, and that URL must be present in the list of known and permitted Maven repositories. If no URL is specified, the package is assumed to come from Maven Central.

* Rule type: [rule-type-indicator failure]#FAILURE#
* FAILURE message: `%s`
* Code: `maven_repos.deny_unpermitted_urls`
* Effective from: `2026-05-10T00:00:00Z`
* https://github.com/conforma/policy/blob/{page-origin-refhash}/policy/release/maven_repos/maven_repos.rego#L40[Source, window="_blank"]

[#maven_repos__policy_data_missing]
=== link:#maven_repos__policy_data_missing[Policy data validation]

Ensures the required allowed_maven_repositories list is provided.

*Solution*: Ensure that 'allowed_maven_repositories' is defined in the rule_data provided to the policy, and that it contains a list of authorized repository URLs.

* Rule type: [rule-type-indicator failure]#FAILURE#
* FAILURE message: `Policy data is missing the required "%s" list`
* Code: `maven_repos.policy_data_missing`
* https://github.com/conforma/policy/blob/{page-origin-refhash}/policy/release/maven_repos/maven_repos.rego#L22[Source, window="_blank"]
12 changes: 12 additions & 0 deletions antora/docs/modules/ROOT/pages/release_policy.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ a| Include policy rules responsible for validating rule data.

Rules included:

* xref:packages/release_maven_repos.adoc#maven_repos__policy_data_missing[All maven artifacts have known repository URLs: Policy data validation]
* xref:packages/release_attestation_type.adoc#attestation_type__known_attestation_types_provided[Attestation type: Known attestation types provided]
* xref:packages/release_base_image_registries.adoc#base_image_registries__allowed_registries_provided[Base image checks: Allowed base image registry prefixes list was provided]
* xref:packages/release_buildah_build_task.adoc#buildah_build_task__disallowed_platform_patterns_pattern[Buildah build task: disallowed_platform_patterns format]
Expand Down Expand Up @@ -103,6 +104,7 @@ a| Include the set of policy rules required for Red Hat products.

Rules included:

* xref:packages/release_maven_repos.adoc#maven_repos_package[All maven artifacts have known repository URLs: All maven artifacts have known repository URLs]
* xref:packages/release_attestation_type.adoc#attestation_type__deprecated_policy_attestation_format[Attestation type: Deprecated policy attestation format]
* xref:packages/release_attestation_type.adoc#attestation_type__known_attestation_type[Attestation type: Known attestation type found]
* xref:packages/release_attestation_type.adoc#attestation_type__known_attestation_types_provided[Attestation type: Known attestation types provided]
Expand Down Expand Up @@ -233,6 +235,13 @@ Rules included:
* xref:packages/release_rpm_ostree_task.adoc#rpm_ostree_task__builder_image_param[rpm-ostree Task: Builder image parameter]
* xref:packages/release_rpm_ostree_task.adoc#rpm_ostree_task__rule_data[rpm-ostree Task: Rule data]

| [#redhat_maven]`redhat_maven`
a| Ruleset for validating artifacts built via Red Hat Maven repositories.

Rules included:

* xref:packages/release_maven_repos.adoc#maven_repos_package[All maven artifacts have known repository URLs: All maven artifacts have known repository URLs]

| [#redhat_rpms]`redhat_rpms`
a| Include the set of policy rules required for building Red Hat RPMs.

Expand Down Expand Up @@ -336,6 +345,9 @@ Rules included:
|*Package Name*
|*Description*

| xref:packages/release_maven_repos.adoc[maven_repos]
a| Each Maven package listed in an SBOM must specify the repository URL that it comes from, and that URL must be present in the list of known and permitted Maven repositories. If no URL is specified, the package is assumed to come from Maven Central.

| xref:packages/release_attestation_type.adoc[attestation_type]
a| Sanity checks related to the format of the image build's attestation.

Expand Down
4 changes: 4 additions & 0 deletions antora/docs/modules/ROOT/partials/release_policy_nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@
*** xref:release_policy.adoc#minimal[minimal]
*** xref:release_policy.adoc#policy_data[policy_data]
*** xref:release_policy.adoc#redhat[redhat]
*** xref:release_policy.adoc#redhat_maven[redhat_maven]
*** xref:release_policy.adoc#redhat_rpms[redhat_rpms]
*** xref:release_policy.adoc#rhtap-multi-ci[rhtap-multi-ci]
*** xref:release_policy.adoc#slsa3[slsa3]
** Release Rules
*** xref:packages/release_maven_repos.adoc[All maven artifacts have known repository URLs]
**** xref:packages/release_maven_repos.adoc#maven_repos__deny_unpermitted_urls[Known Repository URLs]
**** xref:packages/release_maven_repos.adoc#maven_repos__policy_data_missing[Policy data validation]
*** xref:packages/release_attestation_type.adoc[Attestation type]
**** xref:packages/release_attestation_type.adoc#attestation_type__deprecated_policy_attestation_format[Deprecated policy attestation format]
**** xref:packages/release_attestation_type.adoc#attestation_type__known_attestation_type[Known attestation type found]
Expand Down
64 changes: 64 additions & 0 deletions policy/lib/sbom/maven.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# METADATA
# title: Maven Package Extraction
# description: >-
# Extracts Maven packages and their repository URLs from both CycloneDX
# and SPDX SBOM formats.
package lib.sbom

import future.keywords.contains
import future.keywords.if
import future.keywords.in

packages contains pkg if {
some pkg in _cyclonedx_maven_packages
}

packages contains pkg if {
some pkg in _spdx_maven_packages
}

_cyclonedx_maven_packages contains pkg if {
some s in cyclonedx_sboms
some component in s.components

startswith(component.purl, "pkg:maven/")

repos := {ref.url |
some ref in component.externalRefs
ref.type in ["distribution", "artifact-repository"]
}

final_repos := _empty_to_default(repos)

some repo_url in final_repos
pkg := {
"purl": component.purl,
"name": component.name,
"repository_url": repo_url,
}
}

_spdx_maven_packages contains pkg if {
some s in spdx_sboms
some item in s.packages

startswith(item.purl, "pkg:maven/")

repos := {ref.referenceLocator |
some ref in item.externalRefs
ref.referenceType in ["distribution", "repository"]
}

final_repos := _empty_to_default(repos)

some repo_url in final_repos
pkg := {
"purl": item.purl,
"name": item.name,
"repository_url": repo_url,
}
}

_empty_to_default(repo_set) := repo_set if {
count(repo_set) > 0
} else := {""}
104 changes: 104 additions & 0 deletions policy/lib/sbom/maven_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package lib.sbom_test

import data.lib.sbom
import future.keywords.if
import future.keywords.in

test_cyclonedx_maven_extraction if {
mock_components := [{
"name": "auth-lib",
"purl": "pkg:maven/org.example/auth@1.0",
"externalRefs": [{"type": "distribution", "url": "https://repo.maven.apache.org/maven2/"}],
}]

res := sbom.packages with sbom.cyclonedx_sboms as [_cyclonedx_sbom(mock_components)]

res == {{
"name": "auth-lib",
"purl": "pkg:maven/org.example/auth@1.0",
"repository_url": "https://repo.maven.apache.org/maven2/",
}}
}

test_cyclonedx_ignores_non_maven if {
mock_components := [{"name": "react", "purl": "pkg:npm/react@18.2.0"}]

res := sbom.packages with sbom.cyclonedx_sboms as [_cyclonedx_sbom(mock_components)]

count(res) == 0
}

test_cyclonedx_empty_repo_url if {
mock_components := [{
"name": "no-repo",
"purl": "pkg:maven/org.example/no-repo@1.0",
"externalRefs": [],
}]

res := sbom.packages with sbom.cyclonedx_sboms as [_cyclonedx_sbom(mock_components)]

some pkg in res
pkg.repository_url == ""
}

test_spdx_maven_extraction if {
mock_packages := [{
"name": "data-service",
"purl": "pkg:maven/org.example/data@2.5",
"externalRefs": [{
"referenceType": "repository",
"referenceLocator": "https://internal.jfrog.io/artifactory",
}],
}]

res := sbom.packages with sbom.spdx_sboms as [_spdx_sbom(mock_packages)]

res == {{
"name": "data-service",
"purl": "pkg:maven/org.example/data@2.5",
"repository_url": "https://internal.jfrog.io/artifactory",
}}
}

test_combined_sources if {
mock_cdx := [{
"name": "cdx-pkg",
"purl": "pkg:maven/cdx/pkg@1",
"externalRefs": [{"type": "distribution", "url": "url1"}],
}]

mock_spdx := [{
"name": "spdx-pkg",
"purl": "pkg:maven/spdx/pkg@1",
"externalRefs": [{
"referenceType": "repository",
"referenceLocator": "url2",
}],
}]

res := sbom.packages with sbom.cyclonedx_sboms as [_cyclonedx_sbom(mock_cdx)]
with sbom.spdx_sboms as [_spdx_sbom(mock_spdx)]

count(res) == 2
}

test_cyclonedx_multiple_repo_capture if {
mock_components := [{
"name": "multi-repo-lib",
"purl": "pkg:maven/org.example/multi@1.0",
"externalRefs": [
{"type": "distribution", "url": "https://repo-a.com"},
{"type": "artifact-repository", "url": "https://repo-b.com"},
],
}]

pkg_list := sbom.packages with sbom.cyclonedx_sboms as [_cyclonedx_sbom(mock_components)]

count(pkg_list) == 2
urls := {p.repository_url | some p in pkg_list}
urls == {"https://repo-a.com", "https://repo-b.com"}
}

_cyclonedx_sbom(components) := {"components": components}

_spdx_sbom(packages) := {"packages": packages}
8 changes: 8 additions & 0 deletions policy/release/collection/redhat_maven/redhat_maven.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#
# METADATA
# title: redhat_maven
# description: >-
# Ruleset for validating artifacts built via Red Hat Maven repositories.
package collection.redhat_maven

import rego.v1
85 changes: 85 additions & 0 deletions policy/release/maven_repos/maven_repos.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# METADATA
# title: All maven artifacts have known repository URLs
# description: >-
# Each Maven package listed in an SBOM must specify the repository URL that it
# comes from, and that URL must be present in the list of known and permitted
# Maven repositories. If no URL is specified, the package is assumed to come
# from Maven Central.
# custom:
# collections:
# - redhat
# - redhat_maven
#
package release.maven_repos

import future.keywords.contains
import future.keywords.if
import future.keywords.in

import data.lib
import data.lib.sbom

# METADATA
# title: Policy data validation
# description: Ensures the required allowed_maven_repositories list is provided.
# custom:
# short_name: policy_data_missing
# failure_msg: Policy data is missing the required "%s" list
# solution: >-
# Ensure that 'allowed_maven_repositories' is defined in the rule_data
# provided to the policy, and that it contains a list of authorized
# repository URLs.
# collections:
# - policy_data
# severity: failure
deny contains result if {
some key in _rule_data_errors
result := lib.result_helper(rego.metadata.chain(), [key])
}

# METADATA
# title: Known Repository URLs
# description: >-
# Each Maven package listed in an SBOM must specify the repository URL that it
# comes from, and that URL must be present in the list of known and permitted
# Maven repositories. If no URL is specified, the package is assumed to come
# from Maven Central.
# scope: rule
# custom:
# short_name: deny_unpermitted_urls
# failure_msg: '%s'
# effective_on: 2026-05-10T00:00:00Z
deny contains result if {
some purl, msg in _repo_url_errors
base := lib.result_helper(rego.metadata.chain(), [msg])
result := object.union(base, {"term": purl})
}

_repo_url_errors[pkg.purl] := msg if {
some pkg in sbom.packages
source := _get_effective_url(pkg.repository_url)
not _url_is_permitted(source)
msg := sprintf("Package %q (source: %q) is not in the permitted list", [pkg.purl, source])
}

_get_effective_url(url) := url if {
url != ""
} else := "https://repo.maven.apache.org/maven2/"

_url_is_permitted(url) if {
permitted := lib.rule_data("allowed_maven_repositories")
url in permitted
}

_rule_data_errors contains key if {
key := "allowed_maven_repositories"
data_list := lib.rule_data(key)
_is_invalid_data(data_list)
}

_is_invalid_data(val) if not is_array(val)

_is_invalid_data(val) if {
is_array(val)
count(val) == 0
}
Loading
Loading