Skip to content
Merged
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
2 changes: 1 addition & 1 deletion relenv/build/darwin.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def build_python(env: MutableMapping[str, str], dirs: Dirs, logfp: IO[str]) -> N
xz_checksum = xz_info["sha256"]
else:
xz_version = "5.8.1"
xz_url = "http://tukaani.org/xz/xz-{version}.tar.gz"
xz_url = "https://github.com/tukaani-project/xz/releases/download/v{version}/xz-{version}.tar.gz"
xz_checksum = "ed4d5589c4cfe84e1697bd02a9954b76af336931"

build.add(
Expand Down
2 changes: 1 addition & 1 deletion relenv/build/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ def build_python(env: EnvMapping, dirs: Dirs, logfp: IO[str]) -> None:
else:
# Fallback to hardcoded values
xz_version = "5.8.1"
xz_url = "http://tukaani.org/xz/xz-{version}.tar.gz"
xz_url = "https://github.com/tukaani-project/xz/releases/download/v{version}/xz-{version}.tar.gz"
xz_checksum = "ed4d5589c4cfe84e1697bd02a9954b76af336931"

build.add(
Expand Down
4 changes: 2 additions & 2 deletions relenv/python-versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@
},
"xz": {
"5.8.2": {
"url": "http://tukaani.org/xz/xz-{version}.tar.gz",
"url": "https://github.com/tukaani-project/xz/releases/download/v{version}/xz-{version}.tar.gz",
"sha256": "ce09c50a5962786b83e5da389c90dd2c15ecd0980a258dd01f70f9e7ce58a8f1",
"platforms": [
"linux",
Expand All @@ -376,7 +376,7 @@
]
},
"5.8.3": {
"url": "http://tukaani.org/xz/xz-{version}.tar.gz",
"url": "https://github.com/tukaani-project/xz/releases/download/v{version}/xz-{version}.tar.gz",
"sha256": "3d3a1b973af218114f4f889bbaa2f4c037deaae0c8e815eec381c3d546b974a0",
"platforms": [
"linux",
Expand Down
40 changes: 30 additions & 10 deletions relenv/pyversions.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,16 +331,36 @@ def detect_sqlite_versions() -> list[tuple[str, str]]:

def detect_xz_versions() -> list[str]:
"""
Detect available XZ versions from tukaani.org.
Detect available XZ versions from the tukaani-project GitHub releases API.

Sourcing xz version metadata from tukaani.org is discouraged after
CVE-2024-3094 (the March 2024 xz-utils supply-chain backdoor). Both
release tarball hosting and the authoritative release listing moved
to https://github.com/tukaani-project/xz, so we consult that project's
Releases API and skip drafts / prereleases.
"""
url = "https://tukaani.org/xz/"
url = "https://api.github.com/repos/tukaani-project/xz/releases"
content = fetch_url_content(url)
# Find xz-X.Y.Z.tar.gz
pattern = r"xz-(\d+\.\d+\.\d+)\.tar\.gz"
matches = re.findall(pattern, content)
# Deduplicate and sort
versions = sorted(set(matches), key=lambda v: [int(x) for x in v.split(".")], reverse=True)
return versions
try:
releases = json.loads(content)
except json.JSONDecodeError:
return []
versions: list[str] = []
for release in releases:
if not isinstance(release, dict):
continue
if release.get("draft") or release.get("prerelease"):
continue
tag = release.get("tag_name", "")
if not isinstance(tag, str):
continue
# Tags are like "v5.8.4"; accept plain "5.8.4" too for robustness.
if tag.startswith("v"):
tag = tag[1:]
if not re.fullmatch(r"\d+\.\d+\.\d+", tag):
continue
versions.append(tag)
return sorted(set(versions), key=lambda v: [int(x) for x in v.split(".")], reverse=True)


def detect_libffi_versions() -> list[str]:
Expand Down Expand Up @@ -691,13 +711,13 @@ def update_dependency_versions(path: pathlib.Path, deps_to_update: list[str] | N
if "xz" not in dependencies:
dependencies["xz"] = {}
if latest not in dependencies["xz"]:
url = f"http://tukaani.org/xz/xz-{latest}.tar.gz"
url = f"https://github.com/tukaani-project/xz/releases/download/v{latest}/xz-{latest}.tar.gz"
print(f"Downloading {url}...")
download_path = download_url(url, cwd)
checksum = sha256_digest(download_path)
print(f"SHA-256: {checksum}")
dependencies["xz"][latest] = {
"url": "http://tukaani.org/xz/xz-{version}.tar.gz",
"url": "https://github.com/tukaani-project/xz/releases/download/v{version}/xz-{version}.tar.gz",
"sha256": checksum,
"platforms": ["linux", "darwin", "win32"],
}
Expand Down
29 changes: 20 additions & 9 deletions tests/test_pyversions_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,24 +170,35 @@ def fake_fetch(url: str) -> str:


def test_detect_xz_versions(monkeypatch: pytest.MonkeyPatch) -> None:
"""Test XZ version detection from tukaani.org."""
mock_html = """
<html>
<a href="xz-5.8.1.tar.gz">xz-5.8.1.tar.gz</a>
<a href="xz-5.8.0.tar.gz">xz-5.8.0.tar.gz</a>
<a href="xz-5.6.3.tar.gz">xz-5.6.3.tar.gz</a>
</html>
"""
"""Test XZ version detection from the tukaani-project GitHub releases API."""
import json

mock_releases = json.dumps(
[
{"tag_name": "v5.8.1", "draft": False, "prerelease": False},
{"tag_name": "v5.7.2beta", "draft": False, "prerelease": True},
{"tag_name": "v5.8.0", "draft": False, "prerelease": False},
{"tag_name": "v5.6.3", "draft": False, "prerelease": False},
{"tag_name": "v5.9.0-draft", "draft": True, "prerelease": False},
]
)

captured_url: dict[str, str] = {}

def fake_fetch(url: str) -> str:
return mock_html
captured_url["url"] = url
return mock_releases

monkeypatch.setattr(pyversions, "fetch_url_content", fake_fetch)
versions = pyversions.detect_xz_versions()
assert captured_url["url"] == "https://api.github.com/repos/tukaani-project/xz/releases"
assert isinstance(versions, list)
assert "5.8.1" in versions
assert "5.8.0" in versions
assert "5.6.3" in versions
# Draft and prerelease tags must be skipped
assert "5.7.2beta" not in versions
assert not any(v.startswith("5.9") for v in versions)
# Verify sorting (latest first)
assert versions[0] == "5.8.1"

Expand Down
Loading