From 5cd805a2afac657dba7500b7c0f2d5370b241e58 Mon Sep 17 00:00:00 2001 From: ghangz <152254226+ghangz@users.noreply.github.com> Date: Wed, 1 Jul 2026 11:42:07 +0800 Subject: [PATCH 1/2] Add mcoplib artifact manifest --- tools/artifact_manifest.py | 61 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tools/artifact_manifest.py diff --git a/tools/artifact_manifest.py b/tools/artifact_manifest.py new file mode 100644 index 0000000..c5c7dc4 --- /dev/null +++ b/tools/artifact_manifest.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +"""Build a reproducible artifact manifest with file sizes and hashes.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +from pathlib import Path + +PATTERNS = ['build/**/*.so', 'benchmark/**/*.log', 'logs/**/*', '*.txt'] + + +def sha256(path: Path) -> str: + h = hashlib.sha256() + with path.open("rb") as f: + for chunk in iter(lambda: f.read(1024 * 1024), b""): + h.update(chunk) + return h.hexdigest() + + +def collect(root: Path) -> dict[str, object]: + seen: set[str] = set() + artifacts: list[dict[str, object]] = [] + for pattern in PATTERNS: + for path in sorted(root.glob(pattern)): + if not path.is_file(): + continue + rel = path.relative_to(root).as_posix() + if rel in seen: + continue + seen.add(rel) + artifacts.append({"path": rel, "bytes": path.stat().st_size, "sha256": sha256(path)}) + return {"root": str(root), "count": len(artifacts), "artifacts": artifacts} + + +def self_test() -> None: + sample = Path("_artifact_manifest_sample.txt") + sample.write_text("maca artifact\n", encoding="utf-8") + try: + data = collect(Path.cwd()) + assert any(item["path"] == sample.name for item in data["artifacts"]) + print(json.dumps({"ok": True, "count": data["count"]}, ensure_ascii=False)) + finally: + sample.unlink(missing_ok=True) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--root", default=".") + parser.add_argument("--self-test", action="store_true") + args = parser.parse_args() + if args.self_test: + self_test() + return 0 + print(json.dumps(collect(Path(args.root)), ensure_ascii=False, indent=2)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 76d76c0252e82d0f2feed2795296c55f60e2d241 Mon Sep 17 00:00:00 2001 From: ghangz <152254226+ghangz@users.noreply.github.com> Date: Wed, 1 Jul 2026 15:43:51 +0800 Subject: [PATCH 2/2] Harden artifact manifest validation --- tools/artifact_manifest.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/tools/artifact_manifest.py b/tools/artifact_manifest.py index c5c7dc4..0f0539c 100644 --- a/tools/artifact_manifest.py +++ b/tools/artifact_manifest.py @@ -7,8 +7,9 @@ import hashlib import json from pathlib import Path +from tempfile import TemporaryDirectory -PATTERNS = ['build/**/*.so', 'benchmark/**/*.log', 'logs/**/*', '*.txt'] +PATTERNS = ["build/**/*.so", "benchmark/**/*.log", "logs/**/*", "*.txt"] def sha256(path: Path) -> str: @@ -20,6 +21,9 @@ def sha256(path: Path) -> str: def collect(root: Path) -> dict[str, object]: + if not root.is_dir(): + raise NotADirectoryError(f"artifact root is not a directory: {root}") + seen: set[str] = set() artifacts: list[dict[str, object]] = [] for pattern in PATTERNS: @@ -30,19 +34,21 @@ def collect(root: Path) -> dict[str, object]: if rel in seen: continue seen.add(rel) - artifacts.append({"path": rel, "bytes": path.stat().st_size, "sha256": sha256(path)}) + artifacts.append( + {"path": rel, "bytes": path.stat().st_size, "sha256": sha256(path)} + ) return {"root": str(root), "count": len(artifacts), "artifacts": artifacts} def self_test() -> None: - sample = Path("_artifact_manifest_sample.txt") - sample.write_text("maca artifact\n", encoding="utf-8") - try: - data = collect(Path.cwd()) - assert any(item["path"] == sample.name for item in data["artifacts"]) - print(json.dumps({"ok": True, "count": data["count"]}, ensure_ascii=False)) - finally: - sample.unlink(missing_ok=True) + with TemporaryDirectory() as tmp_dir: + root = Path(tmp_dir) + sample = root / "artifact_manifest_sample.txt" + sample.write_text("maca artifact\n", encoding="utf-8") + data = collect(root) + if not any(item["path"] == sample.name for item in data["artifacts"]): + raise RuntimeError(f"self-test failed: {data}") + print(json.dumps({"ok": True, "count": data["count"]}, ensure_ascii=False)) def main() -> int: @@ -53,7 +59,10 @@ def main() -> int: if args.self_test: self_test() return 0 - print(json.dumps(collect(Path(args.root)), ensure_ascii=False, indent=2)) + root = Path(args.root) + if not root.is_dir(): + parser.error(f"--root is not a directory: {root}") + print(json.dumps(collect(root), ensure_ascii=False, indent=2)) return 0