feat(assessment): verify installed composition evidence
This commit is contained in:
@@ -17,11 +17,18 @@ for tools_root in (ASSESSMENT_TOOLS_ROOT, RELEASE_TOOLS_ROOT):
|
||||
if str(tools_root) not in sys.path:
|
||||
sys.path.insert(0, str(tools_root))
|
||||
|
||||
from govoplan_assessment import render_review, review_capability_fit # noqa: E402
|
||||
from govoplan_assessment import ( # noqa: E402
|
||||
collect_installed_composition,
|
||||
render_review,
|
||||
review_capability_fit,
|
||||
)
|
||||
from govoplan_assessment.evidence import validate_payload # noqa: E402
|
||||
from govoplan_release.catalog import DEFAULT_PUBLIC_BASE_URL, fetch_json # noqa: E402
|
||||
|
||||
|
||||
TRUSTED_KEYRING_FILE_ENV = "GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE"
|
||||
MAX_ASSESSMENT_INPUT_BYTES = 16 * 1024 * 1024
|
||||
MAX_EVIDENCE_INPUT_BYTES = 4 * 1024 * 1024
|
||||
|
||||
|
||||
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
||||
@@ -71,6 +78,58 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
||||
action="store_true",
|
||||
help="Compare signed metadata without checking local annotated tags.",
|
||||
)
|
||||
installed = parser.add_mutually_exclusive_group()
|
||||
installed.add_argument(
|
||||
"--installed-evidence",
|
||||
type=Path,
|
||||
help="Validate an existing bounded installed-composition evidence document.",
|
||||
)
|
||||
installed.add_argument(
|
||||
"--collect-installed-evidence",
|
||||
type=Path,
|
||||
help=(
|
||||
"Collect the current interpreter's GovOPlaN distributions, write the "
|
||||
"bounded evidence document, and include it in this review. Loading "
|
||||
"module entry points executes installed GovOPlaN manifest factories."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--installed-evidence-schema",
|
||||
type=Path,
|
||||
default=META_ROOT / "docs" / "installed-composition-evidence.schema.json",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--boundary-evidence",
|
||||
type=Path,
|
||||
help=(
|
||||
"Externally issued target/provider/production proof bound to the "
|
||||
"installed-evidence digest."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--boundary-evidence-schema",
|
||||
type=Path,
|
||||
default=META_ROOT / "docs" / "capability-fit-boundary-evidence.schema.json",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--boundary-authority-keyring",
|
||||
type=Path,
|
||||
help=(
|
||||
"Independently provisioned keyring authorizing proof signers for "
|
||||
"specific target/provider/production scopes."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--boundary-authority-keyring-schema",
|
||||
type=Path,
|
||||
default=META_ROOT
|
||||
/ "docs"
|
||||
/ "capability-fit-proof-authority-keyring.schema.json",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verification-time",
|
||||
help="Optional ISO-8601 time for reproducible boundary-proof verification.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--json", action="store_true", help="Print the machine-readable review report."
|
||||
)
|
||||
@@ -88,6 +147,22 @@ def main(argv: list[str] | None = None) -> int:
|
||||
raise SystemExit("--keyring is required with --catalog")
|
||||
if args.public and args.keyring is not None:
|
||||
raise SystemExit("--keyring cannot be combined with --public")
|
||||
if (args.boundary_evidence is None) != (args.boundary_authority_keyring is None):
|
||||
raise SystemExit(
|
||||
"--boundary-evidence and --boundary-authority-keyring are required together"
|
||||
)
|
||||
if args.boundary_evidence is not None and (
|
||||
args.installed_evidence is None and args.collect_installed_evidence is None
|
||||
):
|
||||
raise SystemExit(
|
||||
"--boundary-evidence requires --installed-evidence or --collect-installed-evidence"
|
||||
)
|
||||
if (
|
||||
args.collect_installed_evidence is not None
|
||||
and args.output is not None
|
||||
and args.collect_installed_evidence.resolve() == args.output.resolve()
|
||||
):
|
||||
raise SystemExit("Evidence and review output paths must differ")
|
||||
configured_trusted_keyring = os.getenv(TRUSTED_KEYRING_FILE_ENV, "").strip()
|
||||
trusted_keyring_path = args.trusted_keyring or (
|
||||
Path(configured_trusted_keyring) if configured_trusted_keyring else None
|
||||
@@ -96,8 +171,16 @@ def main(argv: list[str] | None = None) -> int:
|
||||
raise SystemExit(
|
||||
f"--trusted-keyring or ${TRUSTED_KEYRING_FILE_ENV} is required"
|
||||
)
|
||||
assessment = read_object(args.assessment, label="assessment")
|
||||
schema = read_object(args.schema, label="schema")
|
||||
assessment = read_object(
|
||||
args.assessment,
|
||||
label="assessment",
|
||||
max_bytes=MAX_ASSESSMENT_INPUT_BYTES,
|
||||
)
|
||||
schema = read_object(
|
||||
args.schema,
|
||||
label="schema",
|
||||
max_bytes=MAX_ASSESSMENT_INPUT_BYTES,
|
||||
)
|
||||
if args.public:
|
||||
catalog = fetch_public_json(
|
||||
f"{DEFAULT_PUBLIC_BASE_URL}/catalogs/v1/channels/stable.json",
|
||||
@@ -108,13 +191,75 @@ def main(argv: list[str] | None = None) -> int:
|
||||
label="published keyring",
|
||||
)
|
||||
else:
|
||||
catalog = read_object(args.catalog, label="catalog")
|
||||
published_keyring = read_object(args.keyring, label="published keyring")
|
||||
catalog = read_object(
|
||||
args.catalog, label="catalog", max_bytes=MAX_ASSESSMENT_INPUT_BYTES
|
||||
)
|
||||
published_keyring = read_object(
|
||||
args.keyring,
|
||||
label="published keyring",
|
||||
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
|
||||
)
|
||||
trusted_keyring = read_object(
|
||||
trusted_keyring_path,
|
||||
label="trusted keyring",
|
||||
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
|
||||
)
|
||||
|
||||
installed_evidence = None
|
||||
installed_evidence_schema = None
|
||||
if (
|
||||
args.installed_evidence is not None
|
||||
or args.collect_installed_evidence is not None
|
||||
):
|
||||
installed_evidence_schema = read_object(
|
||||
args.installed_evidence_schema,
|
||||
label="installed evidence schema",
|
||||
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
|
||||
)
|
||||
if args.installed_evidence is not None:
|
||||
installed_evidence = read_object(
|
||||
args.installed_evidence,
|
||||
label="installed evidence",
|
||||
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
|
||||
)
|
||||
else:
|
||||
installed_evidence = collect_installed_composition(assessment=assessment)
|
||||
collection_schema_errors = validate_payload(
|
||||
payload=installed_evidence,
|
||||
schema=installed_evidence_schema,
|
||||
)
|
||||
if collection_schema_errors:
|
||||
raise SystemExit(
|
||||
"Collected installed evidence did not satisfy its bounded schema"
|
||||
)
|
||||
write_object(args.collect_installed_evidence, installed_evidence)
|
||||
|
||||
boundary_evidence = None
|
||||
boundary_evidence_schema = None
|
||||
boundary_authority_keyring = None
|
||||
boundary_authority_keyring_schema = None
|
||||
if args.boundary_evidence is not None:
|
||||
boundary_evidence = read_object(
|
||||
args.boundary_evidence,
|
||||
label="boundary evidence",
|
||||
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
|
||||
)
|
||||
boundary_evidence_schema = read_object(
|
||||
args.boundary_evidence_schema,
|
||||
label="boundary evidence schema",
|
||||
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
|
||||
)
|
||||
boundary_authority_keyring = read_object(
|
||||
args.boundary_authority_keyring,
|
||||
label="boundary authority keyring",
|
||||
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
|
||||
)
|
||||
boundary_authority_keyring_schema = read_object(
|
||||
args.boundary_authority_keyring_schema,
|
||||
label="boundary authority keyring schema",
|
||||
max_bytes=MAX_EVIDENCE_INPUT_BYTES,
|
||||
)
|
||||
|
||||
report = review_capability_fit(
|
||||
assessment=assessment,
|
||||
schema=schema,
|
||||
@@ -124,6 +269,13 @@ def main(argv: list[str] | None = None) -> int:
|
||||
workspace_root=None
|
||||
if args.skip_tag_provenance
|
||||
else args.workspace_root.resolve(),
|
||||
installed_evidence=installed_evidence,
|
||||
installed_evidence_schema=installed_evidence_schema,
|
||||
boundary_evidence=boundary_evidence,
|
||||
boundary_evidence_schema=boundary_evidence_schema,
|
||||
boundary_authority_keyring=boundary_authority_keyring,
|
||||
boundary_authority_keyring_schema=boundary_authority_keyring_schema,
|
||||
verification_time=parse_datetime(args.verification_time),
|
||||
)
|
||||
encoded = json.dumps(report, indent=2, sort_keys=True) + "\n"
|
||||
if args.output is not None:
|
||||
@@ -133,18 +285,54 @@ def main(argv: list[str] | None = None) -> int:
|
||||
return {"current": 0, "blocked": 1, "review_required": 2}[report["status"]]
|
||||
|
||||
|
||||
def read_object(path: Path | None, *, label: str) -> dict[str, object]:
|
||||
def read_object(path: Path | None, *, label: str, max_bytes: int) -> dict[str, object]:
|
||||
if path is None:
|
||||
raise SystemExit(f"Missing {label} path")
|
||||
try:
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError) as exc:
|
||||
if path.stat().st_size > max_bytes:
|
||||
raise SystemExit(
|
||||
f"{label.capitalize()} exceeds the {max_bytes}-byte input limit"
|
||||
)
|
||||
with path.open("rb") as handle:
|
||||
encoded = handle.read(max_bytes + 1)
|
||||
if len(encoded) > max_bytes:
|
||||
raise SystemExit(
|
||||
f"{label.capitalize()} exceeds the {max_bytes}-byte input limit"
|
||||
)
|
||||
payload = json.loads(encoded.decode("utf-8"))
|
||||
except (OSError, UnicodeDecodeError, json.JSONDecodeError) as exc:
|
||||
raise SystemExit(f"Could not read {label} {path}: {exc}") from exc
|
||||
if not isinstance(payload, dict):
|
||||
raise SystemExit(f"{label.capitalize()} must be a JSON object: {path}")
|
||||
return payload
|
||||
|
||||
|
||||
def write_object(path: Path | None, payload: dict[str, object]) -> None:
|
||||
if path is None:
|
||||
raise SystemExit("Missing installed evidence output path")
|
||||
encoded = json.dumps(payload, indent=2, sort_keys=True) + "\n"
|
||||
if len(encoded.encode("utf-8")) > MAX_EVIDENCE_INPUT_BYTES:
|
||||
raise SystemExit(
|
||||
"Collected installed evidence exceeds the bounded output limit"
|
||||
)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(encoded, encoding="utf-8")
|
||||
|
||||
|
||||
def parse_datetime(value: str | None):
|
||||
if value is None:
|
||||
return None
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
|
||||
except ValueError as exc:
|
||||
raise SystemExit("--verification-time must be an ISO-8601 timestamp") from exc
|
||||
if parsed.tzinfo is None:
|
||||
raise SystemExit("--verification-time must include a timezone")
|
||||
return parsed
|
||||
|
||||
|
||||
def fetch_public_json(url: str, *, label: str) -> dict[str, object]:
|
||||
result = fetch_json(url)
|
||||
if result.get("ok") is not True or not isinstance(result.get("payload"), dict):
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
"""Repeatable GovOPlaN product-assessment tooling."""
|
||||
|
||||
from .capability_fit import review_capability_fit, render_review
|
||||
from .evidence import collect_installed_composition
|
||||
|
||||
__all__ = ("render_review", "review_capability_fit")
|
||||
__all__ = (
|
||||
"collect_installed_composition",
|
||||
"render_review",
|
||||
"review_capability_fit",
|
||||
)
|
||||
|
||||
@@ -25,6 +25,13 @@ 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
|
||||
|
||||
from .evidence import (
|
||||
BoundaryEvidenceReview,
|
||||
InstalledEvidenceReview,
|
||||
review_boundary_evidence,
|
||||
review_installed_composition,
|
||||
)
|
||||
|
||||
|
||||
RELEASE_REF_PATTERN = re.compile(
|
||||
r"^(?P<channel>[a-z][a-z0-9_-]*)-catalog-(?P<sequence>[0-9]+)$"
|
||||
@@ -49,6 +56,13 @@ def review_capability_fit(
|
||||
published_keyring: dict[str, Any],
|
||||
trusted_keyring: dict[str, Any],
|
||||
workspace_root: Path | None = None,
|
||||
installed_evidence: dict[str, Any] | None = None,
|
||||
installed_evidence_schema: dict[str, Any] | None = None,
|
||||
boundary_evidence: dict[str, Any] | None = None,
|
||||
boundary_evidence_schema: dict[str, Any] | None = None,
|
||||
boundary_authority_keyring: dict[str, Any] | None = None,
|
||||
boundary_authority_keyring_schema: dict[str, Any] | None = None,
|
||||
verification_time: datetime | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Return a secret-free release-drift report for one fit assessment."""
|
||||
|
||||
@@ -68,6 +82,8 @@ def review_capability_fit(
|
||||
local_tag_provenance_attempted=0,
|
||||
local_tag_provenance_expected=0,
|
||||
local_tag_catalog_scope_complete=False,
|
||||
installed_review=None,
|
||||
boundary_review=None,
|
||||
)
|
||||
|
||||
catalog_validation = validate_catalog(
|
||||
@@ -340,11 +356,47 @@ def review_capability_fit(
|
||||
)
|
||||
)
|
||||
|
||||
installed_review = review_installed_composition(
|
||||
assessment=assessment,
|
||||
catalog_entries=catalog_entries,
|
||||
selected_versions=source_selection.selected_versions,
|
||||
selected_commits=source_selection.selected_commits,
|
||||
evidence=installed_evidence,
|
||||
schema=installed_evidence_schema,
|
||||
)
|
||||
findings.extend(
|
||||
Finding(item.severity, item.code, item.message, item.assessment_ids)
|
||||
for item in installed_review.findings
|
||||
)
|
||||
changes.extend(installed_review.changes)
|
||||
changed_repositories.update(installed_review.changed_repositories)
|
||||
|
||||
boundary_review = review_boundary_evidence(
|
||||
assessment=assessment,
|
||||
installed_review=installed_review,
|
||||
evidence=boundary_evidence,
|
||||
evidence_schema=boundary_evidence_schema,
|
||||
authority_keyring=boundary_authority_keyring,
|
||||
authority_keyring_schema=boundary_authority_keyring_schema,
|
||||
verification_time=verification_time,
|
||||
)
|
||||
findings.extend(
|
||||
Finding(item.severity, item.code, item.message, item.assessment_ids)
|
||||
for item in boundary_review.findings
|
||||
)
|
||||
|
||||
review_targets = conclusions_needing_review(
|
||||
assessment=assessment,
|
||||
changed_repositories=changed_repositories,
|
||||
release_changed=assessed_sequence != catalog_sequence,
|
||||
)
|
||||
review_targets = merge_review_targets(
|
||||
review_targets,
|
||||
installed_evidence_review_targets(
|
||||
assessment=assessment,
|
||||
installed_review=installed_review,
|
||||
),
|
||||
)
|
||||
return build_report(
|
||||
assessment=assessment,
|
||||
catalog=catalog,
|
||||
@@ -355,6 +407,8 @@ def review_capability_fit(
|
||||
local_tag_provenance_attempted=local_tag_provenance_attempted,
|
||||
local_tag_provenance_expected=local_tag_provenance_expected,
|
||||
local_tag_catalog_scope_complete=local_tag_catalog_scope_complete,
|
||||
installed_review=installed_review,
|
||||
boundary_review=boundary_review,
|
||||
)
|
||||
|
||||
|
||||
@@ -512,6 +566,7 @@ def catalog_entries_by_id(
|
||||
entries[module_id] = {
|
||||
"module_id": module_id,
|
||||
"repository": catalog_repository(item),
|
||||
"package": catalog_package(item),
|
||||
"version": _text(item.get("version")),
|
||||
"tags": tuple(
|
||||
tag for tag in (catalog_ref_tag(value) for value in refs) if tag
|
||||
@@ -534,6 +589,11 @@ def catalog_repository(entry: dict[str, Any]) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
def catalog_package(entry: dict[str, Any]) -> str | None:
|
||||
package = _text(entry.get("python_package"))
|
||||
return package.split("[", 1)[0].strip() if package else None
|
||||
|
||||
|
||||
def catalog_ref_tag(value: str) -> str | None:
|
||||
match = TAG_PATTERN.search(value)
|
||||
return match.group("tag") if match else None
|
||||
@@ -709,6 +769,51 @@ def conclusions_needing_review(
|
||||
return [targets[key] for key in sorted(targets)]
|
||||
|
||||
|
||||
def installed_evidence_review_targets(
|
||||
*,
|
||||
assessment: dict[str, Any],
|
||||
installed_review: InstalledEvidenceReview,
|
||||
) -> list[dict[str, Any]]:
|
||||
if not installed_review.findings:
|
||||
return []
|
||||
targets: dict[str, dict[str, Any]] = {
|
||||
"assessment.installed_composition": {
|
||||
"id": "assessment.installed_composition",
|
||||
"section": "installed_composition",
|
||||
"reason": "Installed-composition evidence is incomplete, mutable, extra, missing, or inconsistent with the assessed release.",
|
||||
}
|
||||
}
|
||||
components = {
|
||||
str(item.get("module_id")): item
|
||||
for item in assessment.get("composition", [])
|
||||
if isinstance(item, dict)
|
||||
}
|
||||
for module_id in sorted(installed_review.affected_module_ids):
|
||||
component = components.get(module_id)
|
||||
target_id = f"composition.{module_id}"
|
||||
targets[target_id] = {
|
||||
"id": target_id,
|
||||
"section": "composition",
|
||||
"repositories": [component.get("repository")]
|
||||
if component is not None
|
||||
else [],
|
||||
"reason": "The observed installed distribution, manifest, RECORD integrity, or immutable provenance differs from the assessed composition.",
|
||||
}
|
||||
return [targets[key] for key in sorted(targets)]
|
||||
|
||||
|
||||
def merge_review_targets(
|
||||
*groups: Iterable[dict[str, Any]],
|
||||
) -> list[dict[str, Any]]:
|
||||
merged: dict[str, dict[str, Any]] = {}
|
||||
for group in groups:
|
||||
for item in group:
|
||||
item_id = str(item.get("id") or "")
|
||||
if item_id and item_id not in merged:
|
||||
merged[item_id] = item
|
||||
return [merged[key] for key in sorted(merged)]
|
||||
|
||||
|
||||
def build_report(
|
||||
*,
|
||||
assessment: dict[str, Any],
|
||||
@@ -720,6 +825,8 @@ def build_report(
|
||||
local_tag_provenance_attempted: int,
|
||||
local_tag_provenance_expected: int,
|
||||
local_tag_catalog_scope_complete: bool,
|
||||
installed_review: InstalledEvidenceReview | None,
|
||||
boundary_review: BoundaryEvidenceReview | None,
|
||||
) -> dict[str, Any]:
|
||||
finding_list = sorted(
|
||||
findings,
|
||||
@@ -736,7 +843,9 @@ def build_report(
|
||||
)
|
||||
catalog_valid = trusted_signature_valid and published_keyring_valid
|
||||
release_valid = catalog_valid and not any(
|
||||
item.severity in {"blocker", "review"} for item in finding_list
|
||||
item.severity in {"blocker", "review"}
|
||||
and not item.code.startswith(("installed_", "boundary_"))
|
||||
for item in finding_list
|
||||
)
|
||||
tag_provenance_checked = (
|
||||
local_tag_provenance_expected > 0
|
||||
@@ -752,8 +861,54 @@ def build_report(
|
||||
status = "review_required"
|
||||
else:
|
||||
status = "current"
|
||||
installed_scope = (
|
||||
installed_review.proof_scope
|
||||
if installed_review is not None
|
||||
else {
|
||||
"installed_artifacts": {"checked": False, "valid": None},
|
||||
"installed_record_integrity": {"checked": False, "valid": None},
|
||||
"installed_source_provenance": {"checked": False, "valid": None},
|
||||
"runtime_activation": {"checked": False, "valid": None},
|
||||
}
|
||||
)
|
||||
boundary_scope = (
|
||||
boundary_review.proof_scope
|
||||
if boundary_review is not None
|
||||
else {
|
||||
"target_environment": {"checked": False, "valid": None},
|
||||
"external_providers": {"checked": False, "valid": None},
|
||||
"production_approval": {"checked": False, "valid": None},
|
||||
}
|
||||
)
|
||||
proof_scope = {
|
||||
"assessment_schema": {"checked": True, "valid": schema_valid},
|
||||
"catalog_signature_and_keyring": {
|
||||
"checked": catalog_checked,
|
||||
"valid": catalog_valid if catalog_checked else None,
|
||||
},
|
||||
"catalog_signature_and_trusted_keyring": {
|
||||
"checked": catalog_checked,
|
||||
"valid": trusted_signature_valid if catalog_checked else None,
|
||||
},
|
||||
"published_keyring_hash": {
|
||||
"checked": catalog_checked,
|
||||
"valid": published_keyring_valid if catalog_checked else None,
|
||||
},
|
||||
"release_metadata": {
|
||||
"checked": catalog_checked,
|
||||
"valid": release_valid if catalog_checked else None,
|
||||
},
|
||||
"local_tag_provenance": {
|
||||
"checked": tag_provenance_checked,
|
||||
"valid": tag_provenance_valid if tag_provenance_checked else None,
|
||||
"attempted_count": local_tag_provenance_attempted,
|
||||
"expected_count": local_tag_provenance_expected,
|
||||
},
|
||||
**installed_scope,
|
||||
**boundary_scope,
|
||||
}
|
||||
return {
|
||||
"report_version": "0.1.0",
|
||||
"report_version": "0.2.0",
|
||||
"status": status,
|
||||
"assessment_id": assessment.get("assessment_id"),
|
||||
"assessment_release": assessment.get("release", {}).get("ref")
|
||||
@@ -764,35 +919,7 @@ def build_report(
|
||||
"sequence": catalog.get("sequence"),
|
||||
"generated_at": catalog.get("generated_at"),
|
||||
},
|
||||
"proof_scope": {
|
||||
"assessment_schema": {"checked": True, "valid": schema_valid},
|
||||
"catalog_signature_and_keyring": {
|
||||
"checked": catalog_checked,
|
||||
"valid": catalog_valid if catalog_checked else None,
|
||||
},
|
||||
"catalog_signature_and_trusted_keyring": {
|
||||
"checked": catalog_checked,
|
||||
"valid": trusted_signature_valid if catalog_checked else None,
|
||||
},
|
||||
"published_keyring_hash": {
|
||||
"checked": catalog_checked,
|
||||
"valid": published_keyring_valid if catalog_checked else None,
|
||||
},
|
||||
"release_metadata": {
|
||||
"checked": catalog_checked,
|
||||
"valid": release_valid if catalog_checked else None,
|
||||
},
|
||||
"local_tag_provenance": {
|
||||
"checked": tag_provenance_checked,
|
||||
"valid": tag_provenance_valid if tag_provenance_checked else None,
|
||||
"attempted_count": local_tag_provenance_attempted,
|
||||
"expected_count": local_tag_provenance_expected,
|
||||
},
|
||||
"installed_artifacts": {"checked": False, "valid": None},
|
||||
"target_environment": {"checked": False, "valid": None},
|
||||
"external_providers": {"checked": False, "valid": None},
|
||||
"production_approval": {"checked": False, "valid": None},
|
||||
},
|
||||
"proof_scope": proof_scope,
|
||||
"findings": [asdict(item) for item in finding_list],
|
||||
"changes": sorted(
|
||||
changes,
|
||||
@@ -803,11 +930,22 @@ def build_report(
|
||||
|
||||
|
||||
def render_review(report: dict[str, Any]) -> str:
|
||||
installed_checked = (
|
||||
report.get("proof_scope", {}).get("installed_artifacts", {}).get("checked")
|
||||
is True
|
||||
)
|
||||
lines = [
|
||||
f"Capability fit rerun: {report['status']}",
|
||||
f"Assessment: {report.get('assessment_id') or '-'} ({report.get('assessment_release') or '-'})",
|
||||
f"Catalog: {report['catalog'].get('channel') or '-'} sequence {report['catalog'].get('sequence') or '-'}",
|
||||
"Scope: schema, signed release metadata, and optional local tag provenance only.",
|
||||
(
|
||||
"Scope: schema, signed release metadata, optional local tag provenance, "
|
||||
+ (
|
||||
"and supplied installed-composition evidence."
|
||||
if installed_checked
|
||||
else "and no installed-composition evidence."
|
||||
)
|
||||
),
|
||||
]
|
||||
findings = report.get("findings") or []
|
||||
if findings:
|
||||
@@ -822,9 +960,23 @@ def render_review(report: dict[str, Any]) -> str:
|
||||
if targets:
|
||||
lines.append("Conclusions requiring review:")
|
||||
lines.extend(f"- {item['id']}: {item['reason']}" for item in targets)
|
||||
lines.append(
|
||||
"No installed-artifact, target-provider, or production proof was performed."
|
||||
)
|
||||
unchecked_boundaries = [
|
||||
label
|
||||
for key, label in (
|
||||
("target_environment", "target-environment"),
|
||||
("external_providers", "external-provider"),
|
||||
("production_approval", "production-approval"),
|
||||
)
|
||||
if report.get("proof_scope", {}).get(key, {}).get("checked") is not True
|
||||
]
|
||||
if not installed_checked:
|
||||
unchecked_boundaries.insert(0, "installed-artifact")
|
||||
if not installed_checked and len(unchecked_boundaries) == 4:
|
||||
lines.append(
|
||||
"No installed-artifact, target-provider, or production proof was performed."
|
||||
)
|
||||
elif unchecked_boundaries:
|
||||
lines.append("No " + ", ".join(unchecked_boundaries) + " proof was performed.")
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
|
||||
1322
tools/assessments/govoplan_assessment/evidence.py
Normal file
1322
tools/assessments/govoplan_assessment/evidence.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user