fix(release): harden review gate diagnostics

This commit is contained in:
2026-07-22 16:52:27 +02:00
parent 36f662c56f
commit 72f697c341
4 changed files with 409 additions and 52 deletions

View File

@@ -16,11 +16,14 @@ import re
import subprocess
import tempfile
from typing import Any, Iterable
from unittest import mock
from jsonschema import Draft202012Validator, FormatChecker
from jsonschema.exceptions import SchemaError
from govoplan_core.core.module_package_catalog import validate_module_package_catalog
import govoplan_core.core.module_package_catalog as module_package_catalog
from govoplan_release.source_provenance import catalog_source_selection
from govoplan_release.version_alignment import candidate_catalog_version_issues
RELEASE_REF_PATTERN = re.compile(
@@ -74,6 +77,28 @@ def review_capability_fit(
("assessment.release",),
)
)
findings.extend(
Finding(
"blocker",
"catalog_release_metadata",
(
f"{issue.source}: {issue.message}; expected {issue.expected!r}, "
f"found {issue.actual!r}."
),
("assessment.release",),
)
for issue in candidate_catalog_version_issues(catalog)
)
source_selection = catalog_source_selection(catalog)
findings.extend(
Finding(
"blocker",
"catalog_source_provenance",
issue.message,
("assessment.release",),
)
for issue in source_selection.issues
)
expected_keyring_hash = _catalog_keyring_hash(catalog)
actual_keyring_hash = canonical_hash(keyring)
if expected_keyring_hash is None:
@@ -208,6 +233,37 @@ def review_capability_fit(
)
)
selected_version = source_selection.selected_versions.get(repository)
selected_commit = source_selection.selected_commits.get(repository)
assessed_commit = str(module["commit"]).lower()
if (
selected_version == assessed_version
and selected_commit is not None
and not selected_commit.lower().startswith(assessed_commit)
):
changes.append(
{
"module_id": module_id,
"repository": repository,
"kind": "commit_changed",
"assessed_commit": module["commit"],
"catalog_commit": selected_commit,
}
)
changed_repositories.add(repository)
findings.append(
Finding(
"review",
"composition_commit_changed",
(
f"Signed selected-unit provenance for {repository!r} at "
f"{assessed_version!r} points to commit {selected_commit[:12]}, "
f"not assessed commit {module['commit']}."
),
(f"composition.{module_id}",),
)
)
expected_tag = f"v{catalog_version}" if catalog_version else None
catalog_tags = entry["tags"]
if (
@@ -310,12 +366,27 @@ def validate_catalog(
) as handle:
json.dump(catalog, handle)
handle.flush()
return validate_module_package_catalog(
Path(handle.name),
require_trusted=True,
approved_channels=(channel,) if channel else (),
trusted_keys=trusted_keys,
)
# Installer replay state answers whether a catalog may be accepted again
# by one runtime. This read-only assessment instead compares explicit
# inputs, so ambient installer state must not affect its result.
with (
mock.patch.object(
module_package_catalog,
"_configured_sequence_state_path",
return_value=None,
),
mock.patch.object(
module_package_catalog,
"_configured_enforce_sequence",
return_value=False,
),
):
return module_package_catalog.validate_module_package_catalog(
Path(handle.name),
require_trusted=True,
approved_channels=(channel,) if channel else (),
trusted_keys=trusted_keys,
)
def trusted_keys_from_keyring(payload: dict[str, Any]) -> dict[str, str]: