Validate complete Core release bundle sources
This commit is contained in:
@@ -7,6 +7,7 @@ import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shutil
|
||||
import signal
|
||||
import stat
|
||||
@@ -76,6 +77,9 @@ DURABLE_REMOTE = "origin"
|
||||
FLATPAK_BUILDER_PROXY = Path("/usr/bin/flatpak-spawn")
|
||||
HOST_BUBBLEWRAP = Path("/usr/bin/bwrap")
|
||||
FLATPAK_HOST_BUS = Path("/run/flatpak/bus")
|
||||
_WEBUI_RELEASE_SOURCE = re.compile(
|
||||
r"/(?P<repo>govoplan-[a-z0-9-]+)\.git#v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)$"
|
||||
)
|
||||
|
||||
|
||||
class ReleaseExecutionError(RuntimeError):
|
||||
@@ -1631,9 +1635,122 @@ def _clone_catalog_sources(
|
||||
tag=f"v{version.removeprefix('v')}",
|
||||
source_root=destination,
|
||||
)
|
||||
_clone_release_bundle_sources(
|
||||
result=result,
|
||||
specs=specs,
|
||||
source_root=destination,
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
def _clone_release_bundle_sources(
|
||||
*,
|
||||
result: dict[str, Path],
|
||||
specs: dict[str, Any],
|
||||
source_root: Path,
|
||||
) -> None:
|
||||
"""Add exact Core bundle dependencies needed only for alignment checks."""
|
||||
|
||||
core = result.get("govoplan-core")
|
||||
if core is None:
|
||||
raise ReleaseExecutionBlocked(
|
||||
"Authenticated catalog composition has no Core source."
|
||||
)
|
||||
package_path = core / "webui" / "package.release.json"
|
||||
lock_path = core / "webui" / "package-lock.release.json"
|
||||
if not package_path.exists() and not lock_path.exists():
|
||||
return
|
||||
package = _read_bounded_release_json(
|
||||
package_path,
|
||||
label="Core release WebUI package",
|
||||
)
|
||||
lock = _read_bounded_release_json(
|
||||
lock_path,
|
||||
label="Core release WebUI lock",
|
||||
)
|
||||
dependencies = package.get("dependencies")
|
||||
lock_packages = lock.get("packages")
|
||||
if not isinstance(dependencies, dict) or not isinstance(lock_packages, dict):
|
||||
raise ReleaseExecutionBlocked(
|
||||
"Core release WebUI dependency metadata is incomplete."
|
||||
)
|
||||
if len(dependencies) > MAX_CATALOG_SOURCE_REPOSITORIES:
|
||||
raise ReleaseExecutionBlocked(
|
||||
"Core release WebUI dependency set exceeds its bound."
|
||||
)
|
||||
for package_name, reference in sorted(dependencies.items()):
|
||||
if not isinstance(package_name, str) or not package_name.startswith(
|
||||
"@govoplan/"
|
||||
):
|
||||
continue
|
||||
match = (
|
||||
_WEBUI_RELEASE_SOURCE.search(reference)
|
||||
if isinstance(reference, str)
|
||||
else None
|
||||
)
|
||||
if match is None:
|
||||
raise ReleaseExecutionBlocked(
|
||||
f"Core release dependency {package_name} has no immutable source tag."
|
||||
)
|
||||
repo = match.group("repo")
|
||||
version = match.group("version")
|
||||
repository = specs.get(repo)
|
||||
if repository is None:
|
||||
raise ReleaseExecutionBlocked(
|
||||
f"Core release dependency {repo} is not registered."
|
||||
)
|
||||
locked = lock_packages.get(f"node_modules/{package_name}")
|
||||
resolved = locked.get("resolved") if isinstance(locked, dict) else None
|
||||
locked_version = locked.get("version") if isinstance(locked, dict) else None
|
||||
commit = (
|
||||
resolved.rsplit("#", 1)[-1]
|
||||
if isinstance(resolved, str) and "#" in resolved
|
||||
else ""
|
||||
)
|
||||
if (
|
||||
locked_version != version
|
||||
or not re.fullmatch(r"[0-9a-f]{40}|[0-9a-f]{64}", commit)
|
||||
):
|
||||
raise ReleaseExecutionBlocked(
|
||||
f"Core release dependency {repo} has no exact lock identity."
|
||||
)
|
||||
if repo not in result:
|
||||
if len(result) >= MAX_CATALOG_SOURCE_REPOSITORIES:
|
||||
raise ReleaseExecutionBlocked(
|
||||
"Release composition source set exceeds its bound."
|
||||
)
|
||||
result[repo] = _checkout_registered_source_tag(
|
||||
repo=repo,
|
||||
source_remote=repository.remote,
|
||||
tag=f"v{version}",
|
||||
source_root=source_root,
|
||||
)
|
||||
observed_type = git_text(
|
||||
result[repo], "cat-file", "-t", f"refs/tags/v{version}"
|
||||
)
|
||||
observed = ref_commit(result[repo], f"refs/tags/v{version}")
|
||||
if observed_type != "tag" or observed != commit:
|
||||
raise ReleaseExecutionBlocked(
|
||||
f"Core release dependency {repo} lock does not match its origin tag."
|
||||
)
|
||||
|
||||
|
||||
def _read_bounded_release_json(path: Path, *, label: str) -> dict[str, Any]:
|
||||
try:
|
||||
encoded = path.read_bytes()
|
||||
except OSError as exc:
|
||||
raise ReleaseExecutionBlocked(f"{label} cannot be read.") from exc
|
||||
if len(encoded) > 4 * 1024 * 1024:
|
||||
raise ReleaseExecutionBlocked(f"{label} exceeds its size limit.")
|
||||
try:
|
||||
payload = json.loads(encoded)
|
||||
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
|
||||
raise ReleaseExecutionBlocked(f"{label} is malformed.") from exc
|
||||
if not isinstance(payload, dict):
|
||||
raise ReleaseExecutionBlocked(f"{label} must be a JSON object.")
|
||||
return payload
|
||||
|
||||
|
||||
def verify_frozen_repository_tag_receipt(
|
||||
*, receipt: dict[str, Any] | None, workspace_root: Path
|
||||
) -> dict[str, Any]:
|
||||
|
||||
Reference in New Issue
Block a user