release: assemble deterministic BUILD-05 package v2

This commit is contained in:
2026-09-27 11:03:35 +08:00
parent 072237abed
commit 7c77174f2a
3 changed files with 1275 additions and 0 deletions
+1
View File
@@ -26,6 +26,7 @@ The current RC-05 through RC-08 release must follow the repository [mandatory de
- `plan-rollback-rehearsal.py`: verifies the frozen package and source-bound release tools before emitting a non-writing rollback rehearsal plan.
- `../scripts/build-infrastructure-image-bundle.py`: file-only validator for the four application and seven infrastructure image archives, security reports, content-addressed layers, and offline import plan.
- `../scripts/build-third-party-materials.py`: deterministic third-party notice, license-text, and corresponding-source material builder/verifier.
- `../scripts/assemble-build05-v2-package.py`: read-only-by-default BUILD-05 package preflight and atomic assembler. It only composes already validated application, infrastructure, third-party, recovery, and external-evidence inputs; `--assemble` is required to create an output outside the source repository.
- `../release-trust/third-party-materials-baseline.json`: source-frozen technical trust baseline. The shipped baseline intentionally remains `NOT_PROVISIONED` until reviewed real catalog, license, and source identities are supplied.
## Prepare without changing traffic
@@ -0,0 +1,998 @@
#!/usr/bin/env python3
"""Preflight and atomically assemble one self-contained BUILD-05 package v2.
This command composes the existing strict validators. It does not build or
pull images, invoke Docker, contact a registry or database, sign evidence, or
apply a release. The default mode is read-only preflight. ``--assemble`` is
required before any output directory is created.
"""
from __future__ import annotations
import argparse
import hashlib
import importlib.util
import json
import os
import re
import shutil
import stat
import subprocess
import sys
import tempfile
from pathlib import Path, PurePosixPath
from typing import Any, Iterable, Mapping, Sequence
sys.dont_write_bytecode = True
SCRIPT_DIR = Path(__file__).resolve().parent
REPO_ROOT = SCRIPT_DIR.parents[1]
INFRA_ROOT = REPO_ROOT / "yuqei-infra"
if str(SCRIPT_DIR) not in sys.path:
sys.path.insert(0, str(SCRIPT_DIR))
INSTALLABLE_TOOL = SCRIPT_DIR / "build-installable-release.py"
INFRASTRUCTURE_TOOL = SCRIPT_DIR / "build-infrastructure-image-bundle.py"
THIRD_PARTY_TOOL = SCRIPT_DIR / "build-third-party-materials.py"
PACKAGE_TOOL = INFRA_ROOT / "deploy" / "release-package.py"
RESULT_SCHEMA = "yuqei.build05-v2-package-assembly-result.v1"
HEX64_RE = re.compile(r"^[0-9a-f]{64}$")
COMMIT_RE = re.compile(r"^[0-9a-f]{40}(?:[0-9a-f]{24})?$")
SAFE_ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$")
PROJECT_RE = re.compile(r"^[a-z0-9][a-z0-9_-]{0,62}$")
MAX_JSON_BYTES = 16 * 1024 * 1024
class AssemblyError(RuntimeError):
"""Raised when package input or publication cannot be proven safe."""
def _canonical_json_bytes(value: object) -> bytes:
try:
return json.dumps(
value,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
allow_nan=False,
).encode("utf-8")
except (TypeError, ValueError) as exc:
raise AssemblyError("value cannot be encoded as canonical JSON") from exc
def _canonical_file_bytes(value: object) -> bytes:
return _canonical_json_bytes(value) + b"\n"
def _canonical_sha256(value: object) -> str:
return hashlib.sha256(_canonical_json_bytes(value)).hexdigest()
def _with_hash(payload: Mapping[str, Any], field: str) -> dict[str, Any]:
result = dict(payload)
result[field] = _canonical_sha256(result)
return result
def _file_sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for chunk in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def _reject_constant(value: str) -> None:
raise AssemblyError(f"non-finite JSON value is forbidden: {value}")
def _reject_duplicate_pairs(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
result: dict[str, Any] = {}
for key, value in pairs:
if key in result:
raise AssemblyError(f"duplicate JSON key is forbidden: {key}")
result[key] = value
return result
def _read_json(path: Path, *, label: str) -> dict[str, Any]:
target = _regular_file(path, label=label)
try:
size = target.stat().st_size
if size <= 0 or size > MAX_JSON_BYTES:
raise AssemblyError(f"{label} has an invalid size")
payload = json.loads(
target.read_text(encoding="utf-8"),
object_pairs_hook=_reject_duplicate_pairs,
parse_constant=_reject_constant,
)
except AssemblyError:
raise
except (OSError, UnicodeError, json.JSONDecodeError) as exc:
raise AssemblyError(f"{label} is not strict UTF-8 JSON") from exc
if not isinstance(payload, dict):
raise AssemblyError(f"{label} must be a JSON object")
return payload
def _is_linklike(path: Path, info: os.stat_result | None = None) -> bool:
if path.is_symlink():
return True
if hasattr(path, "is_junction") and path.is_junction():
return True
details = info if info is not None else path.lstat()
attributes = getattr(details, "st_file_attributes", 0)
reparse_flag = getattr(stat, "FILE_ATTRIBUTE_REPARSE_POINT", 0)
return bool(reparse_flag and attributes & reparse_flag)
def _absolute(path: Path) -> Path:
return Path(os.path.abspath(os.fspath(path)))
def _reject_link_components(path: Path, *, label: str, require_leaf: bool = True) -> None:
absolute = _absolute(path)
current = Path(absolute.anchor)
parts = absolute.parts[1:] if absolute.anchor else absolute.parts
for index, part in enumerate(parts):
current /= part
if not current.exists() and not current.is_symlink():
if require_leaf or index < len(parts) - 1:
raise AssemblyError(f"{label} path component is missing: {current}")
continue
try:
info = current.lstat()
except OSError as exc:
raise AssemblyError(f"cannot inspect {label} path") from exc
if _is_linklike(current, info):
raise AssemblyError(f"{label} contains a symbolic link or reparse point")
def _directory(path: Path, *, label: str) -> Path:
if not path.is_absolute():
raise AssemblyError(f"{label} must be an absolute path")
lexical = _absolute(path)
_reject_link_components(lexical, label=label)
try:
info = lexical.stat()
except OSError as exc:
raise AssemblyError(f"{label} is missing") from exc
if not stat.S_ISDIR(info.st_mode):
raise AssemblyError(f"{label} must be a real directory")
return lexical.resolve(strict=True)
def _regular_file(path: Path, *, label: str, root: Path | None = None) -> Path:
lexical = _absolute(path)
_reject_link_components(lexical, label=label)
try:
resolved = lexical.resolve(strict=True)
info = resolved.stat()
except OSError as exc:
raise AssemblyError(f"{label} is missing") from exc
if root is not None:
try:
resolved.relative_to(root)
except ValueError as exc:
raise AssemblyError(f"{label} escapes its declared root") from exc
if not stat.S_ISREG(info.st_mode) or info.st_nlink != 1:
raise AssemblyError(f"{label} must be a single-link regular file")
return resolved
def _safe_relative(value: object, *, label: str) -> str:
if not isinstance(value, str) or not value or "\\" in value or "\x00" in value:
raise AssemblyError(f"unsafe {label}")
path = PurePosixPath(value)
if path.is_absolute() or any(part in {"", ".", ".."} for part in path.parts):
raise AssemblyError(f"unsafe {label}: {value!r}")
canonical = path.as_posix()
if canonical != value or re.match(r"^[A-Za-z]:", value):
raise AssemblyError(f"non-canonical {label}: {value!r}")
return canonical
def _relative_file(root: Path, relative: object, *, label: str) -> Path:
safe = _safe_relative(relative, label=label)
return _regular_file(root.joinpath(*PurePosixPath(safe).parts), label=label, root=root)
def _assert_outside_repo(path: Path, repo_root: Path, *, label: str) -> None:
lexical = _absolute(path)
try:
lexical.relative_to(repo_root)
except ValueError:
return
raise AssemblyError(f"{label} must remain outside the source repository")
def _load_module(path: Path, name: str) -> Any:
source = _regular_file(path, label=f"reviewed module {path.name}")
spec = importlib.util.spec_from_file_location(name, source)
if spec is None or spec.loader is None:
raise AssemblyError(f"cannot load reviewed module: {path.name}")
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
try:
spec.loader.exec_module(module)
except Exception:
sys.modules.pop(name, None)
raise
return module
def _git(repo: Path, *args: str) -> str:
environment = {
"PATH": os.environ.get("PATH", ""),
"SYSTEMROOT": os.environ.get("SYSTEMROOT", ""),
"WINDIR": os.environ.get("WINDIR", ""),
"GIT_CONFIG_NOSYSTEM": "1",
"GIT_CONFIG_GLOBAL": os.devnull,
"GIT_OPTIONAL_LOCKS": "0",
"LC_ALL": "C",
"LANG": "C",
}
try:
completed = subprocess.run(
["git", "-c", "core.autocrlf=false", "-c", "core.eol=lf", "-C", str(repo), *args],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=environment,
)
except (OSError, subprocess.CalledProcessError) as exc:
raise AssemblyError(f"Git candidate check failed: {' '.join(args)}") from exc
return completed.stdout.decode("utf-8", errors="strict").strip()
def _verify_repo(repo: Path, expected_commit: str, expected_tag: str) -> None:
if _git(repo, "rev-parse", "HEAD") != expected_commit:
raise AssemblyError("repository HEAD does not match the expected candidate commit")
if _git(repo, "status", "--porcelain=v1", "--untracked-files=all"):
raise AssemblyError("repository checkout is not clean")
if _git(repo, "rev-parse", f"refs/tags/{expected_tag}^{{commit}}") != expected_commit:
raise AssemblyError("candidate tag does not resolve to the expected commit")
if _git(repo, "for-each-ref", "--format=%(refname)", "refs/replace"):
raise AssemblyError("Git replacement refs are forbidden")
def _walk_file_records(value: object) -> Iterable[Mapping[str, Any]]:
if isinstance(value, Mapping):
if {"path", "sha256", "size_bytes"}.issubset(value):
yield value
for nested in value.values():
yield from _walk_file_records(nested)
elif isinstance(value, list):
for nested in value:
yield from _walk_file_records(nested)
def _record_paths(payload: Mapping[str, Any], *, label: str) -> set[str]:
paths: dict[str, str] = {}
for record in _walk_file_records(payload):
relative = _safe_relative(record.get("path"), label=f"{label} file path")
digest = record.get("sha256")
size = record.get("size_bytes")
if not isinstance(digest, str) or not HEX64_RE.fullmatch(digest):
raise AssemblyError(f"{label} file record has an invalid SHA-256: {relative}")
if not isinstance(size, int) or isinstance(size, bool) or size <= 0:
raise AssemblyError(f"{label} file record has an invalid size: {relative}")
prior = paths.get(relative.casefold())
if prior is not None and prior != relative:
raise AssemblyError(f"{label} file paths collide by case")
paths[relative.casefold()] = relative
return set(paths.values())
def _validate_record_files(root: Path, payload: Mapping[str, Any], *, label: str) -> None:
for record in _walk_file_records(payload):
relative = _safe_relative(record.get("path"), label=f"{label} file path")
path = _relative_file(root, relative, label=f"{label} file {relative}")
if path.stat().st_size != record.get("size_bytes") or _file_sha256(path) != record.get("sha256"):
raise AssemblyError(f"{label} file record drifted: {relative}")
def _copy_file_exclusive(source: Path, destination: Path) -> None:
destination.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
descriptor = -1
try:
descriptor = os.open(
destination,
os.O_CREAT | os.O_EXCL | os.O_WRONLY | getattr(os, "O_BINARY", 0),
0o600,
)
with source.open("rb") as reader:
while chunk := reader.read(1024 * 1024):
view = memoryview(chunk)
while view:
written = os.write(descriptor, view)
view = view[written:]
os.fsync(descriptor)
except OSError as exc:
raise AssemblyError(f"cannot create package file: {destination}") from exc
finally:
if descriptor >= 0:
os.close(descriptor)
if os.name != "nt":
destination.chmod(0o600)
def _copy_paths(source_root: Path, destination_root: Path, paths: Iterable[str], *, label: str) -> None:
ordered = sorted(set(paths), key=lambda item: item.encode("utf-8"))
if len({item.casefold() for item in ordered}) != len(ordered):
raise AssemblyError(f"{label} paths collide by case")
for relative in ordered:
source = _relative_file(source_root, relative, label=f"{label} source {relative}")
destination = destination_root.joinpath(*PurePosixPath(relative).parts)
_copy_file_exclusive(source, destination)
if source.stat().st_size != destination.stat().st_size or _file_sha256(source) != _file_sha256(destination):
raise AssemblyError(f"copied {label} file drifted: {relative}")
def _copy_materials_tree(source_root: Path, destination_root: Path) -> None:
paths: list[str] = []
for path in source_root.rglob("*"):
if path.is_dir() and not _is_linklike(path):
continue
relative = path.relative_to(source_root).as_posix()
_regular_file(path, label=f"third-party material {relative}", root=source_root)
paths.append(relative)
_copy_paths(source_root, destination_root, paths, label="third-party material")
def _write_exclusive(path: Path, payload: bytes, *, label: str) -> None:
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
descriptor = -1
try:
descriptor = os.open(
path,
os.O_CREAT | os.O_EXCL | os.O_WRONLY | getattr(os, "O_BINARY", 0),
0o600,
)
view = memoryview(payload)
while view:
written = os.write(descriptor, view)
view = view[written:]
os.fsync(descriptor)
except OSError as exc:
raise AssemblyError(f"cannot create {label}") from exc
finally:
if descriptor >= 0:
os.close(descriptor)
if os.name != "nt":
path.chmod(0o600)
def _files_below(root: Path, *, exclude: set[str]) -> list[dict[str, Any]]:
records: list[dict[str, Any]] = []
for path in root.rglob("*"):
if path.is_dir() and not _is_linklike(path):
continue
relative = path.relative_to(root).as_posix()
_regular_file(path, label=f"staged package file {relative}", root=root)
if relative in exclude:
continue
records.append(
{
"path": relative,
"sha256": _file_sha256(path),
"size_bytes": path.stat().st_size,
}
)
return sorted(records, key=lambda item: item["path"].encode("utf-8"))
def _image_maps(
installable: Mapping[str, Any], infrastructure_bundle: Mapping[str, Any]
) -> tuple[dict[str, dict[str, str]], dict[str, dict[str, str]]]:
application = {
str(item["environment_key"]): {
"reference": str(item["registry_reference"]),
"digest": str(item["manifest_digest"]),
}
for item in installable.get("images", [])
if isinstance(item, Mapping)
}
infrastructure = {
str(item["environment_key"]): {
"reference": str(item["canonical_reference"]),
"digest": str(item["manifest_digest"]),
}
for item in infrastructure_bundle.get("infrastructure_images", [])
if isinstance(item, Mapping)
}
return application, infrastructure
def _validate_cross_identity(
*,
expected_commit: str,
expected_tag: str,
source_manifest: Mapping[str, Any],
source_manifest_sha256: str,
installable: Mapping[str, Any],
infrastructure_bundle: Mapping[str, Any],
third_party_manifest: Mapping[str, Any],
) -> None:
identities = [
source_manifest.get("candidate"),
installable.get("candidate"),
infrastructure_bundle.get("candidate"),
third_party_manifest.get("candidate"),
]
for identity in identities:
if not isinstance(identity, Mapping):
raise AssemblyError("a package input has no candidate identity")
if identity.get("commit") != expected_commit:
raise AssemblyError("package inputs bind different candidate commits")
if "tag" in identity and identity.get("tag") != expected_tag:
raise AssemblyError("package inputs bind different candidate tags")
if third_party_manifest["candidate"].get("source_manifest_sha256") != source_manifest_sha256:
raise AssemblyError("third-party materials bind a different source manifest")
expected_images: dict[str, tuple[str, str]] = {}
for group in (installable.get("images"), infrastructure_bundle.get("infrastructure_images")):
if not isinstance(group, list):
raise AssemblyError("formal image inventory is missing")
for item in group:
if not isinstance(item, Mapping) or not isinstance(item.get("role"), str):
raise AssemblyError("formal image inventory is invalid")
expected_images[item["role"]] = (
str(item.get("manifest_digest")),
str(item.get("config_digest")),
)
observed_images: dict[str, tuple[str, str]] = {}
raw_images = third_party_manifest["candidate"].get("images")
if not isinstance(raw_images, list):
raise AssemblyError("third-party image inventory is missing")
for item in raw_images:
if not isinstance(item, Mapping) or not isinstance(item.get("role"), str):
raise AssemblyError("third-party image inventory is invalid")
observed_images[item["role"]] = (
str(item.get("manifest_digest")),
str(item.get("config_digest")),
)
if len(expected_images) != 11 or observed_images != expected_images:
raise AssemblyError("third-party materials bind a different eleven-image inventory")
def _preflight(args: argparse.Namespace) -> dict[str, Any]:
repo = _directory(args.repo_root, label="repository root")
if not COMMIT_RE.fullmatch(args.expected_candidate_commit):
raise AssemblyError("expected candidate commit is invalid")
if not args.expected_candidate_tag or len(args.expected_candidate_tag) > 255:
raise AssemblyError("expected candidate tag is invalid")
if not SAFE_ID_RE.fullmatch(args.release_id):
raise AssemblyError("release_id is invalid")
if not PROJECT_RE.fullmatch(args.compose_project_name):
raise AssemblyError("compose project name is invalid")
if not HEX64_RE.fullmatch(args.expected_build_receipt_sha256):
raise AssemblyError("expected build receipt SHA-256 is invalid")
output = args.output_dir
if not output.is_absolute():
raise AssemblyError("output directory must be an absolute path")
output = _absolute(output)
parent = _directory(output.parent, label="output parent")
_assert_outside_repo(output, repo, label="output directory")
if output.exists() or output.is_symlink():
raise AssemblyError("refusing to overwrite an existing output path")
application_root = _directory(args.application_root, label="application artifact root")
infrastructure_root = _directory(args.infrastructure_root, label="infrastructure artifact root")
third_party_input_root = _directory(
args.third_party_input_manifest.parent, label="third-party input root"
)
materials_root = _directory(args.third_party_materials_dir, label="third-party materials root")
for label, root in (
("application artifact root", application_root),
("infrastructure artifact root", infrastructure_root),
("third-party input root", third_party_input_root),
("third-party materials root", materials_root),
):
_assert_outside_repo(root, repo, label=label)
try:
output.relative_to(root)
except ValueError:
pass
else:
raise AssemblyError("output directory must not be inside an input artifact root")
try:
root.relative_to(output)
except ValueError:
pass
else:
raise AssemblyError("input artifact roots must not be inside the output directory")
installable_path = _relative_file(
application_root,
args.installable_manifest,
label="installable release manifest",
)
source_set_path = _relative_file(
infrastructure_root,
args.infrastructure_source_set,
label="infrastructure source set",
)
infrastructure_bundle_path = _relative_file(
infrastructure_root,
args.infrastructure_bundle,
label="infrastructure image bundle",
)
input_manifest_path = _regular_file(
args.third_party_input_manifest,
label="third-party input manifest",
root=third_party_input_root,
)
receipt_path = _regular_file(
args.third_party_verification_receipt,
label="third-party verification receipt",
)
_assert_outside_repo(receipt_path, repo, label="third-party verification receipt")
installable_module = _load_module(INSTALLABLE_TOOL, "yuqei_build05_installable_validator")
infrastructure_module = _load_module(INFRASTRUCTURE_TOOL, "yuqei_build05_infrastructure_validator")
third_party_module = _load_module(THIRD_PARTY_TOOL, "yuqei_build05_third_party_validator")
package_module = _load_module(PACKAGE_TOOL, "yuqei_build05_release_package_validator")
try:
installable = installable_module.validate_installable_release_manifest(
artifact_root=application_root,
manifest_path=installable_path,
expected_receipt_sha256=args.expected_build_receipt_sha256,
repo=repo,
)
except Exception as exc:
raise AssemblyError(f"installable release validation failed: {exc}") from exc
source_set = _read_json(source_set_path, label="infrastructure source set")
included_bundle = _read_json(
infrastructure_bundle_path, label="infrastructure image bundle"
)
try:
recomputed_bundle = infrastructure_module.build_bundle(
artifact_root=infrastructure_root,
source_set=source_set,
application_manifest=installable,
)
except Exception as exc:
raise AssemblyError(f"infrastructure bundle validation failed: {exc}") from exc
if recomputed_bundle != included_bundle:
raise AssemblyError("infrastructure bundle differs from deterministic recomputation")
input_manifest = _read_json(input_manifest_path, label="third-party input manifest")
profile = input_manifest.get("profile")
if profile not in {"internal-hosted", "redistributable"}:
raise AssemblyError("third-party profile is invalid")
try:
recomputed_receipt = third_party_module.verify(
input_manifest_path, materials_root, profile
)
except Exception as exc:
raise AssemblyError(f"third-party materials validation failed: {exc}") from exc
receipt = _read_json(receipt_path, label="third-party verification receipt")
if receipt != recomputed_receipt:
raise AssemblyError("third-party receipt differs from independent recomputation")
materials_manifest_path = _relative_file(
materials_root, "materials-manifest.json", label="third-party materials manifest"
)
materials_manifest = _read_json(
materials_manifest_path, label="third-party materials manifest"
)
receipt_record = installable.get("build_receipt")
if not isinstance(receipt_record, Mapping):
raise AssemblyError("installable manifest has no build receipt")
build_receipt_path = _relative_file(
application_root,
receipt_record.get("path"),
label="trusted build receipt",
)
if _file_sha256(build_receipt_path) != args.expected_build_receipt_sha256:
raise AssemblyError("trusted build receipt raw SHA-256 drifted")
build_receipt = _read_json(build_receipt_path, label="trusted build receipt")
receipt_candidate = build_receipt.get("candidate")
source_record = (
receipt_candidate.get("source_manifest")
if isinstance(receipt_candidate, Mapping)
else None
)
if not isinstance(source_record, Mapping):
raise AssemblyError("trusted build receipt has no source manifest record")
source_manifest_path = _relative_file(
application_root,
source_record.get("path"),
label="release source manifest",
)
source_manifest = _read_json(source_manifest_path, label="release source manifest")
source_manifest_sha256 = _file_sha256(source_manifest_path)
if source_record.get("sha256") != source_manifest_sha256:
raise AssemblyError("build receipt source manifest hash drifted")
_verify_repo(repo, args.expected_candidate_commit, args.expected_candidate_tag)
_validate_cross_identity(
expected_commit=args.expected_candidate_commit,
expected_tag=args.expected_candidate_tag,
source_manifest=source_manifest,
source_manifest_sha256=source_manifest_sha256,
installable=installable,
infrastructure_bundle=included_bundle,
third_party_manifest=materials_manifest,
)
_validate_record_files(infrastructure_root, source_set, label="infrastructure source set")
_validate_record_files(third_party_input_root, input_manifest, label="third-party input")
application_paths = {
_safe_relative(args.installable_manifest, label="installable manifest path")
}
raw_installable_files = installable.get("files")
if not isinstance(raw_installable_files, list):
raise AssemblyError("installable manifest file inventory is missing")
for record in raw_installable_files:
if not isinstance(record, Mapping):
raise AssemblyError("installable manifest file record is invalid")
application_paths.add(
_safe_relative(record.get("path"), label="installable file path")
)
infrastructure_paths = _record_paths(source_set, label="infrastructure source set")
infrastructure_paths.update(
_record_paths(
{"application_images": included_bundle.get("application_images")},
label="infrastructure application-image closure",
)
)
infrastructure_paths.update(
{
_safe_relative(args.infrastructure_source_set, label="infrastructure source-set path"),
_safe_relative(args.infrastructure_bundle, label="infrastructure bundle path"),
}
)
input_manifest_relative = input_manifest_path.relative_to(third_party_input_root).as_posix()
third_party_input_paths = _record_paths(input_manifest, label="third-party input")
third_party_input_paths.add(input_manifest_relative)
return {
"repo": repo,
"output": output,
"output_parent": parent,
"application_root": application_root,
"infrastructure_root": infrastructure_root,
"third_party_input_root": third_party_input_root,
"materials_root": materials_root,
"receipt_path": receipt_path,
"installable_path": installable_path,
"source_manifest_path": source_manifest_path,
"source_manifest_sha256": source_manifest_sha256,
"source_manifest": source_manifest,
"installable": installable,
"infrastructure_bundle": included_bundle,
"source_set_path": source_set_path,
"infrastructure_bundle_path": infrastructure_bundle_path,
"input_manifest_path": input_manifest_path,
"materials_manifest_path": materials_manifest_path,
"package_module": package_module,
"application_paths": application_paths,
"infrastructure_paths": infrastructure_paths,
"third_party_input_paths": third_party_input_paths,
"profile": profile,
}
def _identity_payload(
state: Mapping[str, Any], *, release_id: str, package_module: Any
) -> dict[str, Any]:
application, infrastructure = _image_maps(
state["installable"], state["infrastructure_bundle"]
)
expected_application = set(package_module.APPLICATION_IMAGE_KEYS)
expected_infrastructure = set(package_module.INFRASTRUCTURE_IMAGE_KEYS)
if set(application) != expected_application or set(infrastructure) != expected_infrastructure:
raise AssemblyError("image identity does not cover exactly four application and seven infrastructure images")
return _with_hash(
{
"schema_version": package_module.IMAGE_IDENTITY_SCHEMA_V2,
"release_id": release_id,
"source_commit": state["source_manifest"]["candidate"]["commit"],
"source_manifest_sha256": state["source_manifest_sha256"],
"application_images": application,
"infrastructure_images": infrastructure,
"recovery": {
"strategy": package_module.RECOVERY_STRATEGY_FIRST_RELEASE,
"evidence_status": "runtime_signed_evidence_required",
"first_release_only": True,
"predecessor_package_required": False,
"database_downgrade_allowed": False,
"required_restore_scopes": list(
package_module.FIRST_RELEASE_REQUIRED_RESTORE_SCOPES
),
"required_postgres_databases": list(
package_module.FIRST_RELEASE_REQUIRED_POSTGRES_DATABASES
),
"required_storage_targets": list(
package_module.FIRST_RELEASE_REQUIRED_STORAGE_TARGETS
),
},
},
"identity_payload_sha256",
)
def _rename_noreplace(source: Path, destination: Path) -> None:
if destination.exists() or destination.is_symlink():
raise AssemblyError("refusing to overwrite an existing output path")
if sys.platform.startswith("linux"):
import ctypes
libc = ctypes.CDLL(None, use_errno=True)
renameat2 = getattr(libc, "renameat2", None)
if renameat2 is None:
raise AssemblyError("atomic no-replace directory publication is unavailable")
renameat2.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_uint]
renameat2.restype = ctypes.c_int
result = renameat2(
-100,
os.fsencode(source),
-100,
os.fsencode(destination),
1,
)
if result != 0:
errno_value = ctypes.get_errno()
raise AssemblyError(
f"atomic no-replace publication failed: errno={errno_value}"
)
return
try:
os.rename(source, destination)
except OSError as exc:
raise AssemblyError("atomic no-replace publication failed") from exc
def _assemble(state: Mapping[str, Any], args: argparse.Namespace) -> dict[str, Any]:
output: Path = state["output"]
parent: Path = state["output_parent"]
temporary = Path(tempfile.mkdtemp(prefix=f".{output.name}.partial-", dir=parent))
published = False
try:
application_destination = temporary / "application"
infrastructure_destination = temporary / "infrastructure"
third_party_input_destination = temporary / "third-party/input"
third_party_materials_destination = temporary / "third-party/materials"
_copy_paths(
state["application_root"],
application_destination,
state["application_paths"],
label="application artifact",
)
_copy_paths(
state["infrastructure_root"],
infrastructure_destination,
state["infrastructure_paths"],
label="infrastructure artifact",
)
_copy_paths(
state["third_party_input_root"],
third_party_input_destination,
state["third_party_input_paths"],
label="third-party input",
)
_copy_materials_tree(
state["materials_root"], third_party_materials_destination
)
receipt_destination = temporary / "third-party/verification-receipt.json"
_copy_file_exclusive(state["receipt_path"], receipt_destination)
package_module = state["package_module"]
identity_path = temporary / "image-identity.json"
identity = _identity_payload(
state, release_id=args.release_id, package_module=package_module
)
_write_exclusive(
identity_path,
_canonical_file_bytes(identity),
label="image identity",
)
checksum_path = temporary / "checksums.json"
package_path = temporary / "release-package.json"
records = _files_below(
temporary,
exclude={"checksums.json", "release-package.json"},
)
checksums = _with_hash(
{
"schema_version": package_module.CHECKSUM_SCHEMA,
"release_id": args.release_id,
"files": records,
},
"manifest_payload_sha256",
)
_write_exclusive(
checksum_path,
_canonical_file_bytes(checksums),
label="checksum manifest",
)
installable_relative = (
PurePosixPath("application")
/ PurePosixPath(_safe_relative(args.installable_manifest, label="installable manifest path"))
).as_posix()
source_relative = (
PurePosixPath("application")
/ PurePosixPath(state["source_manifest_path"].relative_to(state["application_root"]).as_posix())
).as_posix()
source_set_relative = (
PurePosixPath("infrastructure")
/ PurePosixPath(_safe_relative(args.infrastructure_source_set, label="infrastructure source-set path"))
).as_posix()
infrastructure_bundle_relative = (
PurePosixPath("infrastructure")
/ PurePosixPath(_safe_relative(args.infrastructure_bundle, label="infrastructure bundle path"))
).as_posix()
input_relative = (
PurePosixPath("third-party/input")
/ PurePosixPath(state["input_manifest_path"].relative_to(state["third_party_input_root"]).as_posix())
).as_posix()
material_manifest_relative = "third-party/materials/materials-manifest.json"
receipt_relative = "third-party/verification-receipt.json"
artifact_paths = {
"release_manifest": source_relative,
"checksum_manifest": "checksums.json",
"image_identity": "image-identity.json",
"installable_manifest": installable_relative,
"infrastructure_source_set": source_set_relative,
"infrastructure_image_bundle": infrastructure_bundle_relative,
"third_party_materials_input": input_relative,
"third_party_materials_manifest": material_manifest_relative,
"third_party_materials_verification_receipt": receipt_relative,
}
artifacts = {
name: {
"path": relative,
"sha256": _file_sha256(
temporary.joinpath(*PurePosixPath(relative).parts)
),
}
for name, relative in artifact_paths.items()
}
package = _with_hash(
{
"schema_version": package_module.PACKAGE_SCHEMA_V2,
"release_id": args.release_id,
"compose_project_name": args.compose_project_name,
"deployment_scope": package_module.DEPLOYMENT_SCOPE,
"deployed_service_set": list(package_module.INSTALL_SERVICES),
"separately_deployed_artifacts": list(
package_module.SEPARATELY_DEPLOYED_IMAGE_KEYS
),
"trusted_build_receipt_sha256": args.expected_build_receipt_sha256,
"artifacts": artifacts,
},
"package_payload_sha256",
)
_write_exclusive(
package_path,
_canonical_file_bytes(package),
label="release package manifest",
)
package_sha256 = _file_sha256(package_path)
try:
validated = package_module.validate_release_package(
temporary,
expected_package_sha256=package_sha256,
repo_root=state["repo"],
)
except Exception as exc:
raise AssemblyError(f"assembled package failed strict revalidation: {exc}") from exc
if (
validated.package_schema_version != package_module.PACKAGE_SCHEMA_V2
or validated.package_sha256 != package_sha256
or len(validated.docker_import_plan) != 11
or validated.recovery_strategy
!= package_module.RECOVERY_STRATEGY_FIRST_RELEASE
):
raise AssemblyError("assembled package strict revalidation returned an unsafe state")
_rename_noreplace(temporary, output)
published = True
return {
"schema_version": RESULT_SCHEMA,
"result": "PASS_ASSEMBLED_AND_REVALIDATED",
"mode": "assemble",
"candidate_commit": args.expected_candidate_commit,
"candidate_tag": args.expected_candidate_tag,
"release_id": args.release_id,
"package_schema_version": package_module.PACKAGE_SCHEMA_V2,
"package_sha256": package_sha256,
"file_count": len(records) + 2,
"image_count": len(validated.docker_import_plan),
"recovery_strategy": validated.recovery_strategy,
"output_dir": str(output),
"apply_performed": False,
"remote_connection_attempted": False,
"claims_not_made": [
"installation",
"migration",
"snapshot capture",
"restore",
"UAT",
"pilot authorization",
"production authorization",
"public release authorization",
],
}
finally:
if not published and temporary.exists():
shutil.rmtree(temporary, ignore_errors=True)
def _parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, required=True)
parser.add_argument("--expected-candidate-commit", required=True)
parser.add_argument("--expected-candidate-tag", required=True)
parser.add_argument("--release-id", required=True)
parser.add_argument("--compose-project-name", required=True)
parser.add_argument("--expected-build-receipt-sha256", required=True)
parser.add_argument("--application-root", type=Path, required=True)
parser.add_argument(
"--installable-manifest", default="installable-release-manifest.json"
)
parser.add_argument("--infrastructure-root", type=Path, required=True)
parser.add_argument(
"--infrastructure-source-set", default="infrastructure-source-set.json"
)
parser.add_argument(
"--infrastructure-bundle", default="infrastructure-image-bundle.json"
)
parser.add_argument("--third-party-input-manifest", type=Path, required=True)
parser.add_argument("--third-party-materials-dir", type=Path, required=True)
parser.add_argument(
"--third-party-verification-receipt", type=Path, required=True
)
parser.add_argument("--output-dir", type=Path, required=True)
parser.add_argument(
"--assemble",
action="store_true",
help="create the package; omission performs read-only preflight only",
)
return parser
def main(argv: Sequence[str] | None = None) -> int:
args = _parser().parse_args(argv)
try:
state = _preflight(args)
if args.assemble:
result = _assemble(state, args)
else:
result = {
"schema_version": RESULT_SCHEMA,
"result": "PASS_READ_ONLY_PREFLIGHT",
"mode": "preflight",
"candidate_commit": args.expected_candidate_commit,
"candidate_tag": args.expected_candidate_tag,
"release_id": args.release_id,
"package_schema_version": state["package_module"].PACKAGE_SCHEMA_V2,
"planned_output_dir": str(state["output"]),
"application_file_count": len(state["application_paths"]),
"infrastructure_file_count": len(state["infrastructure_paths"]),
"third_party_input_file_count": len(state["third_party_input_paths"]),
"third_party_profile": state["profile"],
"apply_performed": False,
"filesystem_output_created": False,
"remote_connection_attempted": False,
}
sys.stdout.buffer.write(_canonical_file_bytes(result))
return 0
except (AssemblyError, OSError, UnicodeError, ValueError) as exc:
sys.stderr.write(f"FAILED_CLOSED: {exc}\n")
return 2
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,276 @@
from __future__ import annotations
import hashlib
import importlib.util
import json
import sys
from pathlib import Path
from types import ModuleType, SimpleNamespace
import pytest
REPO_ROOT = Path(__file__).resolve().parents[2]
SCRIPT_PATH = (
REPO_ROOT / "yuqei-infra/scripts/assemble-build05-v2-package.py"
)
HELPER_PATH = REPO_ROOT / "yuqei-infra/tests/test_release_package_executor.py"
def _load(path: Path, name: str) -> ModuleType:
existing = sys.modules.get(name)
if existing is not None:
return existing
spec = importlib.util.spec_from_file_location(name, path)
assert spec is not None and spec.loader is not None
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
spec.loader.exec_module(module)
return module
orchestrator = _load(SCRIPT_PATH, "yuqei_build05_v2_package_orchestrator_tests")
helpers = _load(HELPER_PATH, "yuqei_build05_v2_package_fixture_helpers")
@pytest.fixture(scope="module")
def release_inputs(tmp_path_factory: pytest.TempPathFactory) -> dict[str, object]:
root = tmp_path_factory.mktemp("build05-v2-orchestrator")
template = helpers._strict_build_template(root)
installable = json.loads(
(template["bundle_root"] / "installable-release-manifest.json").read_text(
encoding="utf-8"
)
)
return {
"root": root,
"application_root": template["bundle_root"],
"infrastructure_root": template["v2_root"],
"repo": template["repo"],
"receipt_sha256": template["receipt_sha256"],
"commit": installable["candidate"]["commit"],
"tag": installable["candidate"]["tag"],
}
def _reviewed_module_loader(inputs: dict[str, object]):
base_infrastructure = helpers.release_package._load_infrastructure_bundle_module()
original_infrastructure_root = Path(inputs["infrastructure_root"])
def fixture_bundle_adapter(*, artifact_root, source_set, application_manifest):
# The shared release-package fixture intentionally validates a modern
# synthetic Docker archive and substitutes the separately validated
# application records. Re-run that adapter against its immutable raw
# fixture root when the assembled copy is independently revalidated.
root = Path(artifact_root)
if root != original_infrastructure_root:
root = original_infrastructure_root
return base_infrastructure.build_bundle(
artifact_root=root,
source_set=source_set,
application_manifest=application_manifest,
)
infrastructure = SimpleNamespace(
__file__=base_infrastructure.__file__,
build_bundle=fixture_bundle_adapter,
)
def load(path: Path, _name: str):
if path.name == "build-installable-release.py":
return helpers.release_package._load_installable_validator_module()
if path.name == "build-infrastructure-image-bundle.py":
return infrastructure
if path.name == "build-third-party-materials.py":
return helpers.release_package._load_third_party_materials_module()
if path.name == "release-package.py":
helpers.release_package._INFRASTRUCTURE_BUNDLE_MODULE = infrastructure
return helpers.release_package
raise AssertionError(f"unexpected reviewed module: {path}")
return load
def _argv(inputs: dict[str, object], output: Path, *, assemble: bool = False) -> list[str]:
infrastructure_root = Path(inputs["infrastructure_root"])
args = [
"--repo-root",
str(inputs["repo"]),
"--expected-candidate-commit",
str(inputs["commit"]),
"--expected-candidate-tag",
str(inputs["tag"]),
"--release-id",
"release-2",
"--compose-project-name",
"yuqei-prod",
"--expected-build-receipt-sha256",
str(inputs["receipt_sha256"]),
"--application-root",
str(inputs["application_root"]),
"--infrastructure-root",
str(infrastructure_root),
"--third-party-input-manifest",
str(infrastructure_root / "third-party-input/input-manifest.json"),
"--third-party-materials-dir",
str(infrastructure_root / "third-party-materials"),
"--third-party-verification-receipt",
str(infrastructure_root / "third-party-verification.json"),
"--output-dir",
str(output),
]
if assemble:
args.append("--assemble")
return args
def _tree_hash(root: Path) -> str:
digest = hashlib.sha256()
for path in sorted(
(item for item in root.rglob("*") if item.is_file()),
key=lambda item: item.relative_to(root).as_posix().encode("utf-8"),
):
relative = path.relative_to(root).as_posix().encode("utf-8")
digest.update(len(relative).to_bytes(8, "big"))
digest.update(relative)
digest.update(hashlib.sha256(path.read_bytes()).digest())
return digest.hexdigest()
def test_default_preflight_is_read_only(
release_inputs: dict[str, object],
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
capsysbinary: pytest.CaptureFixture[bytes],
) -> None:
monkeypatch.setattr(
orchestrator, "_load_module", _reviewed_module_loader(release_inputs)
)
output = tmp_path / "package"
assert orchestrator.main(_argv(release_inputs, output)) == 0
captured = capsysbinary.readouterr()
result = json.loads(captured.out)
assert result["result"] == "PASS_READ_ONLY_PREFLIGHT"
assert result["filesystem_output_created"] is False
assert result["apply_performed"] is False
assert result["remote_connection_attempted"] is False
assert not output.exists()
def test_assemble_creates_one_strict_first_release_package_v2(
release_inputs: dict[str, object],
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
capsysbinary: pytest.CaptureFixture[bytes],
) -> None:
monkeypatch.setattr(
orchestrator, "_load_module", _reviewed_module_loader(release_inputs)
)
output = tmp_path / "package"
assert orchestrator.main(_argv(release_inputs, output, assemble=True)) == 0
result = json.loads(capsysbinary.readouterr().out)
assert result["result"] == "PASS_ASSEMBLED_AND_REVALIDATED"
assert result["package_schema_version"] == "yuqei.release-package.v2"
assert result["image_count"] == 11
assert result["recovery_strategy"] == "first_release_snapshot_restore"
assert result["apply_performed"] is False
assert output.is_dir()
package_path = output / "release-package.json"
assert result["package_sha256"] == helpers._sha(package_path)
validated = helpers.release_package.validate_release_package(
output,
expected_package_sha256=result["package_sha256"],
repo_root=Path(release_inputs["repo"]),
)
assert validated.package_schema_version == helpers.release_package.PACKAGE_SCHEMA_V2
assert validated.recovery_strategy == helpers.release_package.RECOVERY_STRATEGY_FIRST_RELEASE
assert len(validated.docker_import_plan) == 11
def test_existing_output_is_never_overwritten(
release_inputs: dict[str, object],
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
capsysbinary: pytest.CaptureFixture[bytes],
) -> None:
monkeypatch.setattr(
orchestrator, "_load_module", _reviewed_module_loader(release_inputs)
)
output = tmp_path / "package"
assert orchestrator.main(_argv(release_inputs, output, assemble=True)) == 0
capsysbinary.readouterr()
before = _tree_hash(output)
assert orchestrator.main(_argv(release_inputs, output, assemble=True)) == 2
captured = capsysbinary.readouterr()
assert b"refusing to overwrite" in captured.err
assert _tree_hash(output) == before
def test_candidate_mismatch_fails_without_output(
release_inputs: dict[str, object],
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
capsysbinary: pytest.CaptureFixture[bytes],
) -> None:
monkeypatch.setattr(
orchestrator, "_load_module", _reviewed_module_loader(release_inputs)
)
output = tmp_path / "package"
args = _argv(release_inputs, output, assemble=True)
index = args.index("--expected-candidate-commit") + 1
args[index] = "f" * 40
assert orchestrator.main(args) == 2
captured = capsysbinary.readouterr()
assert b"repository HEAD does not match" in captured.err
assert not output.exists()
def test_output_inside_source_repository_is_rejected(
release_inputs: dict[str, object],
monkeypatch: pytest.MonkeyPatch,
capsysbinary: pytest.CaptureFixture[bytes],
) -> None:
monkeypatch.setattr(
orchestrator, "_load_module", _reviewed_module_loader(release_inputs)
)
output = Path(release_inputs["repo"]) / "forbidden-package"
assert orchestrator.main(_argv(release_inputs, output, assemble=True)) == 2
captured = capsysbinary.readouterr()
assert b"outside the source repository" in captured.err
assert not output.exists()
def test_failed_final_revalidation_removes_partial_output(
release_inputs: dict[str, object],
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
capsysbinary: pytest.CaptureFixture[bytes],
) -> None:
monkeypatch.setattr(
orchestrator, "_load_module", _reviewed_module_loader(release_inputs)
)
output = tmp_path / "package"
def reject_package(*_args, **_kwargs):
raise helpers.release_package.ReleasePackageError("simulated final rejection")
monkeypatch.setattr(
helpers.release_package, "validate_release_package", reject_package
)
assert orchestrator.main(_argv(release_inputs, output, assemble=True)) == 2
captured = capsysbinary.readouterr()
assert b"assembled package failed strict revalidation" in captured.err
assert not output.exists()
assert list(tmp_path.glob(".package.partial-*")) == []