#!/usr/bin/env python3
"""BeyondCorp Zero Trust Agent - audits IAP configuration, access levels, and policy bindings."""

import json
import argparse
import logging
import subprocess
from datetime import datetime

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)


def gcloud_json(args_list):
    """Execute gcloud command and return JSON output."""
    cmd = ["gcloud"] + args_list + ["--format=json"]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
    return json.loads(result.stdout) if result.returncode == 0 and result.stdout else []


def list_iap_protected_resources(project):
    """List resources protected by Identity-Aware Proxy."""
    backends = gcloud_json(["compute", "backend-services", "list", "--project", project])
    protected = []
    for backend in backends:
        iap = backend.get("iap", {})
        protected.append({
            "name": backend.get("name", ""),
            "iap_enabled": iap.get("enabled", False),
            "oauth2_client_id": bool(iap.get("oauth2ClientId", "")),
        })
    return protected


def get_access_levels(policy_name):
    """Retrieve Access Context Manager access levels."""
    levels = gcloud_json(["access-context-manager", "levels", "list", "--policy", policy_name])
    parsed = []
    for level in levels:
        basic = level.get("basic", {})
        conditions = basic.get("conditions", [])
        parsed.append({
            "name": level.get("name", "").split("/")[-1],
            "title": level.get("title", ""),
            "combining_function": basic.get("combiningFunction", "AND"),
            "condition_count": len(conditions),
            "has_ip_restriction": any(c.get("ipSubnetworks") for c in conditions),
            "has_device_policy": any(c.get("devicePolicy") for c in conditions),
            "has_region_restriction": any(c.get("regions") for c in conditions),
        })
    return parsed


def audit_iap_iam_bindings(project):
    """Audit IAM bindings on IAP-protected resources."""
    findings = []
    cmd = ["gcloud", "iap", "web", "get-iam-policy", "--project", project, "--format=json"]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
    if result.returncode != 0:
        return [{"issue": "Cannot retrieve IAP IAM policy", "severity": "high"}]
    policy = json.loads(result.stdout) if result.stdout else {}
    for binding in policy.get("bindings", []):
        role = binding.get("role", "")
        members = binding.get("members", [])
        condition = binding.get("condition")
        if role == "roles/iap.httpsResourceAccessor":
            if "allUsers" in members or "allAuthenticatedUsers" in members:
                findings.append({
                    "role": role, "issue": "Public access via allUsers/allAuthenticatedUsers",
                    "severity": "critical",
                    "recommendation": "Restrict to specific user/group identities",
                })
            if not condition:
                findings.append({
                    "role": role, "members": members[:5],
                    "issue": "IAP binding without access level condition",
                    "severity": "high",
                    "recommendation": "Add access level condition for context-aware enforcement",
                })
    return findings


def audit_access_level_strength(access_levels):
    """Audit access levels for security strength."""
    findings = []
    for level in access_levels:
        if not level["has_device_policy"]:
            findings.append({
                "access_level": level["name"],
                "issue": "No device policy requirement",
                "severity": "medium",
                "recommendation": "Add device trust requirements (encryption, screen lock, OS version)",
            })
        if not level["has_ip_restriction"] and not level["has_region_restriction"]:
            findings.append({
                "access_level": level["name"],
                "issue": "No network or geographic restriction",
                "severity": "medium",
                "recommendation": "Consider adding corporate IP range or geo restrictions",
            })
        if level["condition_count"] == 0:
            findings.append({
                "access_level": level["name"],
                "issue": "Empty access level with no conditions",
                "severity": "high",
            })
    return findings


def check_endpoint_verification(project):
    """Check Endpoint Verification deployment status."""
    devices = gcloud_json(["endpoint-verification", "list", "--project", project])
    total = len(devices)
    compliant = sum(1 for d in devices if d.get("complianceState") == "COMPLIANT")
    return {
        "total_devices": total,
        "compliant": compliant,
        "non_compliant": total - compliant,
        "compliance_rate": round(compliant / max(total, 1) * 100, 1),
    }


def generate_report(protected, access_levels, iam_findings, level_findings, endpoint_status):
    iap_enabled = sum(1 for r in protected if r["iap_enabled"])
    all_findings = iam_findings + level_findings
    return {
        "timestamp": datetime.utcnow().isoformat(),
        "framework": "BeyondCorp Enterprise / Zero Trust",
        "iap_protected_resources": len(protected),
        "iap_enabled_count": iap_enabled,
        "iap_coverage": round(iap_enabled / max(len(protected), 1) * 100, 1),
        "access_levels_defined": len(access_levels),
        "access_level_details": access_levels,
        "endpoint_verification": endpoint_status,
        "iam_findings": iam_findings,
        "access_level_findings": level_findings,
        "total_findings": len(all_findings),
        "critical_findings": sum(1 for f in all_findings if f.get("severity") == "critical"),
    }


def main():
    parser = argparse.ArgumentParser(description="BeyondCorp Zero Trust Audit Agent")
    parser.add_argument("--project", required=True, help="GCP project ID")
    parser.add_argument("--access-policy", required=True, help="Access Context Manager policy ID")
    parser.add_argument("--output", default="beyondcorp_audit_report.json")
    args = parser.parse_args()

    protected = list_iap_protected_resources(args.project)
    access_levels = get_access_levels(args.access_policy)
    iam_findings = audit_iap_iam_bindings(args.project)
    level_findings = audit_access_level_strength(access_levels)
    endpoint_status = check_endpoint_verification(args.project)
    report = generate_report(protected, access_levels, iam_findings, level_findings, endpoint_status)
    with open(args.output, "w") as f:
        json.dump(report, f, indent=2, default=str)
    logger.info("BeyondCorp: %.1f%% IAP coverage, %d access levels, %d findings",
                report["iap_coverage"], report["access_levels_defined"], report["total_findings"])
    print(json.dumps(report, indent=2, default=str))


if __name__ == "__main__":
    main()
