Files
linuxcncWebWASM/scripts/validate_download_index.py

69 lines
2.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""Validate external artifact provenance before it enters a build context."""
from __future__ import annotations
import argparse
import json
import re
from pathlib import Path
from urllib.parse import urlparse
SHA256 = re.compile(r"^[0-9a-f]{64}$")
KINDS = {"official", "china-mirror", "local-cache"}
def validate(path: Path) -> list[str]:
errors: list[str] = []
seen: set[tuple[str, str]] = set()
with path.open("r", encoding="utf-8") as handle:
for line_number, line in enumerate(handle, 1):
if not line.strip():
continue
try:
row = json.loads(line)
except json.JSONDecodeError as exc:
errors.append(f"{path}:{line_number}: invalid JSON: {exc.msg}")
continue
if row.get("record_type") != "artifact":
continue
required = {"name", "version", "source_url", "sha256", "bytes", "license", "mirror_kind"}
missing = sorted(required - row.keys())
if missing:
errors.append(f"{path}:{line_number}: missing {missing}")
continue
key = (str(row["name"]), str(row["version"]))
if key in seen:
errors.append(f"{path}:{line_number}: duplicate artifact {key[0]}@{key[1]}")
seen.add(key)
if not SHA256.fullmatch(str(row["sha256"])):
errors.append(f"{path}:{line_number}: sha256 must be 64 lowercase hex characters")
if not isinstance(row["bytes"], int) or row["bytes"] <= 0:
errors.append(f"{path}:{line_number}: bytes must be a positive integer")
if row["mirror_kind"] not in KINDS:
errors.append(f"{path}:{line_number}: invalid mirror_kind")
parsed = urlparse(str(row["source_url"]))
if row["mirror_kind"] != "local-cache" and parsed.scheme not in {"http", "https"}:
errors.append(f"{path}:{line_number}: source_url must be HTTP(S) for downloaded artifacts")
if row["mirror_kind"] == "china-mirror" and not row.get("origin_url"):
errors.append(f"{path}:{line_number}: china-mirror requires origin_url")
return errors
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--index", type=Path, default=Path("vendor/downloads/index.jsonl"))
args = parser.parse_args()
errors = validate(args.index)
if errors:
for error in errors:
print(f"ERROR: {error}")
return 1
print(f"download_index=valid path={args.index}")
return 0
if __name__ == "__main__":
raise SystemExit(main())