You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tooling.apache.org by ar...@apache.org on 2026/09/02 09:00:10 UTC
(tooling-trusted-releases) branch arm updated (9e848e09 -> 1839e8a1)
This is an automated email from the ASF dual-hosted git repository.
alitheg pushed a change to branch arm
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
discard 9e848e09 #1544 - fix classifier-style SBOM matching
add 4aa2f528 Paginate checks and release paths in the API
add 0b6b4fee Allow standard routes to have query parameters
add b9f9c0e0 Paginate a page and API endpoint listing releases
new 1839e8a1 #1544 - fix classifier-style SBOM matching
This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version. This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:
* -- * -- B -- O -- O -- O (9e848e09)
\
N -- N -- N refs/heads/arm (1839e8a1)
You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.
Any revisions marked "omit" are not gone; other references still
refer to them. Any revisions marked "discard" are gone forever.
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
atr/admin/__init__.py | 42 +---
atr/api/__init__.py | 37 +++-
atr/blueprints/common.py | 4 +-
atr/blueprints/get.py | 6 +-
atr/blueprints/post.py | 2 +-
atr/db/interaction.py | 1 +
atr/get/release.py | 31 ++-
atr/models/api.py | 21 ++
atr/templates/releases-finished.html | 36 +++-
atr/web.py | 33 ++-
tests/unit/test_api_list_pagination.py | 234 +++++++++++++++++++++
tests/unit/test_blueprints.py | 31 ++-
tests/unit/test_interaction_check_results.py | 13 +-
..._admin_data_browser.py => test_web_page_nav.py} | 18 +-
14 files changed, 434 insertions(+), 75 deletions(-)
create mode 100644 tests/unit/test_api_list_pagination.py
rename tests/unit/{test_admin_data_browser.py => test_web_page_nav.py} (63%)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org
(tooling-trusted-releases) 01/01: #1544 - fix classifier-style SBOM matching
Posted by ar...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
alitheg pushed a commit to branch arm
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
commit 1839e8a17254aaa0c74cd9fd30a6d747661a7417
Author: Alastair McFarlane <ar...@apache.org>
AuthorDate: Wed Sep 2 09:59:33 2026 +0100
#1544 - fix classifier-style SBOM matching
---
atr/analysis.py | 24 +++++++++++++++++++++++
atr/tasks/checks/paths.py | 10 ++++------
tests/unit/test_sbom_candidates.py | 39 ++++++++++++++++++++++++++++++++++++++
3 files changed, 67 insertions(+), 6 deletions(-)
diff --git a/atr/analysis.py b/atr/analysis.py
index 464afb21..42f4f7ef 100755
--- a/atr/analysis.py
+++ b/atr/analysis.py
@@ -488,9 +488,23 @@ def sbom_candidates(name: str, suffixes: tuple[str, ...]) -> list[str]:
candidates = [name + suffix for suffix in suffixes]
if (stem := artifact_stem(name)) is not None:
candidates.extend(stem + suffix for suffix in suffixes)
+ # Where the artifact carries a Maven classifier, e.g. the source-release in
+ # atr-maven-plugin-1.0.0-source-release.zip, the SBOM tooling names its output off the
+ # version alone, dropping the classifier - so also try the stem with the classifier removed
+ declassified = _classifier_removed(name)
+ if (declassified != name) and ((declassified_stem := artifact_stem(declassified)) is not None):
+ candidates.extend(declassified_stem + suffix for suffix in suffixes)
return candidates
+def sbom_pairs_artifact(sbom_name: str, artifact_name: str, suffixes: tuple[str, ...]) -> bool:
+ # Whether sbom_name is the SBOM belonging to artifact_name, i.e. the artifact's own hunt for its
+ # SBOM would turn up exactly this name. Both directions - an artifact looking for its SBOM and an
+ # SBOM looking for its artifact - go through sbom_candidates, so the naming rule lives in one
+ # place and the two can't drift apart
+ return sbom_name in sbom_candidates(artifact_name, suffixes)
+
+
def substitutions_format(substitutions: dict[str, list[str]]) -> str:
subs = []
for key, values in substitutions.items():
@@ -514,5 +528,15 @@ def version_parse(version: str, elements: dict[str, str | None]) -> str:
return version
+def _classifier_removed(name: str) -> str:
+ # A Maven classifier sits between the version and the extension, e.g. the source-release in
+ # apache-example-1.0-source-release.zip. Strip it, but only where it abuts the artifact
+ # extension, so a source or bin appearing elsewhere in the name is left alone. The extension
+ # must still be attached for this to work, as variant_pattern wants a trailing separator and
+ # the extension's dot provides it
+ pattern = r"[_-](?:" + "|".join(VARIANT_PATTERNS) + r")(?=" + extension_pattern() + r")"
+ return re.sub(pattern, "", name, count=1)
+
+
if __name__ == "__main__":
main()
diff --git a/atr/tasks/checks/paths.py b/atr/tasks/checks/paths.py
index 3382aedc..5306dd37 100644
--- a/atr/tasks/checks/paths.py
+++ b/atr/tasks/checks/paths.py
@@ -269,13 +269,11 @@ async def _check_metadata_rules(
# Check whether the corresponding artifact exists.
artifact_path_base = str(relative_path).removesuffix(ext_metadata)
if is_standalone:
+ # An SBOM pairs with any artifact whose own search would generate this SBOM name, which
+ # covers the whole-name, stem, and dropped-classifier styles in one place
+ sbom_name = str(relative_path)
has_artifact = any(
- analysis.is_artifact(p)
- and (
- (p == artifact_path_base)
- or p.startswith(artifact_path_base + ".") # non-maven, suffixed-style
- or p.startswith(artifact_path_base + "-") # maven, classifier-style
- )
+ analysis.is_artifact(p) and analysis.sbom_pairs_artifact(sbom_name, p, analysis.SBOM_SUFFIXES)
for p in relative_paths
)
if not has_artifact:
diff --git a/tests/unit/test_sbom_candidates.py b/tests/unit/test_sbom_candidates.py
index 4bfbe3d2..be997e19 100644
--- a/tests/unit/test_sbom_candidates.py
+++ b/tests/unit/test_sbom_candidates.py
@@ -47,3 +47,42 @@ def test_sbom_candidates() -> None:
assert "apache-example-1.0-cyclonedx.xml" in analysis.sbom_candidates(
"apache-example-1.0.jar", analysis.SBOM_SUFFIXES
)
+
+
+def test_sbom_candidates_maven_classifier() -> None:
+ # The CycloneDX Maven plugin names its output off the version alone, dropping the artifact's
+ # own classifier, so a classified artifact still has to reach the declassified SBOM name
+ candidates = analysis.sbom_candidates(
+ "atr-maven-plugin-1.0.0-beta-2-SNAPSHOT-source-release.zip", analysis.CYCLONEDX_JSON_SUFFIXES
+ )
+ assert "atr-maven-plugin-1.0.0-beta-2-SNAPSHOT-cyclonedx.json" in candidates
+
+
+def test_sbom_pairs_artifact() -> None:
+ # The inverse of sbom_candidates: an SBOM pairs with an artifact when it is one of the names that
+ # artifact would generate, so the whole-name, stem, and dropped-classifier styles all pair
+ assert analysis.sbom_pairs_artifact(
+ "apache-example-1.0.tar.gz.cdx.json", "apache-example-1.0.tar.gz", analysis.SBOM_SUFFIXES
+ )
+ assert analysis.sbom_pairs_artifact(
+ "apache-example-1.0-cyclonedx.json", "apache-example-1.0.jar", analysis.SBOM_SUFFIXES
+ )
+ assert analysis.sbom_pairs_artifact(
+ "atr-maven-plugin-1.0.0-beta-2-SNAPSHOT-cyclonedx.json",
+ "atr-maven-plugin-1.0.0-beta-2-SNAPSHOT-source-release.zip",
+ analysis.SBOM_SUFFIXES,
+ )
+ # An SBOM does not pair with an unrelated artifact
+ assert not analysis.sbom_pairs_artifact(
+ "apache-example-1.0-cyclonedx.json", "apache-other-2.0.jar", analysis.SBOM_SUFFIXES
+ )
+
+
+def test_classifier_removed() -> None:
+ # A classifier abutting the extension comes off, along with its leading separator
+ assert analysis._classifier_removed("apache-example-1.0-source-release.zip") == "apache-example-1.0.zip"
+ assert analysis._classifier_removed("apache-example-1.0-bin.tar.gz") == "apache-example-1.0.tar.gz"
+ # A name with no classifier is returned untouched, so callers can tell nothing was stripped
+ assert analysis._classifier_removed("apache-example-1.0.jar") == "apache-example-1.0.jar"
+ # A variant word elsewhere in the name is not a classifier, so it stays put
+ assert analysis._classifier_removed("apache-source-tool-1.0.tar.gz") == "apache-source-tool-1.0.tar.gz"
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org