"""Tests for mount_security module."""

from __future__ import annotations

import json

import pytest

from openjarvis.sandbox.mount_security import (
    DEFAULT_BLOCKED_PATTERNS,
    AllowedRoot,
    MountAllowlist,
    load_mount_allowlist,
    validate_mount,
    validate_mounts,
)


class TestDefaultBlockedPatterns:
    def test_contains_ssh(self):
        assert ".ssh" in DEFAULT_BLOCKED_PATTERNS

    def test_contains_env(self):
        assert ".env" in DEFAULT_BLOCKED_PATTERNS

    def test_contains_pem(self):
        assert "*.pem" in DEFAULT_BLOCKED_PATTERNS

    def test_contains_key(self):
        assert "*.key" in DEFAULT_BLOCKED_PATTERNS

    def test_contains_gnupg(self):
        assert ".gnupg" in DEFAULT_BLOCKED_PATTERNS

    def test_contains_aws(self):
        assert ".aws" in DEFAULT_BLOCKED_PATTERNS

    def test_contains_credentials(self):
        assert "credentials" in DEFAULT_BLOCKED_PATTERNS


class TestValidateMount:
    def test_allows_valid_path(self, tmp_path):
        allowlist = MountAllowlist(
            roots=[AllowedRoot(path=str(tmp_path))],
        )
        target = tmp_path / "data"
        target.mkdir()
        assert validate_mount(str(target), allowlist) is True

    def test_blocks_ssh_dir(self, tmp_path):
        allowlist = MountAllowlist(
            roots=[AllowedRoot(path=str(tmp_path))],
        )
        target = tmp_path / ".ssh"
        target.mkdir()
        assert validate_mount(str(target), allowlist) is False

    def test_blocks_env_file(self, tmp_path):
        allowlist = MountAllowlist(
            roots=[AllowedRoot(path=str(tmp_path))],
        )
        target = tmp_path / ".env"
        target.touch()
        assert validate_mount(str(target), allowlist) is False

    def test_blocks_pem_file(self, tmp_path):
        allowlist = MountAllowlist(
            roots=[AllowedRoot(path=str(tmp_path))],
        )
        target = tmp_path / "server.pem"
        target.touch()
        assert validate_mount(str(target), allowlist) is False

    def test_blocks_key_file(self, tmp_path):
        allowlist = MountAllowlist(
            roots=[AllowedRoot(path=str(tmp_path))],
        )
        target = tmp_path / "private.key"
        target.touch()
        assert validate_mount(str(target), allowlist) is False

    def test_rejects_outside_root(self, tmp_path):
        allowlist = MountAllowlist(
            roots=[AllowedRoot(path=str(tmp_path / "allowed"))],
        )
        target = tmp_path / "not_allowed" / "data"
        target.mkdir(parents=True)
        assert validate_mount(str(target), allowlist) is False

    def test_no_roots_allows_non_blocked(self, tmp_path):
        allowlist = MountAllowlist(roots=[])
        target = tmp_path / "safe_dir"
        target.mkdir()
        assert validate_mount(str(target), allowlist) is True

    def test_traversal_prevention(self, tmp_path):
        """Paths with .. are resolved before checking."""
        allowed = tmp_path / "allowed"
        allowed.mkdir()
        # This resolves to tmp_path (outside allowed)
        traversal = str(allowed / ".." / "secret")
        allowlist = MountAllowlist(
            roots=[AllowedRoot(path=str(allowed))],
            blocked_patterns=["secret"],
        )
        assert validate_mount(traversal, allowlist) is False


class TestValidateMounts:
    def test_returns_valid_mounts(self, tmp_path):
        d1 = tmp_path / "data1"
        d2 = tmp_path / "data2"
        d1.mkdir()
        d2.mkdir()
        allowlist = MountAllowlist(
            roots=[AllowedRoot(path=str(tmp_path))],
        )
        result = validate_mounts([str(d1), str(d2)], allowlist)
        assert len(result) == 2

    def test_raises_for_blocked(self, tmp_path):
        target = tmp_path / ".ssh"
        target.mkdir()
        allowlist = MountAllowlist(
            roots=[AllowedRoot(path=str(tmp_path))],
        )
        with pytest.raises(ValueError, match="blocked"):
            validate_mounts([str(target)], allowlist)

    def test_raises_for_outside_root(self, tmp_path):
        target = tmp_path / "outside"
        target.mkdir()
        allowlist = MountAllowlist(
            roots=[AllowedRoot(path=str(tmp_path / "inside"))],
        )
        with pytest.raises(ValueError, match="not under"):
            validate_mounts([str(target)], allowlist)

    def test_empty_list(self):
        allowlist = MountAllowlist()
        assert validate_mounts([], allowlist) == []


class TestLoadMountAllowlist:
    def test_loads_from_json(self, tmp_path):
        config = {
            "roots": [
                {"path": "/home/user/projects", "read_only": False},
                {"path": "/data"},
            ],
            "blocked_patterns": [".ssh", "*.pem"],
        }
        f = tmp_path / "allowlist.json"
        f.write_text(json.dumps(config))

        al = load_mount_allowlist(str(f))
        assert len(al.roots) == 2
        assert al.roots[0].path == "/home/user/projects"
        assert al.roots[0].read_only is False
        assert al.roots[1].read_only is True
        assert al.blocked_patterns == [".ssh", "*.pem"]

    def test_default_blocked_patterns(self, tmp_path):
        config = {"roots": []}
        f = tmp_path / "allowlist.json"
        f.write_text(json.dumps(config))

        al = load_mount_allowlist(str(f))
        assert al.blocked_patterns == DEFAULT_BLOCKED_PATTERNS
