feat(security): add GitHub private backup evidence gate

This commit is contained in:
ogt
2026-06-26 17:45:00 +08:00
parent 59485d519c
commit 5d6b128854
10 changed files with 1621 additions and 0 deletions

View File

@@ -0,0 +1,171 @@
from __future__ import annotations
import json
from pathlib import Path
import pytest
from src.services.github_target_private_backup_evidence_gate import (
load_latest_github_target_private_backup_evidence_gate,
)
def test_load_latest_github_target_private_backup_evidence_gate_reads_committed_snapshot():
data = load_latest_github_target_private_backup_evidence_gate()
assert data["schema_version"] == "github_target_private_backup_evidence_gate_v1"
assert data["status"] == "blocked_public_visibility_and_safe_credential_evidence_required"
assert data["summary"]["approval_required_target_count"] == 9
assert data["summary"]["public_probe_visible_target_count"] == 4
assert data["summary"]["not_found_or_private_target_count"] == 5
assert data["summary"]["private_backup_verified_count"] == 0
assert data["summary"]["safe_credential_accepted_evidence_count"] == 0
assert data["summary"]["safe_credential_required_count"] == 9
assert data["summary"]["refs_sync_authorized"] is False
assert data["summary"]["public_repo_allowed"] is False
assert data["operation_boundaries"]["read_only_api_allowed"] is True
assert data["operation_boundaries"]["repo_creation_allowed"] is False
assert data["authorization_flags"]["repo_creation_authorized"] is False
assert data["authorization_flags"]["secret_values_collected"] is False
def test_private_backup_gate_rejects_runtime_authorization(tmp_path: Path):
snapshot = _snapshot()
snapshot["authorization_flags"]["refs_sync_authorized"] = True
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="authorization flags"):
load_latest_github_target_private_backup_evidence_gate(tmp_path)
def test_private_backup_gate_rejects_summary_drift(tmp_path: Path):
snapshot = _snapshot()
snapshot["summary"]["private_backup_verified_count"] = 1
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="summary mismatch"):
load_latest_github_target_private_backup_evidence_gate(tmp_path)
def test_private_backup_gate_rejects_public_target_marked_private(tmp_path: Path):
snapshot = _snapshot()
snapshot["targets"][0]["private_backup_verified"] = True
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="private_backup_verified"):
load_latest_github_target_private_backup_evidence_gate(tmp_path)
def test_private_backup_gate_rejects_not_found_as_verified(tmp_path: Path):
snapshot = _snapshot()
snapshot["targets"][1]["visibility_evidence_status"] = "private_verified"
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="not_found_or_private"):
load_latest_github_target_private_backup_evidence_gate(tmp_path)
def _write_snapshot(directory: Path, snapshot: dict) -> None:
(directory / "github-target-private-backup-evidence-gate.snapshot.json").write_text(
json.dumps(snapshot),
encoding="utf-8",
)
def _snapshot() -> dict:
return {
"schema_version": "github_target_private_backup_evidence_gate_v1",
"generated_at": "2026-06-26T00:00:00+00:00",
"status": "blocked_public_visibility_and_safe_credential_evidence_required",
"mode": "read_only_private_backup_evidence_gate",
"source_reviews": {},
"summary": {
"target_decision_count": 3,
"approval_required_target_count": 2,
"approval_package_item_count": 2,
"public_probe_visible_target_count": 1,
"not_found_or_private_target_count": 1,
"private_backup_verified_count": 0,
"private_visibility_evidence_missing_count": 2,
"safe_credential_required_count": 2,
"safe_credential_accepted_evidence_count": 0,
"owner_response_received_count": 0,
"owner_response_accepted_count": 0,
"execution_ready_count": 0,
"blocked_target_count": 2,
"external_scope_target_count": 1,
"forbidden_action_count": 12,
"repo_creation_authorized": False,
"visibility_change_authorized": False,
"refs_sync_authorized": False,
"github_primary_switch_authorized": False,
"workflow_modification_authorized": False,
"workflow_trigger_authorized": False,
"secret_value_collection_allowed": False,
"private_clone_url_collection_allowed": False,
"not_found_or_private_as_absent_allowed": False,
"public_repo_allowed": False,
},
"targets": [
_target("owenhytsai/awoooi", True, "exists", "blocked_public_probe_visible_private_evidence_required"),
_target("owenhytsai/VibeWork", True, "not_found_or_private", "blocked_private_or_absent_not_verified"),
_target("nexu-io/open-design", False, "exists", "external_scope_not_backup_target"),
],
"acceptance_requirements": ["private evidence required"],
"rejection_rules": ["reject secrets"],
"operation_boundaries": {
"read_only_api_allowed": True,
"github_api_write_allowed": False,
"gitea_api_write_allowed": False,
"repo_creation_allowed": False,
"visibility_change_allowed": False,
"refs_sync_allowed": False,
"workflow_modification_allowed": False,
"workflow_trigger_allowed": False,
"github_primary_switch_allowed": False,
"secret_value_collection_allowed": False,
"private_clone_url_collection_allowed": False,
},
"authorization_flags": {
"runtime_execution_authorized": False,
"repo_creation_authorized": False,
"visibility_change_authorized": False,
"refs_sync_authorized": False,
"workflow_modification_authorized": False,
"workflow_trigger_authorized": False,
"github_primary_switch_authorized": False,
"secret_values_collected": False,
},
}
def _target(
repo: str,
approval_required: bool,
probe_status: str,
visibility_status: str,
) -> dict:
return {
"github_repo": repo,
"source_key": repo,
"approval_required": approval_required,
"probe_status": probe_status,
"target_state": probe_status,
"risk": "HIGH",
"visibility_evidence_status": visibility_status,
"private_backup_verified": False,
"private_visibility_owner_evidence_ref": None,
"safe_credential_evidence_status": "missing_safe_credential_metadata",
"safe_credential_evidence_ref": None,
"owner_response_accepted": False,
"refs_sync_ready": False,
"execution_ready": False,
"blockers": ["blocked"],
"evidence_refs": ["docs/security/github-target-decision.snapshot.json"],
"forbidden_actions": ["push_refs"],
"repo_creation_authorized": False,
"visibility_change_authorized": False,
"refs_sync_authorized": False,
"github_primary_switch_authorized": False,
"secret_values_collected": False,
}

View File

@@ -0,0 +1,44 @@
from __future__ import annotations
from fastapi import FastAPI
from fastapi.testclient import TestClient
from src.api.v1.agents import router
def test_github_target_private_backup_evidence_gate_endpoint_returns_committed_snapshot():
app = FastAPI()
app.include_router(router, prefix="/api/v1")
client = TestClient(app)
response = client.get("/api/v1/agents/github-target-private-backup-evidence-gate")
assert response.status_code == 200
data = response.json()
assert data["schema_version"] == "github_target_private_backup_evidence_gate_v1"
assert data["status"] == "blocked_public_visibility_and_safe_credential_evidence_required"
assert data["summary"]["approval_required_target_count"] == 9
assert data["summary"]["public_probe_visible_target_count"] == 4
assert data["summary"]["not_found_or_private_target_count"] == 5
assert data["summary"]["private_backup_verified_count"] == 0
assert data["summary"]["safe_credential_accepted_evidence_count"] == 0
assert data["summary"]["execution_ready_count"] == 0
assert data["summary"]["public_repo_allowed"] is False
assert data["operation_boundaries"]["read_only_api_allowed"] is True
assert data["operation_boundaries"]["repo_creation_allowed"] is False
assert data["operation_boundaries"]["refs_sync_allowed"] is False
assert data["operation_boundaries"]["workflow_trigger_allowed"] is False
assert data["authorization_flags"]["runtime_execution_authorized"] is False
assert data["authorization_flags"]["repo_creation_authorized"] is False
assert data["authorization_flags"]["secret_values_collected"] is False
public_target = next(target for target in data["targets"] if target["github_repo"] == "owenhytsai/awoooi")
assert public_target["visibility_evidence_status"] == (
"blocked_public_probe_visible_private_evidence_required"
)
private_or_absent_target = next(
target for target in data["targets"] if target["github_repo"] == "owenhytsai/VibeWork"
)
assert private_or_absent_target["visibility_evidence_status"] == (
"blocked_private_or_absent_not_verified"
)