From 3dcb67ffb69186e9f784db4f4370005cbd4aff28 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 27 Jun 2026 12:13:48 +0800 Subject: [PATCH] feat(github): expose owner private backup readback summary --- .../github_target_private_backup_evidence_gate.py | 15 +++++++++++++++ ..._github_target_private_backup_evidence_gate.py | 2 ++ 2 files changed, 17 insertions(+) diff --git a/apps/api/src/services/github_target_private_backup_evidence_gate.py b/apps/api/src/services/github_target_private_backup_evidence_gate.py index 839bd3517..51935638d 100644 --- a/apps/api/src/services/github_target_private_backup_evidence_gate.py +++ b/apps/api/src/services/github_target_private_backup_evidence_gate.py @@ -60,6 +60,7 @@ def build_github_target_private_backup_evidence_gate( ) -> dict[str, Any]: """Build the read-only gate response from source-control snapshots.""" connector_payload = _dict(connector_readback) + owner_readback = _dict(connector_payload.get("owner_readback")) decisions = [_dict(row) for row in _list(decision.get("decisions"))] probe_by_repo = { str(row.get("github_repo")): _dict(row) @@ -129,6 +130,12 @@ def build_github_target_private_backup_evidence_gate( "target_decision_count": len(targets), "approval_required_target_count": len(approval_required_targets), "approval_package_item_count": len(_list(approval_package.get("approval_items"))), + "github_connector_owner_visible_repository_count": _int( + owner_readback.get("visible_repository_count") + ), + "github_connector_owner_visible_private_repository_count": _int( + owner_readback.get("visible_private_repository_count") + ), "github_connector_readback_count": len(_list(connector_payload.get("targets"))), "github_connector_private_visibility_count": sum( 1 @@ -366,9 +373,16 @@ def _require_approval_package_consistency(payload: dict[str, Any], label: str) - def _require_connector_readback_consistency(payload: dict[str, Any], label: str) -> None: summary = _dict(payload.get("summary")) + owner_readback = _dict(payload.get("owner_readback")) targets = [_dict(row) for row in _list(payload.get("targets"))] if _int(summary.get("target_count")) != len(targets): raise ValueError(f"{label}: summary.target_count must equal targets length") + if owner_readback: + visible_repositories = _list(owner_readback.get("visible_repositories")) + if _int(owner_readback.get("visible_repository_count")) != len(visible_repositories): + raise ValueError(f"{label}: owner visible repository count must match visible repositories") + if _int(owner_readback.get("visible_private_repository_count")) > len(visible_repositories): + raise ValueError(f"{label}: owner private repository count cannot exceed visible repositories") private_count = sum(1 for row in targets if row.get("private_visibility_verified") is True) not_found_count = sum(1 for row in targets if row.get("readback_status") == "not_found_or_inaccessible") if _int(summary.get("private_visibility_verified_count")) != private_count: @@ -383,6 +397,7 @@ def _require_connector_readback_consistency(payload: dict[str, Any], label: str) "secret_values_collected", } enabled = sorted(flag for flag in false_flags if summary.get(flag) is not False) + enabled.extend(sorted(flag for flag in false_flags if owner_readback and owner_readback.get(flag) is not False)) if enabled: raise ValueError(f"{label}: connector readback must remain read-only: {enabled}") diff --git a/apps/api/tests/test_github_target_private_backup_evidence_gate.py b/apps/api/tests/test_github_target_private_backup_evidence_gate.py index 102127997..7dfbb3159 100644 --- a/apps/api/tests/test_github_target_private_backup_evidence_gate.py +++ b/apps/api/tests/test_github_target_private_backup_evidence_gate.py @@ -20,6 +20,8 @@ def test_load_github_target_private_backup_evidence_gate_from_committed_snapshot assert snapshot["status"] == "blocked_private_visibility_and_safe_credential_evidence_required" assert snapshot["summary"]["target_decision_count"] == 10 assert snapshot["summary"]["approval_required_target_count"] == 9 + assert snapshot["summary"]["github_connector_owner_visible_repository_count"] == 4 + assert snapshot["summary"]["github_connector_owner_visible_private_repository_count"] == 4 assert snapshot["summary"]["github_connector_readback_count"] == 9 assert snapshot["summary"]["github_connector_private_visibility_count"] == 4 assert snapshot["summary"]["github_connector_not_found_or_inaccessible_count"] == 5