This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch sbp
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
The following commit(s) were added to refs/heads/sbp by this push:
new fb9bf68 Clone source from GitHub in the task to compare source trees
fb9bf68 is described below
commit fb9bf68961d5df8ba5b8be1291256eae1a0e1524
Author: Sean B. Palmer <[email protected]>
AuthorDate: Wed Feb 4 18:32:01 2026 +0000
Clone source from GitHub in the task to compare source trees
---
atr/tasks/checks/compare.py | 50 +++++++++++++++++++++++++++++++++++++++++++++
pyproject.toml | 1 +
uv.lock | 23 ++++++++++++++++++++-
3 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/atr/tasks/checks/compare.py b/atr/tasks/checks/compare.py
index 52f8d1b..ac27392 100644
--- a/atr/tasks/checks/compare.py
+++ b/atr/tasks/checks/compare.py
@@ -15,11 +15,16 @@
# specific language governing permissions and limitations
# under the License.
+import asyncio
import json
+import pathlib
+import secrets
+import shutil
from typing import Any
import aiofiles
import aiofiles.os
+import dulwich.porcelain as porcelain
import pydantic
import atr.attestable as attestable
@@ -27,6 +32,7 @@ import atr.log as log
import atr.models.results as results
import atr.sbom.models.github as github_models
import atr.tasks.checks as checks
+import atr.util as util
async def source_trees(args: checks.FunctionArguments) -> results.Results |
None:
@@ -43,6 +49,9 @@ async def source_trees(args: checks.FunctionArguments) ->
results.Results | None
return None
payload = await _load_tp_payload(args.project_name, args.version_name,
args.revision_number)
+ checkout_dir: str | None = None
+ if payload is not None:
+ checkout_dir = await _checkout_github_source(payload)
payload_summary = _payload_summary(payload)
log.info(
"Ran compare.source_trees successfully",
@@ -51,10 +60,45 @@ async def source_trees(args: checks.FunctionArguments) ->
results.Results | None
revision=args.revision_number,
path=args.primary_rel_path,
github_payload=payload_summary,
+ github_checkout=checkout_dir,
)
return None
+async def _checkout_github_source(payload:
github_models.TrustedPublisherPayload) -> str | None:
+ tmp_dir = util.get_tmp_dir()
+ await aiofiles.os.makedirs(tmp_dir, exist_ok=True)
+ checkout_dir = tmp_dir / f"github-{secrets.token_hex(12)}"
+ repo_url = f"https://github.com/{payload.repository}.git"
+ branch = _ref_to_branch(payload.ref)
+ try:
+ await asyncio.to_thread(_clone_repo, repo_url, payload.sha, branch,
checkout_dir)
+ except Exception as exc:
+ log.warning(f"Failed to clone GitHub repo for compare.source_trees:
{exc}")
+ return None
+ return str(checkout_dir)
+
+
+def _clone_repo(repo_url: str, sha: str, branch: str | None, checkout_dir:
pathlib.Path) -> None:
+ branch_ref: str | None = None
+ if branch is not None:
+ branch_ref = f"refs/heads/{branch}"
+ repo = porcelain.clone(
+ repo_url,
+ str(checkout_dir),
+ checkout=True,
+ depth=1,
+ branch=branch_ref,
+ )
+ try:
+ porcelain.reset(repo, "hard", sha)
+ except (KeyError, ValueError) as exc:
+ raise RuntimeError(f"Commit {sha} not found in shallow clone") from exc
+ git_dir = pathlib.Path(repo.path)
+ if git_dir.exists():
+ shutil.rmtree(git_dir)
+
+
async def _load_tp_payload(
project_name: str, version_name: str, revision_number: str
) -> github_models.TrustedPublisherPayload | None:
@@ -88,3 +132,9 @@ def _payload_summary(payload:
github_models.TrustedPublisherPayload | None) -> d
"actor": payload.actor,
"actor_id": payload.actor_id,
}
+
+
+def _ref_to_branch(ref: str) -> str | None:
+ if ref.startswith("refs/heads/"):
+ return ref.removeprefix("refs/heads/")
+ return None
diff --git a/pyproject.toml b/pyproject.toml
index 3148339..8ff5474 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -26,6 +26,7 @@ dependencies = [
"cyclonedx-python-lib[json-validation]>=11.0.0",
# "dkimpy @ git+https://github.com/sbp/dkimpy.git@main",
"dnspython>=2.7.0,<3.0.0",
+ "dulwich>=1.0.0",
"dunamai>=1.23.0",
"email-validator~=2.2.0",
"gitignore-parser (>=0.1.12,<0.2.0)",
diff --git a/uv.lock b/uv.lock
index 7cfd9dc..210c5c7 100644
--- a/uv.lock
+++ b/uv.lock
@@ -3,7 +3,7 @@ revision = 3
requires-python = "==3.13.*"
[options]
-exclude-newer = "2026-02-04T16:49:21Z"
+exclude-newer = "2026-02-04T17:11:34Z"
[[package]]
name = "aiofiles"
@@ -517,6 +517,25 @@ wheels = [
{ url =
"https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl",
hash =
"sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size
= 331094, upload-time = "2025-09-07T18:57:58.071Z" },
]
+[[package]]
+name = "dulwich"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "urllib3" },
+]
+sdist = { url =
"https://files.pythonhosted.org/packages/ee/df/4178b6465e118e6e74fd78774b451953dd53c09fdec18f2c4b3319dd0485/dulwich-1.0.0.tar.gz",
hash =
"sha256:3d07104735525f22bfec35514ac611cf328c89b7acb059316a4f6e583c8f09bc", size
= 1135862, upload-time = "2026-01-17T23:44:16.357Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/97/82/5ce63c7a2ac8d756bc7477298633e420632eed97ea645ecea13210e9b1a7/dulwich-1.0.0-cp313-cp313-android_21_arm64_v8a.whl",
hash =
"sha256:ff94f47f0b5787d4e6a0105daf51ff9cdb4e5b9d4e9f8dd01b58ba9a5b79bbd9", size
= 1417766, upload-time = "2026-01-17T23:43:57.855Z" },
+ { url =
"https://files.pythonhosted.org/packages/b9/71/7d4ecdf9e0da21ceec3ac05b03c2cac8cf2271a52172fd55dd65a9faa9e7/dulwich-1.0.0-cp313-cp313-android_21_x86_64.whl",
hash =
"sha256:1d95663441c930631d9d1765dc4f427dcc0662af45f42a0831357e60055ddb84", size
= 1417760, upload-time = "2026-01-17T23:43:59.42Z" },
+ { url =
"https://files.pythonhosted.org/packages/09/3d/0486cefda75c7e9ea8d8dbdeaa014d618e694bc75734f073927135b37a4b/dulwich-1.0.0-cp313-cp313-macosx_11_0_arm64.whl",
hash =
"sha256:78542a62fabea894943a1d01c9c477a56eee5f7d58d3bdee42c7e0622ddf6893", size
= 1316186, upload-time = "2026-01-17T23:44:01.334Z" },
+ { url =
"https://files.pythonhosted.org/packages/f7/a7/a24c6e1e9f7e5a2ee8f9e362e2c3e5d864cc2b69f04d02bedf82673f31c3/dulwich-1.0.0-cp313-cp313-manylinux_2_28_aarch64.whl",
hash =
"sha256:d1c33f6456e4335dfe6f4d3917fa7d77050d6470bbbaf8054b5c5084ee8e8cd1", size
= 1392530, upload-time = "2026-01-17T23:44:03.655Z" },
+ { url =
"https://files.pythonhosted.org/packages/d4/03/1ff9dbda655fc714528786e3fdbbe16278bbefc02b9836e91a38620aa616/dulwich-1.0.0-cp313-cp313-manylinux_2_28_x86_64.whl",
hash =
"sha256:581330cf799577f194fda2b5384b7ba50e095de7ff088779c027a6de63642de2", size
= 1420386, upload-time = "2026-01-17T23:44:05.844Z" },
+ { url =
"https://files.pythonhosted.org/packages/f0/ca/72e7cdde2ee0a4f858166ba8eb81a0d89f61762d9114bd7a358798892fc9/dulwich-1.0.0-cp313-cp313-win32.whl",
hash =
"sha256:276ff18ae734fe4a1be66d4267216a51d2deab0ac981d722db3d32fcc2ac4ff8", size
= 981425, upload-time = "2026-01-17T23:44:07.373Z" },
+ { url =
"https://files.pythonhosted.org/packages/d7/27/8d4bed76ce983052e259da25255fed85b48ad30a34b4e4b7c8f518fdbc30/dulwich-1.0.0-cp313-cp313-win_amd64.whl",
hash =
"sha256:cc0ab4ba7fd8617bebe20294dedaa8f713d1767ce059bfbefd971b911b702726", size
= 998055, upload-time = "2026-01-17T23:44:08.908Z" },
+ { url =
"https://files.pythonhosted.org/packages/f9/99/4543953d2f7c1a940c1373362a70d253b85860be64b4ef8885bf8bfb340b/dulwich-1.0.0-py3-none-any.whl",
hash =
"sha256:221be803b71b060c928e9faae4ab3e259ff5beac6e0c251ba3c176b51b5c2ffb", size
= 647950, upload-time = "2026-01-17T23:44:14.449Z" },
+]
+
[[package]]
name = "dunamai"
version = "1.25.0"
@@ -1874,6 +1893,7 @@ dependencies = [
{ name = "cvss" },
{ name = "cyclonedx-python-lib", extra = ["json-validation"] },
{ name = "dnspython" },
+ { name = "dulwich" },
{ name = "dunamai" },
{ name = "email-validator" },
{ name = "gitignore-parser" },
@@ -1937,6 +1957,7 @@ requires-dist = [
{ name = "cvss", specifier = "~=3.6" },
{ name = "cyclonedx-python-lib", extras = ["json-validation"], specifier =
">=11.0.0" },
{ name = "dnspython", specifier = ">=2.7.0,<3.0.0" },
+ { name = "dulwich", specifier = ">=1.0.0" },
{ name = "dunamai", specifier = ">=1.23.0" },
{ name = "email-validator", specifier = "~=2.2.0" },
{ name = "gitignore-parser", specifier = ">=0.1.12,<0.2.0" },
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]