# src/agentsh_secure_sandbox/policies/presets.py
# mypy: disable-error-code="list-item"
"""Built-in policy presets for common use cases.

Mirrors the TypeScript @agentsh/secure-sandbox presets exactly.
Aligned with production agent-default.yaml from agentsh v0.16.9.
"""

from __future__ import annotations

from .merge import merge
from .schema import AuditSettings, EnvPolicy, PolicyDefinition, ResourceLimits


def agent_default(
    extensions: PolicyDefinition | None = None,
) -> PolicyDefinition:
    """Comprehensive policy for AI coding agents.

    This is the DEFAULT policy used when no policy is specified.
    Designed to work with all enforcement modes including
    file_monitor (seccomp/ptrace).
    """
    base = PolicyDefinition(
        file=[
            # --- Deny dangerous binaries (before system read allows them) ---
            {"deny": [
                "/usr/bin/sudo", "/usr/bin/su", "/usr/bin/pkexec", "/usr/bin/doas",
                "/bin/su", "/usr/sbin/chroot", "/usr/bin/nsenter", "/usr/bin/unshare",
            ]},

            # --- Workspace ---
            {"allow": "/workspace/**", "ops": ["read", "write", "create", "open", "stat", "list", "readlink", "mkdir", "chmod", "rename"]},
            {"soft_delete": "/workspace/**"},

            # --- Temp directories (full access) ---
            {"allow": ["/tmp/**", "/var/tmp/**"]},

            # --- System read (libraries, binaries, runtimes, devices) ---
            {"allow": ["/usr/**", "/lib/**", "/lib64/**", "/bin/**", "/sbin/**", "/opt/**", "/dev/**"], "ops": ["read", "open", "stat", "list", "readlink"]},

            # --- Device file writes (safe nodes) ---
            {"allow": [
                "/dev/null", "/dev/zero", "/dev/tty", "/dev/pts/**",
                "/dev/urandom", "/dev/random", "/dev/shm/**",
            ], "ops": ["write", "create", "open"]},

            # --- Sensitive /etc files (deny before /etc read) ---
            {"deny": ["/etc/shadow", "/etc/gshadow", "/etc/sudoers", "/etc/sudoers.d/**"]},

            # --- /etc minimal read ---
            {"allow": [
                "/etc/hosts", "/etc/resolv.conf",
                "/etc/ssl/**", "/etc/ca-certificates/**",
                "/etc/localtime", "/etc/timezone",
                "/etc/ld.so.cache", "/etc/ld.so.preload", "/etc/ld.so.conf", "/etc/ld.so.conf.d/**",
                "/etc/nsswitch.conf", "/etc/passwd", "/etc/group",
                "/etc/mime.types", "/etc/protocols", "/etc/services",
                "/etc/gai.conf",
            ], "ops": ["read", "open", "stat", "readlink"]},

            # --- /proc/self for process introspection ---
            {"allow": ["/proc/self/**", "/proc/thread-self/**"], "ops": ["read", "open", "stat", "list", "readlink"]},

            # --- Package caches (full access for dev workflows) ---
            {"allow": [
                "~/.npm/**", "~/.yarn/**", "~/.pnpm-store/**",
                "~/.cache/**", "~/.cargo/**", "~/go/**",
                "~/.local/**", "~/.rustup/**", "~/.bun/**",
                "/root/.npm/**", "/root/.yarn/**", "/root/.pnpm-store/**",
                "/root/.cache/**", "/root/.cargo/**", "/root/go/**",
                "/root/.local/**", "/root/.rustup/**", "/root/.bun/**",
            ]},

            # --- agentsh runtime ---
            {"allow": ["/var/lib/agentsh/**", "/var/log/agentsh/**"], "ops": ["read", "write", "open", "stat", "list", "readlink"]},

            # --- Secrets and credentials ---
            {"deny": ["**/.env", "**/.env.*", "**/credentials*", "**/*.pem", "**/*.key"]},
            {"deny": ["/workspace/.git/config", "/workspace/.netrc"]},
            {"deny": ["~/.ssh/**", "/proc/*/environ"]},
            {"deny": ["~/.aws/**", "~/.gcp/**", "~/.azure/**", "~/.config/gcloud/**"]},

            # --- Shell config injection (deny writes) ---
            {"deny": [
                "~/.bashrc", "~/.zshrc", "~/.profile", "~/.bash_profile",
                "/root/.bashrc", "/root/.zshrc", "/root/.profile", "/root/.bash_profile",
            ], "ops": ["write", "create"]},
            # --- Hostname config (deny writes) ---
            {"deny": ["/etc/hostname", "/etc/hosts"], "ops": ["write", "create"]},
            # --- Docker socket ---
            {"deny": ["/var/run/docker.sock", "/run/docker.sock"]},
            # --- Credential stores ---
            {"deny": ["~/.gitconfig", "~/.netrc", "~/.curlrc", "~/.wgetrc"]},
            # --- Agent config files (deny writes) ---
            {"deny": ["**/.cursorrules", "**/CLAUDE.md", "**/copilot-instructions.md"], "ops": ["write", "create", "delete"]},

            # --- Sensitive /proc entries ---
            {"deny": ["/proc/self/environ", "/proc/thread-self/environ", "/proc/*/environ", "/proc/*/mem", "/proc/kcore"]},
            # --- Block /proc and /sys writes ---
            {"deny": ["/proc/**", "/sys/**"], "ops": ["write", "create", "chmod", "delete", "rename", "mkdir"]},

            # --- Default deny (catch-all) ---
            {"deny": "**"},
        ],
        network=[
            # LLM providers
            {
                "allow": [
                    "api.anthropic.com", "*.anthropic.com",
                    "api.openai.com", "*.openai.com",
                    "generativelanguage.googleapis.com", "*.googleapis.com",
                ],
                "ports": [443],
            },
            # npm registry
            {
                "allow": ["registry.npmjs.org", "*.npmjs.org", "*.npmjs.com", "registry.yarnpkg.com"],
                "ports": [443, 80],
            },
            # PyPI
            {
                "allow": ["pypi.org", "*.pypi.org", "files.pythonhosted.org"],
                "ports": [443, 80],
            },
            # Cargo registry
            {
                "allow": ["crates.io", "*.crates.io", "static.crates.io", "index.crates.io"],
                "ports": [443, 80],
            },
            # Go module proxy
            {
                "allow": ["proxy.golang.org", "sum.golang.org", "*.golang.org"],
                "ports": [443, 80],
            },
            # Other registries (Maven, RubyGems, Docker, Homebrew)
            {
                "allow": [
                    "repo1.maven.org", "central.maven.org", "*.maven.org",
                    "rubygems.org", "*.rubygems.org",
                    "registry-1.docker.io", "*.docker.io", "*.docker.com",
                    "ghcr.io", "*.ghcr.io",
                    "formulae.brew.sh",
                ],
                "ports": [443, 80],
            },
            # GitHub (HTTPS + SSH)
            {
                "allow": ["github.com", "*.github.com", "*.githubusercontent.com", "api.github.com"],
                "ports": [443, 80, 22],
            },
            # GitLab
            {"allow": ["gitlab.com", "*.gitlab.com"], "ports": [443, 80, 22]},
            # Bitbucket
            {"allow": ["bitbucket.org", "*.bitbucket.org"], "ports": [443, 80, 22]},
            # CDNs
            {
                "allow": ["*.cloudflare.com", "*.cloudfront.net", "cdn.jsdelivr.net", "unpkg.com", "esm.sh"],
                "ports": [443, 80],
            },
            # Localhost
            {"allow_cidrs": ["127.0.0.1/32", "::1/128"]},
            # Block cloud metadata services
            {"deny_cidrs": ["169.254.169.254/32", "100.100.100.200/32"]},
            # Block private networks
            {"deny_cidrs": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "169.254.0.0/16"]},
            # Default deny
            {"deny": "*"},
        ],
        commands=[
            # File operations
            {
                "allow": [
                    "ls", "cat", "head", "tail", "less", "more", "file", "stat",
                    "wc", "du", "df", "touch", "mkdir", "cp", "mv", "ln",
                    "chmod", "rm", "rmdir", "basename", "dirname", "realpath", "readlink",
                ],
            },
            # Search tools
            {
                "allow": [
                    "grep", "rg", "find", "fd", "ag", "ack",
                    "which", "whereis", "type", "locate",
                ],
            },
            # Text processing
            {
                "allow": [
                    "sed", "awk", "tr", "sort", "uniq", "cut", "paste",
                    "tee", "xargs", "jq", "yq", "column", "fmt", "fold",
                    "expand", "unexpand",
                ],
            },
            # Shell interpreters and builtins
            {
                "allow": [
                    "bash", "sh", "zsh", "/bin/bash", "/bin/sh",
                    "env", "printenv", "true", "false", "test", "[",
                    "expr", "seq", "sh.real", "bash.real",
                ],
            },
            # System information
            {
                "allow": [
                    "whoami", "id", "uname", "hostname", "pwd", "date",
                    "echo", "printf", "yes", "sleep", "time", "timeout",
                ],
            },
            # Dev tools and runtimes
            {
                "allow": [
                    "git", "node", "npm", "npx", "yarn", "pnpm", "bun", "deno",
                    "python", "python3", "pip", "pip3", "uv",
                    "go", "cargo", "rustc", "rustup",
                    "make", "cmake", "gcc", "g++", "clang", "clang++", "ld", "ar",
                    "javac", "java", "mvn", "gradle",
                    "ruby", "gem", "bundler",
                    "php", "composer",
                ],
            },
            # Build, test, and lint
            {
                "allow": [
                    "pytest", "jest", "mocha", "vitest",
                    "tsc", "eslint", "prettier",
                    "rubocop", "rspec", "phpunit",
                ],
            },
            # HTTP tools (network rules are the real guard)
            {"allow": ["curl", "wget"]},
            # Containers
            {"allow": ["docker", "docker-compose", "podman"]},
            # Archive and compression
            {"allow": ["tar", "gzip", "gunzip", "zip", "unzip", "bzip2", "xz"]},
            # Miscellaneous utilities
            {
                "allow": [
                    "nohup", "patch", "diff", "bc", "openssl", "ssh-keygen",
                    "base64", "md5sum", "sha256sum",
                    "ps", "top", "htop", "pgrep",
                ],
            },
            # AI coding tools
            {
                "allow": [
                    "claude", "codex", "aider", "copilot", "gh",
                    "agentsh", "agentsh-unixwrap", "agentsh-stub",
                ],
            },
            # Deny raw network tools
            {"deny": ["nc", "ncat", "netcat", "socat", "telnet"]},
            # Deny system administration
            {"deny": ["shutdown", "reboot", "halt", "poweroff", "systemctl", "service", "mount", "umount", "dd", "fdisk", "mkfs"]},
            # Deny privilege escalation
            {"deny": ["sudo", "su", "doas", "chroot", "nsenter", "unshare"]},
            # Deny system package managers (use language-specific managers)
            {"deny": ["apt", "apt-get", "yum", "dnf", "brew"]},
            # Allow-all catch-all (file + network rules are the real enforcement)
            {"allow": "*"},
        ],
        package_rules=[
            # Critical vulnerability = block
            {
                "match": {"finding_type": "vulnerability", "severity": "critical"},
                "action": "block",
                "reason": "Critical vulnerability — review before installing",
            },
            # Known malware = block
            {
                "match": {"finding_type": "malware"},
                "action": "block",
                "reason": "Known malware detected",
            },
            # Typosquat = block
            {
                "match": {"finding_type": "reputation", "reasons": ["typosquat"]},
                "action": "block",
                "reason": "Package flagged as potential typosquat",
            },
            # Medium vulnerability = warn
            {
                "match": {"finding_type": "vulnerability", "severity": "medium"},
                "action": "warn",
                "reason": "Medium vulnerability — review before using",
            },
            # Copyleft licenses = block
            {
                "match": {
                    "finding_type": "license",
                    "license_spdx": {"deny": ["AGPL-3.0-only", "SSPL-1.0"]},
                },
                "action": "block",
                "reason": "Copyleft license incompatible with proprietary code",
            },
            # Package too new = approve (requires human confirmation)
            {
                "match": {
                    "finding_type": "reputation",
                    "reasons": ["package_too_new"],
                },
                "action": "approve",
                "reason": "Package published recently — requires approval",
            },
        ],
        env_policy=EnvPolicy(
            deny=[
                "*_SECRET*",
                "*_PASSWORD*",
                "*_PRIVATE_KEY*",
                "*_API_KEY*",
                "*_ACCESS_KEY*",
                "*_TOKEN",
                "ANTHROPIC_API_KEY",
                "OPENAI_API_KEY",
                "GITHUB_TOKEN",
                "GH_TOKEN",
                "NPM_TOKEN",
                "AWS_SECRET_ACCESS_KEY",
                "AWS_SESSION_TOKEN",
                "GOOGLE_APPLICATION_CREDENTIALS",
            ],
            block_iteration=True,
        ),
        signal_rules=[
            {"name": "allow-self", "signals": ["@all"], "target": {"type": "self"}, "decision": "allow"},
            {"name": "allow-children", "signals": ["@all"], "target": {"type": "children"}, "decision": "allow"},
            {"name": "allow-session", "signals": ["SIGTERM", "SIGINT", "SIGHUP", "SIGUSR1", "SIGUSR2"], "target": {"type": "session"}, "decision": "allow"},
            {"name": "audit-parent", "signals": ["@all"], "target": {"type": "parent"}, "decision": "audit"},
            {"name": "deny-external-fatal", "signals": ["@fatal"], "target": {"type": "external"}, "decision": "deny", "fallback": "audit", "message": "Blocking signal to process outside session"},
            {"name": "deny-system", "signals": ["@all"], "target": {"type": "system"}, "decision": "deny", "fallback": "audit", "message": "Blocking signal to system process"},
        ],
        unix_socket_rules=[
            {"name": "allow-docker-socket", "paths": ["/var/run/docker.sock"], "operations": ["connect"], "decision": "allow"},
            {"name": "deny-system-sockets", "paths": ["/var/run/**"], "operations": ["connect", "bind", "listen", "sendto"], "decision": "deny"},
        ],
        resource_limits=ResourceLimits(
            max_memory_mb=8192,
            cpu_quota_percent=100,
            pids_max=500,
            command_timeout="15m",
            session_timeout="12h",
            idle_timeout="30m",
        ),
        audit_settings=AuditSettings(
            log_allowed=False,
            log_denied=True,
            log_approved=True,
            include_stdout=False,
            include_stderr=True,
        ),
    )
    return merge(base, extensions) if extensions else base


def dev_safe(
    extensions: PolicyDefinition | None = None,
) -> PolicyDefinition:
    """Permissive defaults for local development. Not recommended for production."""
    base = PolicyDefinition(
        file=[
            {"allow": "/workspace/**", "ops": ["read", "write", "create"]},
            {"deny": ["**/.env", "**/.env.*", "**/credentials*", "**/*.pem", "**/*.key"]},
            {"deny": ["~/.ssh/**", "/proc/*/environ"]},
            {"deny": ["~/.aws/**", "~/.gcp/**", "~/.azure/**", "~/.config/gcloud/**"]},
            {"deny": ["~/.bashrc", "~/.zshrc", "~/.profile", "~/.bash_profile"]},
            {"deny": ["~/.gitconfig", "~/.netrc", "~/.curlrc", "~/.wgetrc"]},
        ],
        network=[
            {
                "allow": ["registry.npmjs.org", "registry.yarnpkg.com"],
                "ports": [443],
            },
        ],
        commands=[{"deny": ["env", "printenv", "shutdown", "reboot"]}],
    )
    return merge(base, extensions) if extensions else base


def ci_strict(
    extensions: PolicyDefinition | None = None,
) -> PolicyDefinition:
    """Locked down for CI/CD runners."""
    base = PolicyDefinition(
        file=[
            {"allow": "/workspace/**"},
            {"deny": ["**/.env", "**/.env.*", "**/credentials*", "**/*.pem", "**/*.key"]},
            {"deny": ["~/.aws/**", "~/.gcp/**", "~/.azure/**", "~/.config/gcloud/**"]},
            {"deny": "/**"},
        ],
        network=[
            {
                "allow": [
                    "registry.npmjs.org",
                    "registry.yarnpkg.com",
                    "pypi.org",
                    "files.pythonhosted.org",
                    "crates.io",
                    "static.crates.io",
                    "index.crates.io",
                    "proxy.golang.org",
                    "sum.golang.org",
                ],
                "ports": [443],
            },
            {"deny": "*"},
        ],
        commands=[{"deny": ["env", "printenv", "shutdown", "reboot", "sudo"]}],
    )
    return merge(base, extensions) if extensions else base


def agent_sandbox(
    extensions: PolicyDefinition | None = None,
) -> PolicyDefinition:
    """Maximum restriction for untrusted code. Read-only workspace, no network."""
    base = PolicyDefinition(
        file=[
            {"allow": "/workspace/**", "ops": ["read"]},
            {"deny": "/**"},
        ],
        network=[{"deny": "*"}],
        commands=[{"deny": ["env", "printenv", "sudo", "su", "shutdown", "reboot"]}],
    )
    return merge(base, extensions) if extensions else base
