Validate complete Core release bundle sources
Some checks failed
Dependency Audit / dependency-audit (push) Failing after 14s
Security Audit / security-audit (push) Failing after 13s

This commit is contained in:
2026-07-22 22:10:35 +02:00
parent b00d4e55ee
commit dc46bda224
2 changed files with 253 additions and 0 deletions

View File

@@ -1,5 +1,6 @@
from __future__ import annotations
import json
from pathlib import Path
import os
import subprocess
@@ -762,6 +763,141 @@ class ReleaseExecutionTests(unittest.TestCase):
_git_output(cloned["govoplan-core"], "rev-parse", "--abbrev-ref", "HEAD"),
)
def test_catalog_synthesis_adds_exact_core_bundle_dependency(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir:
workspace = Path(temp_dir)
idm_repo, idm_remote = _tagged_repository(
workspace,
repo="govoplan-idm",
bare="idm.git",
version="0.1.8",
)
idm_commit = _git_output(idm_repo, "rev-parse", "v0.1.8^{commit}")
(idm_repo / "pyproject.toml").write_text(
'[project]\nname = "govoplan-idm"\nversion = "0.1.9"\n',
encoding="utf-8",
)
_git(idm_repo, "add", "pyproject.toml")
_git(idm_repo, "commit", "-m", "Next release")
_git(idm_repo, "tag", "-a", "v0.1.9", "-m", "Next release")
_git(idm_repo, "push", "origin", "main", "refs/tags/v0.1.9")
catalog_commit = _git_output(idm_repo, "rev-parse", "v0.1.9^{commit}")
core_repo = workspace / "govoplan-core"
core_remote = workspace / "core.git"
_git(workspace, "init", "--bare", str(core_remote))
_git(workspace, "init", "-b", "main", str(core_repo))
_git(core_repo, "config", "user.name", "Release Test")
_git(core_repo, "config", "user.email", "release@example.test")
(core_repo / "webui").mkdir()
(core_repo / "pyproject.toml").write_text(
'[project]\nname = "govoplan-core"\nversion = "1.0.0"\n',
encoding="utf-8",
)
reference = (
"git+ssh://git@example.test/add-ideas/"
"govoplan-idm.git#v0.1.8"
)
(core_repo / "webui/package.release.json").write_text(
json.dumps(
{
"version": "1.0.0",
"dependencies": {"@govoplan/idm-webui": reference},
}
),
encoding="utf-8",
)
(core_repo / "webui/package-lock.release.json").write_text(
json.dumps(
{
"packages": {
"": {
"version": "1.0.0",
"dependencies": {
"@govoplan/idm-webui": reference,
},
},
"node_modules/@govoplan/idm-webui": {
"version": "0.1.8",
"resolved": f"{reference.rsplit('#', 1)[0]}#{idm_commit}",
},
}
}
),
encoding="utf-8",
)
_git(core_repo, "add", ".")
_git(core_repo, "commit", "-m", "Release")
_git(core_repo, "tag", "-a", "v1.0.0", "-m", "Release")
_git(core_repo, "remote", "add", "origin", str(core_remote))
_git(core_repo, "push", "-u", "origin", "main", "refs/tags/v1.0.0")
specs = (
RepositorySpec(
name="govoplan-core",
category="system",
subtype="kernel",
remote=str(core_remote),
path="govoplan-core",
),
RepositorySpec(
name="govoplan-idm",
category="module",
subtype="platform",
remote=str(idm_remote),
path="govoplan-idm",
),
)
with patch(
"govoplan_release.release_execution.load_repository_specs",
return_value=specs,
):
synthesis = workspace / "synthesis"
synthesis.mkdir()
cloned = _clone_catalog_sources(
source_versions={"govoplan-core": "1.0.0"},
repo_versions={},
source_receipts={},
workspace_root=workspace,
destination=synthesis,
)
newer_synthesis = workspace / "newer-synthesis"
newer_synthesis.mkdir()
cloned_with_newer_catalog_source = _clone_catalog_sources(
source_versions={
"govoplan-core": "1.0.0",
"govoplan-idm": "0.1.9",
},
repo_versions={},
source_receipts={},
workspace_root=workspace,
destination=newer_synthesis,
)
self.assertEqual(
{"govoplan-core", "govoplan-idm"},
set(cloned),
)
self.assertEqual(
idm_commit,
_git_output(cloned["govoplan-idm"], "rev-parse", "HEAD"),
)
self.assertEqual(
catalog_commit,
_git_output(
cloned_with_newer_catalog_source["govoplan-idm"],
"rev-parse",
"HEAD",
),
)
self.assertEqual(
idm_commit,
_git_output(
cloned_with_newer_catalog_source["govoplan-idm"],
"rev-parse",
"v0.1.8^{commit}",
),
)
def _repository_spec(remote: Path) -> RepositorySpec:
return RepositorySpec(

View File

@@ -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]: