Harden source release preparation and record verified security follow-up
This commit is contained in:
@@ -6,12 +6,13 @@ from dataclasses import dataclass
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import runpy
|
||||
import subprocess
|
||||
import tomllib
|
||||
|
||||
from .git_state import collect_versions, sanitized_git_environment
|
||||
from .git_state import collect_versions, registered_developer_meta_path, sanitized_git_environment
|
||||
from .registry_reference import registry_artifact_conflicts, registry_entry_source
|
||||
from .workspace import load_repository_specs, resolve_repo_path
|
||||
from .workspace import META_ROOT, load_repository_specs, resolve_repo_path
|
||||
|
||||
|
||||
_PYTHON_RELEASE_REF = re.compile(
|
||||
@@ -43,6 +44,7 @@ def repository_version_issues(
|
||||
versions = collect_versions(repo_path)
|
||||
declared = {
|
||||
"pyproject.toml": versions.pyproject,
|
||||
"packages/govoplan-meta/pyproject.toml": versions.developer_meta,
|
||||
"package.json": versions.package,
|
||||
"webui/package.json": versions.webui_package,
|
||||
"webui/package.release.json": _json_version(repo_path / "webui" / "package.release.json")
|
||||
@@ -83,6 +85,8 @@ def repository_version_issues(
|
||||
for source, version in declared.items()
|
||||
if version is not None and version != canonical_version
|
||||
]
|
||||
if registered_developer_meta_path(repo_path) is not None:
|
||||
issues.extend(developer_meta_composition_issues(repo_path))
|
||||
|
||||
if expected_version is not None and canonical_version.removeprefix("v") != expected_version.removeprefix("v"):
|
||||
issues.append(
|
||||
@@ -120,6 +124,34 @@ def repository_version_issues(
|
||||
return tuple(issues)
|
||||
|
||||
|
||||
def developer_meta_composition_issues(repo_path: Path) -> tuple[VersionAlignmentIssue, ...]:
|
||||
"""Compare the real nested package with the trusted generator's exact output.
|
||||
|
||||
Never execute a generator from a selected checkout. Only the installed
|
||||
operator tooling provides code; selected TOML/requirements are data inputs.
|
||||
"""
|
||||
package_path = registered_developer_meta_path(repo_path)
|
||||
if package_path is None:
|
||||
return (VersionAlignmentIssue(repo_path.name, "repository", "registered Meta support repository", "", "nested developer-package identity is not registered"),)
|
||||
source = "packages/govoplan-meta/pyproject.toml"
|
||||
try:
|
||||
current = package_path.read_text(encoding="utf-8")
|
||||
project = tomllib.loads(current).get("project")
|
||||
if not isinstance(project, dict) or project.get("name") != "govoplan":
|
||||
return (VersionAlignmentIssue("govoplan", source + ":project.name", "govoplan", str(project.get("name") if isinstance(project, dict) else ""), "developer meta-package identity must be exact"),)
|
||||
# META_ROOT belongs to the running operator tools, not repo_path.
|
||||
generator = runpy.run_path(str(META_ROOT / "tools/release/generate-developer-meta-package.py"))
|
||||
expected = generator["render"](
|
||||
workspace=repo_path.parent,
|
||||
requirements=repo_path / "requirements-release.txt",
|
||||
)
|
||||
except (OSError, UnicodeError, KeyError, ValueError, TypeError) as exc:
|
||||
return (VersionAlignmentIssue("govoplan", source, "readable exact developer composition and Core version", type(exc).__name__, "developer meta-package composition could not be validated"),)
|
||||
if current != expected:
|
||||
return (VersionAlignmentIssue("govoplan", source, "trusted generator output matching Core and release requirements", "stale composition", "developer meta-package must exactly match the generator --check contract"),)
|
||||
return ()
|
||||
|
||||
|
||||
def selected_repository_version_issues(
|
||||
*,
|
||||
repo_versions: dict[str, str],
|
||||
@@ -165,6 +197,11 @@ def selected_repository_version_issues(
|
||||
return tuple(issues)
|
||||
|
||||
|
||||
def selected_webui_repository_names(*, repo_versions: dict[str, str], workspace: Path) -> tuple[str, ...]:
|
||||
"""Identify the exact selections for which Core's WebUI inputs are relevant."""
|
||||
return tuple(repo for repo in sorted(repo_versions) if repo != "govoplan-core" and (workspace / repo / "webui/package.json").exists())
|
||||
|
||||
|
||||
def selected_release_webui_bundle_issues(
|
||||
*,
|
||||
repo_versions: dict[str, str],
|
||||
@@ -177,6 +214,8 @@ def selected_release_webui_bundle_issues(
|
||||
immutable release package input and lockfile will actually install.
|
||||
"""
|
||||
|
||||
if not selected_webui_repository_names(repo_versions=repo_versions, workspace=workspace):
|
||||
return ()
|
||||
core_webui = workspace / "govoplan-core" / "webui"
|
||||
release_package_path = core_webui / "package.release.json"
|
||||
release_lock_path = core_webui / "package-lock.release.json"
|
||||
|
||||
Reference in New Issue
Block a user