#!/usr/bin/env python3
"""Agent for auditing Zscaler Private Access (ZPA) zero trust configuration via API."""

import argparse
import json
import os
import requests
from datetime import datetime, timezone

ZPA_BASE = os.environ.get("ZPA_BASE_URL", "https://config.private.zscaler.com")


def authenticate(client_id, client_secret, customer_id):
    """Authenticate to Zscaler ZPA API."""
    url = f"{ZPA_BASE}/signin"
    payload = {"client_id": client_id, "client_secret": client_secret}
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    resp = requests.post(url, data=payload, headers=headers, timeout=30)
    resp.raise_for_status()
    token = resp.json()["access_token"]
    print("[*] Authenticated to ZPA API")
    return {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}


def list_app_segments(headers, customer_id):
    """List ZPA application segments."""
    url = f"{ZPA_BASE}/mgmtconfig/v1/admin/customers/{customer_id}/application"
    resp = requests.get(url, headers=headers, timeout=30)
    resp.raise_for_status()
    apps = resp.json().get("list", [])
    print(f"\n[*] Application Segments: {len(apps)}")
    findings = []
    for app in apps:
        bypass = app.get("bypassType", "NEVER")
        if bypass != "NEVER":
            findings.append({"name": app["name"], "bypass": bypass, "severity": "HIGH"})
        print(f"  {app['name']} - bypass={bypass}, enabled={app.get('enabled', False)}")
    return apps, findings


def list_server_groups(headers, customer_id):
    """List server groups and their connectors."""
    url = f"{ZPA_BASE}/mgmtconfig/v1/admin/customers/{customer_id}/serverGroup"
    resp = requests.get(url, headers=headers, timeout=30)
    resp.raise_for_status()
    groups = resp.json().get("list", [])
    print(f"\n[*] Server Groups: {len(groups)}")
    for g in groups:
        connectors = g.get("connectors", [])
        print(f"  {g['name']} - {len(connectors)} connectors, enabled={g.get('enabled')}")
    return groups


def list_access_policies(headers, customer_id):
    """List ZPA access policies to verify least-privilege enforcement."""
    url = f"{ZPA_BASE}/mgmtconfig/v1/admin/customers/{customer_id}/policySet/rules"
    resp = requests.get(url, headers=headers, timeout=30)
    resp.raise_for_status()
    rules = resp.json().get("list", [])
    findings = []
    print(f"\n[*] Access Policy Rules: {len(rules)}")
    for r in rules:
        action = r.get("action", "")
        conditions = r.get("conditions", [])
        if action == "ALLOW" and not conditions:
            findings.append({"rule": r.get("name"), "issue": "ALLOW with no conditions",
                             "severity": "CRITICAL"})
            print(f"  [!] {r.get('name')}: ALLOW without conditions")
        else:
            print(f"  {r.get('name')}: action={action}, conditions={len(conditions)}")
    return rules, findings


def check_connector_health(headers, customer_id):
    """Check connector enrollment and health status."""
    url = f"{ZPA_BASE}/mgmtconfig/v1/admin/customers/{customer_id}/connector"
    resp = requests.get(url, headers=headers, timeout=30)
    resp.raise_for_status()
    connectors = resp.json().get("list", [])
    issues = []
    for c in connectors:
        status = c.get("currentVersion", "unknown")
        enabled = c.get("enabled", False)
        if not enabled:
            issues.append({"connector": c.get("name"), "issue": "disabled", "severity": "MEDIUM"})
        print(f"  {c.get('name')}: enabled={enabled}, version={status}")
    print(f"[*] Connectors: {len(connectors)} total, {len(issues)} disabled")
    return connectors, issues


def generate_report(apps, app_findings, policy_findings, connector_issues, output_path):
    """Generate ZPA audit report."""
    report = {
        "audit_date": datetime.now(timezone.utc).isoformat(),
        "summary": {"app_segments": len(apps), "bypass_findings": len(app_findings),
                     "policy_findings": len(policy_findings),
                     "connector_issues": len(connector_issues)},
        "bypass_findings": app_findings, "policy_findings": policy_findings,
        "connector_issues": connector_issues,
    }
    with open(output_path, "w") as f:
        json.dump(report, f, indent=2, default=str)
    print(f"\n[*] Report saved to {output_path}")


def main():
    parser = argparse.ArgumentParser(description="Zscaler ZPA Zero Trust Audit Agent")
    parser.add_argument("action", choices=["apps", "servers", "policies", "connectors", "full-audit"])
    parser.add_argument("--client-id", required=True)
    parser.add_argument("--client-secret", required=True)
    parser.add_argument("--customer-id", required=True)
    parser.add_argument("-o", "--output", default="zpa_audit.json")
    args = parser.parse_args()

    headers = authenticate(args.client_id, args.client_secret, args.customer_id)
    if args.action == "apps":
        list_app_segments(headers, args.customer_id)
    elif args.action == "servers":
        list_server_groups(headers, args.customer_id)
    elif args.action == "policies":
        list_access_policies(headers, args.customer_id)
    elif args.action == "connectors":
        check_connector_health(headers, args.customer_id)
    elif args.action == "full-audit":
        apps, af = list_app_segments(headers, args.customer_id)
        list_server_groups(headers, args.customer_id)
        _, pf = list_access_policies(headers, args.customer_id)
        _, ci = check_connector_health(headers, args.customer_id)
        generate_report(apps, af, pf, ci, args.output)


if __name__ == "__main__":
    main()
