Files
MyGoNavi/tools/validate-driver-release-assets.test.py
Syngnat 84d6007be9 ️ perf(driver/release): 优化驱动镜像下载与发布链路
- 将各平台驱动拆分为独立 ZIP,并为 DuckDB 同包携带运行库
- 仅生成 ZIP 下载候选,按 Gatewaysentry 与 GitHub 短测速结果调整优先级
- 扩展发布索引的归档摘要与条目元数据,强化跨平台资产校验
- 禁止裸驱动与 CI 总包进入 VPS 镜像,并校验载荷摘要和索引一致性
- 显式控制驱动镜像发布,自动清理失败暂存、过期目录和旧版本
2026-07-23 16:10:08 +08:00

1083 lines
40 KiB
Python

#!/usr/bin/env python3
import contextlib
import hashlib
import importlib.util
import io
import json
import pathlib
import sys
import tempfile
import unittest
import zipfile
MODULE_PATH = pathlib.Path(__file__).with_name("validate-driver-release-assets.py")
SPEC = importlib.util.spec_from_file_location("validate_driver_release_assets", MODULE_PATH)
MODULE = importlib.util.module_from_spec(SPEC)
assert SPEC.loader is not None
SPEC.loader.exec_module(MODULE)
class ValidateDriverReleaseAssetsTests(unittest.TestCase):
def test_infer_asset_path(self):
self.assertEqual(
MODULE.infer_asset_path("clickhouse-driver-agent-darwin-arm64"),
"MacOS/clickhouse-driver-agent-darwin-arm64",
)
self.assertEqual(
MODULE.infer_asset_path("clickhouse-driver-agent-windows-arm64.exe"),
"Windows/clickhouse-driver-agent-windows-arm64.exe",
)
self.assertEqual(
MODULE.infer_asset_path("mongodb-driver-agent-v1-windows-amd64.exe"),
"Windows/mongodb-driver-agent-v1-windows-amd64.exe",
)
self.assertEqual(
MODULE.infer_asset_path("mongodb-driver-agent-v2-darwin-arm64"),
"MacOS/mongodb-driver-agent-v2-darwin-arm64",
)
self.assertEqual(
MODULE.infer_asset_path("clickhouse-driver-agent-linux-arm64"),
"Linux/clickhouse-driver-agent-linux-arm64",
)
self.assertEqual(MODULE.infer_asset_path("duckdb.dll"), "Windows/duckdb.dll")
self.assertIsNone(MODULE.infer_asset_path("duckdb-driver.zip"))
def test_infer_driver_zip_asset_name(self):
self.assertEqual(
MODULE.infer_driver_zip_asset_name("clickhouse-driver-agent-darwin-arm64"),
"clickhouse-driver-agent-darwin-arm64.zip",
)
self.assertEqual(
MODULE.infer_driver_zip_asset_name("mariadb-driver-agent-windows-amd64.exe"),
"mariadb-driver-agent-windows-amd64.zip",
)
self.assertEqual(
MODULE.infer_driver_zip_asset_name("mongodb-driver-agent-v1-windows-arm64.exe"),
"mongodb-driver-agent-v1-windows-arm64.zip",
)
self.assertEqual(
MODULE.infer_driver_zip_asset_name("duckdb-driver-agent-windows-amd64.exe"),
"duckdb-driver-agent-windows-amd64.zip",
)
self.assertIsNone(MODULE.infer_driver_zip_asset_name("duckdb.dll"))
def test_validate_release_assets_extracts_independent_zip(self):
name = "clickhouse-driver-agent-darwin-arm64"
zip_name = f"{name}.zip"
payload = b"zipped-driver-agent"
release = {
"assets": [
{
"name": zip_name,
"browser_download_url": f"https://example.test/{zip_name}",
}
]
}
manifest = {
"assets": {
name: {
"platform": "darwin/arm64",
"revision": "src-expected",
"sha256": hashlib.sha256(payload).hexdigest(),
}
}
}
with tempfile.TemporaryDirectory(prefix="gonavi-validate-release-assets-") as tmp:
archive_path = pathlib.Path(tmp) / zip_name
with zipfile.ZipFile(archive_path, "w", compression=zipfile.ZIP_DEFLATED) as archive:
archive.writestr(f"MacOS/{name}", payload)
archive_bytes = archive_path.read_bytes()
archive_sha = hashlib.sha256(archive_bytes).hexdigest()
release["assets"][0]["size"] = len(archive_bytes)
release["assets"][0]["digest"] = f"sha256:{archive_sha}"
manifest["assets"][name]["size"] = len(payload)
release_index = {
"assets": {zip_name: len(archive_bytes)},
"assetSha256": {zip_name: archive_sha},
"entries": {
name: {
"archive": zip_name,
"path": f"MacOS/{name}",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
},
}
downloaded_urls = []
probed_payloads = []
def fake_download(url, destination):
downloaded_urls.append(url)
destination.write_bytes(archive_path.read_bytes())
def fake_probe(path):
probed_payloads.append(path.read_bytes())
return "src-expected"
original_download = MODULE.download_url
original_probe = MODULE.probe_metadata_revision
try:
MODULE.download_url = fake_download
MODULE.probe_metadata_revision = fake_probe
mismatches, skipped = MODULE.validate_release_assets(
release,
manifest,
runtime_platform="darwin/arm64",
release_index=release_index,
)
finally:
MODULE.download_url = original_download
MODULE.probe_metadata_revision = original_probe
self.assertEqual(mismatches, [])
self.assertEqual(skipped, [])
self.assertEqual(downloaded_urls, [f"https://example.test/{zip_name}"])
self.assertEqual(probed_payloads, [payload])
def test_indexed_duckdb_archive_verifies_runtime_library_entry(self):
name = "duckdb-driver-agent-windows-amd64.exe"
zip_name = "duckdb-driver-agent-windows-amd64.zip"
agent_payload = b"duckdb-agent"
library_payload = b"wrong-duckdb-library"
expected_library_sha = hashlib.sha256(b"expected-duckdb-library").hexdigest()
manifest = {
"assets": {
name: {
"platform": "windows/amd64",
"revision": "src-expected",
"size": len(agent_payload),
"sha256": hashlib.sha256(agent_payload).hexdigest(),
}
}
}
with tempfile.TemporaryDirectory(prefix="gonavi-validate-release-assets-") as tmp:
archive_path = pathlib.Path(tmp) / zip_name
with zipfile.ZipFile(archive_path, "w", compression=zipfile.ZIP_DEFLATED) as archive:
archive.writestr(f"Windows/{name}", agent_payload)
archive.writestr("Windows/duckdb.dll", library_payload)
archive_bytes = archive_path.read_bytes()
archive_sha = hashlib.sha256(archive_bytes).hexdigest()
release = {
"assets": [
{
"name": zip_name,
"size": len(archive_bytes),
"digest": f"sha256:{archive_sha}",
"browser_download_url": f"https://example.test/{zip_name}",
}
]
}
release_index = {
"assets": {zip_name: len(archive_bytes)},
"assetSha256": {zip_name: archive_sha},
"entries": {
name: {
"archive": zip_name,
"path": f"Windows/{name}",
"size": len(agent_payload),
"sha256": hashlib.sha256(agent_payload).hexdigest(),
},
"duckdb.dll": {
"archive": zip_name,
"path": "Windows/duckdb.dll",
"size": len(library_payload),
"sha256": expected_library_sha,
},
},
}
def fake_download(_url, destination):
destination.write_bytes(archive_bytes)
original_download = MODULE.download_url
original_probe = MODULE.probe_metadata_revision
try:
MODULE.download_url = fake_download
MODULE.probe_metadata_revision = lambda _path: "src-expected"
mismatches, skipped = MODULE.validate_release_assets(
release,
manifest,
runtime_platform="windows/amd64",
release_index=release_index,
)
finally:
MODULE.download_url = original_download
MODULE.probe_metadata_revision = original_probe
self.assertEqual(skipped, [])
self.assertEqual(
mismatches,
[
(
"duckdb.dll",
"entry_sha256",
hashlib.sha256(library_payload).hexdigest(),
expected_library_sha,
)
],
)
def test_indexed_validation_rejects_ci_bundle_archive_maps(self):
name = "clickhouse-driver-agent-linux-amd64"
zip_name = f"{name}.zip"
archive_bytes = b"independent-archive"
archive_sha = hashlib.sha256(archive_bytes).hexdigest()
bundle_bytes = b"ci-completion-bundle"
bundle_sha = hashlib.sha256(bundle_bytes).hexdigest()
payload = b"driver"
release = {
"assets": [
{
"name": zip_name,
"size": len(archive_bytes),
"digest": f"sha256:{archive_sha}",
"browser_download_url": f"https://example.test/{zip_name}",
},
{
"name": MODULE.CI_BUNDLE_ASSET_NAME,
"size": len(bundle_bytes),
"digest": f"sha256:{bundle_sha}",
"browser_download_url": f"https://example.test/{MODULE.CI_BUNDLE_ASSET_NAME}",
},
]
}
manifest = {
"assets": {
name: {
"platform": "linux/amd64",
"revision": "src-expected",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
}
}
release_index = {
"assets": {
zip_name: len(archive_bytes),
MODULE.CI_BUNDLE_ASSET_NAME: len(bundle_bytes),
},
"assetSha256": {
zip_name: archive_sha,
MODULE.CI_BUNDLE_ASSET_NAME: bundle_sha,
},
"entries": {
name: {
"archive": zip_name,
"path": f"Linux/{name}",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
},
}
def fail_download(_url, _destination):
raise AssertionError("cross-platform indexed asset should not be downloaded")
original_download = MODULE.download_url
try:
MODULE.download_url = fail_download
mismatches, skipped = MODULE.validate_release_assets(
release,
manifest,
runtime_platform="darwin/arm64",
release_index=release_index,
)
finally:
MODULE.download_url = original_download
self.assertEqual(skipped, [])
self.assertIn(
(MODULE.CI_BUNDLE_ASSET_NAME, "index_ci_bundle", "present in assets", "absent"),
mismatches,
)
self.assertIn(
(
MODULE.CI_BUNDLE_ASSET_NAME,
"index_ci_bundle_sha256",
"present in assetSha256",
"absent",
),
mismatches,
)
def test_indexed_validation_rejects_entry_backed_by_ci_bundle(self):
name = "clickhouse-driver-agent-linux-amd64"
zip_name = f"{name}.zip"
archive_bytes = b"independent-archive"
archive_sha = hashlib.sha256(archive_bytes).hexdigest()
payload = b"driver"
release = {
"assets": [
{
"name": zip_name,
"size": len(archive_bytes),
"digest": f"sha256:{archive_sha}",
"browser_download_url": f"https://example.test/{zip_name}",
}
]
}
manifest = {
"assets": {
name: {
"platform": "linux/amd64",
"revision": "src-expected",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
}
}
release_index = {
"assets": {zip_name: len(archive_bytes)},
"assetSha256": {zip_name: archive_sha},
"entries": {
name: {
"archive": zip_name,
"path": f"Linux/{name}",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
},
"rogue-driver-agent": {
"archive": MODULE.CI_BUNDLE_ASSET_NAME,
"path": "Linux/rogue-driver-agent",
"size": 1,
"sha256": "a" * 64,
},
},
}
def fail_download(_url, _destination):
raise AssertionError("cross-platform indexed asset should not be downloaded")
original_download = MODULE.download_url
try:
MODULE.download_url = fail_download
mismatches, skipped = MODULE.validate_release_assets(
release,
manifest,
runtime_platform="darwin/arm64",
release_index=release_index,
)
finally:
MODULE.download_url = original_download
self.assertEqual(skipped, [])
self.assertIn(
(
"rogue-driver-agent",
"index_ci_bundle_entry",
MODULE.CI_BUNDLE_ASSET_NAME,
"individual driver archive",
),
mismatches,
)
def test_indexed_validation_rejects_malformed_cross_platform_duckdb_library(self):
name = MODULE.DUCKDB_WINDOWS_AGENT_NAME
zip_name = MODULE.infer_driver_zip_asset_name(name)
archive_bytes = b"duckdb-archive"
archive_sha = hashlib.sha256(archive_bytes).hexdigest()
payload = b"duckdb-agent"
release = {
"assets": [
{
"name": zip_name,
"size": len(archive_bytes),
"digest": f"sha256:{archive_sha}",
"browser_download_url": f"https://example.test/{zip_name}",
}
]
}
manifest = {
"assets": {
name: {
"platform": "windows/amd64",
"revision": "src-expected",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
}
}
release_index = {
"assets": {zip_name: len(archive_bytes)},
"assetSha256": {zip_name: archive_sha},
"entries": {
name: {
"archive": zip_name,
"path": f"Windows/{name}",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
},
MODULE.DUCKDB_WINDOWS_LIBRARY_NAME: {
"archive": "missing.zip",
"path": "../Windows/duckdb.dll",
"size": -1,
"sha256": "invalid",
},
},
}
def fail_download(_url, _destination):
raise AssertionError("cross-platform indexed asset should not be downloaded")
original_download = MODULE.download_url
try:
MODULE.download_url = fail_download
mismatches, skipped = MODULE.validate_release_assets(
release,
manifest,
runtime_platform="darwin/arm64",
release_index=release_index,
)
finally:
MODULE.download_url = original_download
self.assertEqual(skipped, [])
self.assertIn(
(MODULE.DUCKDB_WINDOWS_LIBRARY_NAME, "index_asset", "missing.zip", "present in assets"),
mismatches,
)
self.assertIn(
(
MODULE.DUCKDB_WINDOWS_LIBRARY_NAME,
"index_entry_path",
"../Windows/duckdb.dll",
"safe relative archive path",
),
mismatches,
)
self.assertIn(
(MODULE.DUCKDB_WINDOWS_LIBRARY_NAME, "index_entry_size", -1, "non-negative integer"),
mismatches,
)
self.assertIn(
(MODULE.DUCKDB_WINDOWS_LIBRARY_NAME, "index_entry_sha256", "invalid", "sha256"),
mismatches,
)
self.assertIn(
(MODULE.DUCKDB_WINDOWS_LIBRARY_NAME, "index_archive", "missing.zip", zip_name),
mismatches,
)
def test_indexed_validation_requires_duckdb_library_mapping(self):
name = MODULE.DUCKDB_WINDOWS_AGENT_NAME
zip_name = MODULE.infer_driver_zip_asset_name(name)
archive_bytes = b"duckdb-archive"
archive_sha = hashlib.sha256(archive_bytes).hexdigest()
payload = b"duckdb-agent"
release = {
"assets": [
{
"name": zip_name,
"size": len(archive_bytes),
"digest": f"sha256:{archive_sha}",
"browser_download_url": f"https://example.test/{zip_name}",
}
]
}
manifest = {
"assets": {
name: {
"platform": "windows/amd64",
"revision": "src-expected",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
}
}
release_index = {
"assets": {zip_name: len(archive_bytes)},
"assetSha256": {zip_name: archive_sha},
"entries": {
name: {
"archive": zip_name,
"path": f"Windows/{name}",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
},
}
def fail_download(_url, _destination):
raise AssertionError("cross-platform indexed asset should not be downloaded")
original_download = MODULE.download_url
try:
MODULE.download_url = fail_download
mismatches, skipped = MODULE.validate_release_assets(
release,
manifest,
runtime_platform="darwin/arm64",
release_index=release_index,
)
finally:
MODULE.download_url = original_download
self.assertEqual(skipped, [])
self.assertIn(
(
MODULE.DUCKDB_WINDOWS_LIBRARY_NAME,
"index_entry",
"",
f"present with {MODULE.DUCKDB_WINDOWS_AGENT_NAME}",
),
mismatches,
)
def test_validate_release_assets_reports_independent_zip_raw_sha_mismatch(self):
name = "mariadb-driver-agent-windows-amd64.exe"
zip_name = "mariadb-driver-agent-windows-amd64.zip"
payload = b"unexpected-driver-agent"
expected_manifest_sha = "d" * 64
release = {
"assets": [
{
"name": zip_name,
"browser_download_url": f"https://example.test/{zip_name}",
"digest": f"sha256:{hashlib.sha256(b'archive-bytes').hexdigest()}",
}
]
}
manifest = {
"assets": {
name: {
"platform": "windows/amd64",
"revision": "src-expected",
"sha256": expected_manifest_sha,
}
}
}
with tempfile.TemporaryDirectory(prefix="gonavi-validate-release-assets-") as tmp:
archive_path = pathlib.Path(tmp) / zip_name
with zipfile.ZipFile(archive_path, "w", compression=zipfile.ZIP_DEFLATED) as archive:
archive.writestr(f"Windows/{name}", payload)
archive_bytes = archive_path.read_bytes()
archive_sha = hashlib.sha256(archive_bytes).hexdigest()
release["assets"][0]["size"] = len(archive_bytes)
release["assets"][0]["digest"] = f"sha256:{archive_sha}"
manifest["assets"][name]["size"] = len(payload)
release_index = {
"assets": {zip_name: len(archive_bytes)},
"assetSha256": {zip_name: archive_sha},
"entries": {
name: {
"archive": zip_name,
"path": f"Windows/{name}",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
},
}
def fail_download(_url, _destination):
raise AssertionError("cross-platform indexed asset should not be downloaded")
original_download = MODULE.download_url
original_probe = MODULE.probe_metadata_revision
try:
MODULE.download_url = fail_download
MODULE.probe_metadata_revision = lambda _path: "src-expected"
mismatches, skipped = MODULE.validate_release_assets(
release,
manifest,
runtime_platform="linux/amd64",
release_index=release_index,
)
finally:
MODULE.download_url = original_download
MODULE.probe_metadata_revision = original_probe
self.assertEqual(skipped, [])
self.assertEqual(
mismatches,
[(name, "index_sha256", hashlib.sha256(payload).hexdigest(), expected_manifest_sha)],
)
def test_validate_release_assets_skips_cross_platform_zip_revision_probe(self):
name = "mongodb-driver-agent-v1-linux-arm64"
zip_name = f"{name}.zip"
payload = b"cross-platform-driver-agent"
release = {
"assets": [
{
"name": zip_name,
"browser_download_url": f"https://example.test/{zip_name}",
}
]
}
manifest = {
"assets": {
name: {
"platform": "linux/arm64",
"revision": "src-expected",
"sha256": hashlib.sha256(payload).hexdigest(),
}
}
}
with tempfile.TemporaryDirectory(prefix="gonavi-validate-release-assets-") as tmp:
archive_path = pathlib.Path(tmp) / zip_name
with zipfile.ZipFile(archive_path, "w", compression=zipfile.ZIP_DEFLATED) as archive:
archive.writestr(f"Linux/{name}", payload)
archive_bytes = archive_path.read_bytes()
archive_sha = hashlib.sha256(archive_bytes).hexdigest()
release["assets"][0]["size"] = len(archive_bytes)
release["assets"][0]["digest"] = f"sha256:{archive_sha}"
manifest["assets"][name]["size"] = len(payload)
release_index = {
"assets": {zip_name: len(archive_bytes)},
"assetSha256": {zip_name: archive_sha},
"entries": {
name: {
"archive": zip_name,
"path": f"Linux/{name}",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
},
}
def fail_download(_url, _destination):
raise AssertionError("cross-platform indexed asset should not be downloaded")
def fail_probe(_path):
raise AssertionError("cross-platform zip entry should not be executed")
original_download = MODULE.download_url
original_probe = MODULE.probe_metadata_revision
try:
MODULE.download_url = fail_download
MODULE.probe_metadata_revision = fail_probe
mismatches, skipped = MODULE.validate_release_assets(
release,
manifest,
runtime_platform="darwin/arm64",
release_index=release_index,
)
finally:
MODULE.download_url = original_download
MODULE.probe_metadata_revision = original_probe
self.assertEqual(mismatches, [])
self.assertEqual(skipped, [])
def test_validate_release_assets_reports_missing_independent_zip_entry(self):
name = "clickhouse-driver-agent-linux-amd64"
zip_name = f"{name}.zip"
release = {
"assets": [
{
"name": zip_name,
"browser_download_url": f"https://example.test/{zip_name}",
}
]
}
manifest = {
"assets": {
name: {
"platform": "linux/amd64",
"revision": "src-expected",
"sha256": hashlib.sha256(b"driver").hexdigest(),
}
}
}
with tempfile.TemporaryDirectory(prefix="gonavi-validate-release-assets-") as tmp:
archive_path = pathlib.Path(tmp) / zip_name
with zipfile.ZipFile(archive_path, "w", compression=zipfile.ZIP_DEFLATED) as archive:
archive.writestr(name, b"driver")
archive_bytes = archive_path.read_bytes()
archive_sha = hashlib.sha256(archive_bytes).hexdigest()
release["assets"][0]["size"] = len(archive_bytes)
release["assets"][0]["digest"] = f"sha256:{archive_sha}"
manifest["assets"][name]["size"] = len(b"driver")
release_index = {
"assets": {zip_name: len(archive_bytes)},
"assetSha256": {zip_name: archive_sha},
"entries": {
name: {
"archive": zip_name,
"path": f"Linux/{name}",
"size": len(b"driver"),
"sha256": hashlib.sha256(b"driver").hexdigest(),
}
},
}
def fake_download(_url, destination):
destination.write_bytes(archive_path.read_bytes())
original_download = MODULE.download_url
try:
MODULE.download_url = fake_download
mismatches, skipped = MODULE.validate_release_assets(
release,
manifest,
runtime_platform="linux/amd64",
release_index=release_index,
)
finally:
MODULE.download_url = original_download
self.assertEqual(skipped, [])
self.assertEqual(
mismatches,
[(name, "zip_entry", "", f"Linux/{name}")],
)
def test_indexed_validation_checks_release_archive_metadata_without_download(self):
name = "clickhouse-driver-agent-linux-amd64"
zip_name = f"{name}.zip"
payload = b"driver"
expected_archive = b"indexed-archive"
expected_archive_sha = hashlib.sha256(expected_archive).hexdigest()
release = {
"assets": [
{
"name": zip_name,
"size": len(expected_archive) + 1,
"digest": f"sha256:{hashlib.sha256(b'wrong-archive').hexdigest()}",
"browser_download_url": f"https://example.test/{zip_name}",
}
]
}
manifest = {
"assets": {
name: {
"platform": "linux/amd64",
"revision": "src-expected",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
}
}
release_index = {
"assets": {zip_name: len(expected_archive)},
"assetSha256": {zip_name: expected_archive_sha},
"entries": {
name: {
"archive": zip_name,
"path": f"Linux/{name}",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
},
}
def fail_download(_url, _destination):
raise AssertionError("cross-platform indexed asset should not be downloaded")
original_download = MODULE.download_url
try:
MODULE.download_url = fail_download
mismatches, skipped = MODULE.validate_release_assets(
release,
manifest,
runtime_platform="darwin/arm64",
release_index=release_index,
)
finally:
MODULE.download_url = original_download
self.assertEqual(skipped, [])
self.assertEqual(
mismatches,
[
(zip_name, "archive_size", len(expected_archive) + 1, len(expected_archive)),
(
zip_name,
"archive_sha256",
hashlib.sha256(b"wrong-archive").hexdigest(),
expected_archive_sha,
),
],
)
def test_malformed_new_index_does_not_fall_back_to_zip_downloads(self):
name = "clickhouse-driver-agent-linux-amd64"
zip_name = f"{name}.zip"
release = {
"assets": [
{
"name": zip_name,
"browser_download_url": f"https://example.test/{zip_name}",
}
]
}
manifest = {
"assets": {
name: {
"platform": "linux/amd64",
"revision": "src-expected",
"size": 6,
"sha256": hashlib.sha256(b"driver").hexdigest(),
}
}
}
release_index = {"assets": {zip_name: 123}, "entries": {}}
def fail_download(_url, _destination):
raise AssertionError("malformed new index must fail before downloading archives")
original_download = MODULE.download_url
try:
MODULE.download_url = fail_download
with self.assertRaisesRegex(RuntimeError, "assetSha256"):
MODULE.validate_release_assets(
release,
manifest,
runtime_platform="linux/amd64",
release_index=release_index,
)
finally:
MODULE.download_url = original_download
def test_main_downloads_index_and_avoids_cross_platform_archive(self):
name = "mongodb-driver-agent-v1-linux-arm64"
zip_name = f"{name}.zip"
payload = b"driver"
archive_size = 123
archive_sha = hashlib.sha256(b"archive").hexdigest()
manifest = {
"assets": {
name: {
"platform": "linux/arm64",
"revision": "src-expected",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
}
}
release_index = {
"assets": {zip_name: archive_size},
"assetSha256": {zip_name: archive_sha},
"entries": {
name: {
"archive": zip_name,
"path": f"Linux/{name}",
"size": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
}
},
}
release = {
"assets": [
{
"name": MODULE.MANIFEST_ASSET_NAME,
"browser_download_url": "https://example.test/manifest",
},
{
"name": MODULE.INDEX_ASSET_NAME,
"browser_download_url": "https://example.test/index",
},
{
"name": zip_name,
"size": archive_size,
"digest": f"sha256:{archive_sha}",
"browser_download_url": f"https://example.test/{zip_name}",
},
]
}
downloaded_urls = []
def fake_download(url, destination):
downloaded_urls.append(url)
if url.endswith("/manifest"):
destination.write_text(json.dumps(manifest), encoding="utf-8")
elif url.endswith("/index"):
destination.write_text(json.dumps(release_index), encoding="utf-8")
else:
raise AssertionError("main should not download a cross-platform archive")
original_load_release = MODULE.load_release
original_download = MODULE.download_url
original_runtime = MODULE.current_runtime_platform
original_argv = sys.argv
try:
MODULE.load_release = lambda _repo, _tag: release
MODULE.download_url = fake_download
MODULE.current_runtime_platform = lambda: "darwin/arm64"
sys.argv = [str(MODULE_PATH), "--tag", "dev-latest"]
with contextlib.redirect_stdout(io.StringIO()):
self.assertEqual(MODULE.main(), 0)
finally:
MODULE.load_release = original_load_release
MODULE.download_url = original_download
MODULE.current_runtime_platform = original_runtime
sys.argv = original_argv
self.assertEqual(
downloaded_urls,
["https://example.test/manifest", "https://example.test/index"],
)
def test_validate_release_assets_reports_sha_mismatch(self):
release = {
"assets": [
{
"name": "clickhouse-driver-agent-darwin-arm64",
"browser_download_url": "https://example.test/clickhouse-driver-agent-darwin-arm64",
}
]
}
manifest = {
"assets": {
"clickhouse-driver-agent-darwin-arm64": {
"revision": "src-expected",
"sha256": "deadbeef",
}
}
}
with tempfile.TemporaryDirectory(prefix="gonavi-validate-release-assets-") as tmp:
payload_path = pathlib.Path(tmp) / "clickhouse-driver-agent-darwin-arm64"
payload_path.write_bytes(b"test-binary")
def fake_download(url, destination):
destination.write_bytes(payload_path.read_bytes())
original_download = MODULE.download_url
original_probe = MODULE.probe_metadata_revision
try:
MODULE.download_url = fake_download
MODULE.probe_metadata_revision = lambda _path: "src-expected"
mismatches, skipped = MODULE.validate_release_assets(release, manifest)
finally:
MODULE.download_url = original_download
MODULE.probe_metadata_revision = original_probe
self.assertEqual(skipped, [])
self.assertEqual(len(mismatches), 1)
name, field, actual, expected = mismatches[0]
self.assertEqual(name, "clickhouse-driver-agent-darwin-arm64")
self.assertEqual(field, "sha256")
self.assertEqual(actual, hashlib.sha256(b"test-binary").hexdigest())
self.assertEqual(expected, "deadbeef")
def test_validate_release_assets_reports_revision_mismatch(self):
release = {
"assets": [
{
"name": "clickhouse-driver-agent-darwin-arm64",
"browser_download_url": "https://example.test/clickhouse-driver-agent-darwin-arm64",
}
]
}
payload = b"test-binary"
manifest = {
"assets": {
"clickhouse-driver-agent-darwin-arm64": {
"platform": "darwin/arm64",
"revision": "src-expected",
"sha256": hashlib.sha256(payload).hexdigest(),
}
}
}
with tempfile.TemporaryDirectory(prefix="gonavi-validate-release-assets-") as tmp:
payload_path = pathlib.Path(tmp) / "clickhouse-driver-agent-darwin-arm64"
payload_path.write_bytes(payload)
def fake_download(url, destination):
destination.write_bytes(payload_path.read_bytes())
original_download = MODULE.download_url
original_probe = MODULE.probe_metadata_revision
try:
MODULE.download_url = fake_download
MODULE.probe_metadata_revision = lambda _path: "src-actual"
mismatches, skipped = MODULE.validate_release_assets(release, manifest, runtime_platform="darwin/arm64")
finally:
MODULE.download_url = original_download
MODULE.probe_metadata_revision = original_probe
self.assertEqual(skipped, [])
self.assertEqual(mismatches, [("clickhouse-driver-agent-darwin-arm64", "revision", "src-actual", "src-expected")])
def test_validate_release_assets_skips_cross_platform_revision_probe(self):
release = {
"assets": [
{
"name": "clickhouse-driver-agent-darwin-amd64",
"browser_download_url": "https://example.test/clickhouse-driver-agent-darwin-amd64",
}
]
}
payload = b"darwin-binary"
manifest = {
"assets": {
"clickhouse-driver-agent-darwin-amd64": {
"platform": "darwin/amd64",
"revision": "src-expected",
"sha256": hashlib.sha256(payload).hexdigest(),
}
}
}
with tempfile.TemporaryDirectory(prefix="gonavi-validate-release-assets-") as tmp:
payload_path = pathlib.Path(tmp) / "clickhouse-driver-agent-darwin-amd64"
payload_path.write_bytes(payload)
def fake_download(url, destination):
destination.write_bytes(payload_path.read_bytes())
def fail_probe(_path):
raise AssertionError("cross-platform asset should not be executed")
original_download = MODULE.download_url
original_probe = MODULE.probe_metadata_revision
try:
MODULE.download_url = fake_download
MODULE.probe_metadata_revision = fail_probe
mismatches, skipped = MODULE.validate_release_assets(release, manifest, runtime_platform="linux/amd64")
finally:
MODULE.download_url = original_download
MODULE.probe_metadata_revision = original_probe
self.assertEqual(mismatches, [])
self.assertEqual(skipped, [])
def test_validate_release_assets_uses_release_digest_without_download(self):
payload = b"darwin-binary"
digest = hashlib.sha256(payload).hexdigest()
release = {
"assets": [
{
"name": "clickhouse-driver-agent-darwin-amd64",
"digest": f"sha256:{digest}",
"browser_download_url": "https://example.test/clickhouse-driver-agent-darwin-amd64",
}
]
}
manifest = {
"assets": {
"clickhouse-driver-agent-darwin-amd64": {
"platform": "darwin/amd64",
"revision": "src-expected",
"sha256": digest,
}
}
}
def fail_download(_url, _destination):
raise AssertionError("release digest should avoid downloading cross-platform assets")
original_download = MODULE.download_url
try:
MODULE.download_url = fail_download
mismatches, skipped = MODULE.validate_release_assets(release, manifest, runtime_platform="linux/amd64")
finally:
MODULE.download_url = original_download
self.assertEqual(mismatches, [])
self.assertEqual(skipped, [])
if __name__ == "__main__":
unittest.main()