71 lines
2.4 KiB
Python
71 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Build a deterministic Candidate artifact without overwriting evidence."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from aios_autonomous_release_candidate.artifact import ArtifactBuilder
|
|
|
|
|
|
def exclusive_write(path: Path, content: bytes, mode: int) -> None:
|
|
if path.is_symlink():
|
|
raise RuntimeError("artifact output symlink rejected")
|
|
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
|
|
if hasattr(os, "O_NOFOLLOW"):
|
|
flags |= os.O_NOFOLLOW
|
|
descriptor = os.open(path, flags, mode)
|
|
try:
|
|
os.write(descriptor, content)
|
|
os.fsync(descriptor)
|
|
finally:
|
|
os.close(descriptor)
|
|
|
|
|
|
def build_parser() -> argparse.ArgumentParser:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--source", required=True, type=Path)
|
|
parser.add_argument("--source-oid", required=True)
|
|
parser.add_argument("--tree-oid", required=True)
|
|
parser.add_argument("--output-directory", required=True, type=Path)
|
|
parser.add_argument("--name", default="aios-autonomous-release-candidate")
|
|
return parser
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
args = build_parser().parse_args(argv)
|
|
output = args.output_directory
|
|
output.mkdir(parents=True, exist_ok=True, mode=0o750)
|
|
if output.is_symlink():
|
|
raise RuntimeError("artifact output directory symlink rejected")
|
|
os.chmod(output, output.stat().st_mode & 0o750)
|
|
builder = ArtifactBuilder()
|
|
built = builder.build_from_directory(args.source_oid, args.tree_oid, args.source)
|
|
builder.verify(built)
|
|
artifact_path = output / f"{args.name}.tar"
|
|
manifest_path = output / f"{args.name}.manifest.json"
|
|
exclusive_write(artifact_path, built.content, 0o640)
|
|
exclusive_write(manifest_path, built.manifest.as_json_bytes(), 0o640)
|
|
print(
|
|
json.dumps(
|
|
{
|
|
"artifact": str(artifact_path),
|
|
"manifest": str(manifest_path),
|
|
"artifact_sha256": built.manifest.artifact_sha256,
|
|
"manifest_sha256": built.manifest.manifest_sha256,
|
|
"package_closure_sha256": built.manifest.package_closure_sha256,
|
|
"secrets_included": False,
|
|
"production_side_effects": False,
|
|
},
|
|
sort_keys=True,
|
|
)
|
|
)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|