-
Notifications
You must be signed in to change notification settings - Fork 53
feat: Maven repo allow-list with metadata-driven enforcement #1696
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+565
−0
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
34 changes: 34 additions & 0 deletions
34
antora/docs/modules/ROOT/pages/packages/release_maven_repos.adoc
This file contains hidden or 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,34 @@ | ||
| = 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. | ||
|
|
||
| *Solution*: The Maven artifact originates from an untrusted or unpermitted repository. To resolve this, ensure the dependency is sourced from a repository defined in the 'allowed_maven_repositories' list in your policy configuration. If the repository is internal, add its URL to the allowed list in rule_data. | ||
|
|
||
| * 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#L35[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#L17[Source, window="_blank"] |
This file contains hidden or 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 hidden or 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 hidden or 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,66 @@ | ||
| # METADATA | ||
| # title: Maven Package Extraction | ||
| # description: >- | ||
| # Extracts Maven packages and their repository URLs from both CycloneDX | ||
| # and SPDX SBOM formats. | ||
| package lib.sbom | ||
|
|
||
| import rego.v1 | ||
|
|
||
| maven_packages contains pkg if { | ||
| some pkg in _cyclonedx_maven_packages | ||
| } | ||
|
|
||
| maven_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 ensures that packages without explicit repository URLs | ||
| # are still processed. If the input repo_set is empty, it returns {""}. | ||
| # In the context of this policy, a blank repository URL is considered | ||
| # to be Maven Central (https://repo.maven.apache.org/maven2/). | ||
| _empty_to_default(repo_set) := repo_set if { | ||
| count(repo_set) > 0 | ||
| } else := {""} | ||
This file contains hidden or 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,134 @@ | ||
| package lib.sbom_test | ||
|
|
||
| import data.lib.assertions | ||
| import data.lib.sbom | ||
|
|
||
| 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/"}], | ||
| }] | ||
|
|
||
| expected := {{ | ||
| "name": "auth-lib", | ||
| "purl": "pkg:maven/org.example/auth@1.0", | ||
| "repository_url": "https://repo.maven.apache.org/maven2/", | ||
| }} | ||
|
csasalu marked this conversation as resolved.
|
||
|
|
||
| result := sbom.maven_packages with sbom.cyclonedx_sboms as [_cyclonedx_sbom(mock_components)] | ||
|
|
||
| assertions.assert_equal(expected, result) | ||
| } | ||
|
|
||
| test_cyclonedx_ignores_non_maven if { | ||
| mock_components := [{"name": "react", "purl": "pkg:npm/react@18.2.0"}] | ||
|
|
||
| assertions.assert_empty(sbom.maven_packages) with sbom.cyclonedx_sboms as [_cyclonedx_sbom(mock_components)] | ||
| } | ||
|
|
||
| test_cyclonedx_empty_repo_url if { | ||
| mock_components := [{ | ||
| "name": "no-repo", | ||
| "purl": "pkg:maven/org.example/no-repo@1.0", | ||
| "externalRefs": [], | ||
| }] | ||
|
|
||
| expected := {{ | ||
| "name": "no-repo", | ||
| "purl": "pkg:maven/org.example/no-repo@1.0", | ||
| "repository_url": "", | ||
| }} | ||
|
|
||
| result := sbom.maven_packages with sbom.cyclonedx_sboms as [_cyclonedx_sbom(mock_components)] | ||
|
|
||
| assertions.assert_equal(expected, result) | ||
| } | ||
|
|
||
| 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", | ||
| }], | ||
| }] | ||
|
|
||
| expected := {{ | ||
| "name": "data-service", | ||
| "purl": "pkg:maven/org.example/data@2.5", | ||
| "repository_url": "https://internal.jfrog.io/artifactory", | ||
| }} | ||
|
csasalu marked this conversation as resolved.
|
||
|
|
||
| result := sbom.maven_packages with sbom.spdx_sboms as [_spdx_sbom(mock_packages)] | ||
|
|
||
| assertions.assert_equal(expected, result) | ||
| } | ||
|
|
||
| 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", | ||
| }], | ||
| }] | ||
|
|
||
| expected := { | ||
| { | ||
| "name": "cdx-pkg", | ||
| "purl": "pkg:maven/cdx/pkg@1", | ||
| "repository_url": "url1", | ||
| }, | ||
| { | ||
| "name": "spdx-pkg", | ||
| "purl": "pkg:maven/spdx/pkg@1", | ||
| "repository_url": "url2", | ||
| }, | ||
| } | ||
|
|
||
| result := sbom.maven_packages with sbom.cyclonedx_sboms as [_cyclonedx_sbom(mock_cdx)] | ||
| with sbom.spdx_sboms as [_spdx_sbom(mock_spdx)] | ||
|
|
||
| assertions.assert_equal(expected, result) | ||
| } | ||
|
|
||
| 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"}, | ||
| ], | ||
| }] | ||
|
|
||
| expected := { | ||
| { | ||
| "name": "multi-repo-lib", | ||
| "purl": "pkg:maven/org.example/multi@1.0", | ||
| "repository_url": "https://repo-a.com", | ||
| }, | ||
| { | ||
| "name": "multi-repo-lib", | ||
| "purl": "pkg:maven/org.example/multi@1.0", | ||
| "repository_url": "https://repo-b.com", | ||
| }, | ||
| } | ||
|
|
||
| result := sbom.maven_packages with sbom.cyclonedx_sboms as [_cyclonedx_sbom(mock_components)] | ||
|
|
||
| assertions.assert_equal(expected, result) | ||
| } | ||
|
|
||
| _cyclonedx_sbom(components) := {"components": components} | ||
|
|
||
| _spdx_sbom(packages) := {"packages": packages} | ||
|
st3penta marked this conversation as resolved.
|
This file contains hidden or 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,8 @@ | ||
| # | ||
| # METADATA | ||
| # title: redhat_maven | ||
|
st3penta marked this conversation as resolved.
|
||
| # description: >- | ||
| # Ruleset for validating artifacts built via Red Hat Maven repositories. | ||
| package collection.redhat_maven | ||
|
|
||
| import rego.v1 | ||
|
csasalu marked this conversation as resolved.
|
||
This file contains hidden or 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,88 @@ | ||
| # 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. | ||
| package release.maven_repos | ||
|
|
||
| import rego.v1 | ||
|
|
||
| import data.lib | ||
| import data.lib.metadata | ||
| import data.lib.rule_data | ||
| 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: | ||
| # - redhat_maven | ||
| # - policy_data | ||
|
st3penta marked this conversation as resolved.
|
||
| 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. | ||
| # custom: | ||
|
csasalu marked this conversation as resolved.
|
||
| # short_name: deny_unpermitted_urls | ||
| # failure_msg: '%s' | ||
| # solution: >- | ||
| # The Maven artifact originates from an untrusted or unpermitted repository. | ||
| # To resolve this, ensure the dependency is sourced from a repository defined | ||
| # in the 'allowed_maven_repositories' list in your policy configuration. | ||
| # If the repository is internal, add its URL to the allowed list in rule_data. | ||
| # effective_on: 2026-05-10T00:00:00Z | ||
|
simonbaird marked this conversation as resolved.
|
||
| # collections: | ||
| # - redhat_maven | ||
| deny contains result if { | ||
| some err in _repo_url_errors | ||
| result := metadata.result_helper_with_term(rego.metadata.chain(), [err.msg], err.purl) | ||
| } | ||
|
|
||
| _repo_url_errors contains err if { | ||
| some pkg in sbom.maven_packages | ||
| source := _get_effective_url(pkg.repository_url) | ||
| not _url_is_permitted(source) | ||
| err := { | ||
| "purl": pkg.purl, | ||
| "msg": sprintf("Package %q (source: %q) is not in the permitted list", [pkg.purl, source]), | ||
| } | ||
| } | ||
|
csasalu marked this conversation as resolved.
|
||
|
|
||
| _get_effective_url(url) := url if { | ||
| url != "" | ||
| } else := "https://repo.maven.apache.org/maven2/" | ||
|
|
||
| _url_is_permitted(url) if { | ||
| permitted := rule_data.get("allowed_maven_repositories") | ||
| url in permitted | ||
| } | ||
|
|
||
| _rule_data_errors contains key if { | ||
| key := "allowed_maven_repositories" | ||
| data_list := rule_data.get(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 | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.