"""Other device-isolation checks (MALWARE_ANALYSIS.md §5.8, 3 checks).

- :func:`device_no_tpm_passthrough` — no ``<tpm>`` in passthrough
  mode (emulated TPM is fine).
- :func:`device_no_vhost_vsock` — no ``<vsock>`` device (host↔guest
  socket channel; bidirectional pipe).
- :func:`device_vhost_net_disabled` — virtio-net interfaces use
  ``<driver name='qemu'/>`` not ``name='vhost'``. vhost_net runs
  in the kernel — historical CVE surface; userspace virtio-net
  is slower but smaller attack surface.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from mgf.vm.core.security.isolation.checks._helpers import finding
from mgf.vm.core.security.isolation.types import (
    FixKind,
    IsolationCategory,
    IsolationFinding,
    isolation_check,
)

if TYPE_CHECKING:
    from mgf.vm.core.security.isolation.context import AnalysisContext


__all__ = [
    "device_no_tpm_passthrough",
    "device_no_vhost_vsock",
    "device_vhost_net_disabled",
]


@isolation_check
def device_no_tpm_passthrough(ctx: AnalysisContext) -> IsolationFinding:
    """No ``<tpm>`` element in passthrough mode."""
    bad: list[str] = []
    for tpm in ctx.find_devices("tpm"):
        backend = tpm.find("backend")
        backend_type = backend.get("type", "") if backend is not None else ""
        if backend_type == "passthrough":
            bad.append(backend.get("path", "") if backend is not None else "")

    return finding(
        fid="device.no_tpm_passthrough",
        title="No host TPM passed through",
        category=IsolationCategory.BLOCKING,
        fix_kind=FixKind.AUTO_FIX,
        passing=not bad,
        summary_pass="no <tpm backend type='passthrough'> declared",
        summary_fail=(
            f"{len(bad)} TPM passthrough(s) — guest can use host's "
            f"hardware TPM (and read its NVRAM): {bad}"
        ),
        details={"paths": bad},
        fix_executor="device.strip_tpm_passthrough",
    )


@isolation_check
def device_no_vhost_vsock(ctx: AnalysisContext) -> IsolationFinding:
    """No ``<vsock>`` device.

    vsock is a guest↔host socket channel — bidirectional pipe;
    even when the host doesn't bind to it, the guest can probe
    for listeners (CID 2 = host).
    """
    vsocks = ctx.find_devices("vsock")
    return finding(
        fid="device.no_vhost_vsock",
        title="No vhost_vsock channel",
        category=IsolationCategory.BLOCKING,
        fix_kind=FixKind.AUTO_FIX,
        passing=not vsocks,
        summary_pass="no <vsock> element",
        summary_fail=(f"{len(vsocks)} <vsock> element(s) — guest↔host socket channel via CID 2"),
        details={
            "cids": [cid.get("address", "") for v in vsocks if (cid := v.find("cid")) is not None],
        },
        fix_executor="strip.vsock",
    )


@isolation_check
def device_vhost_net_disabled(ctx: AnalysisContext) -> IsolationFinding:
    """Every NIC's driver is qemu (userspace), not vhost (kernel).

    vhost_net runs the network datapath in the kernel for speed.
    Historical CVE surface (e.g., CVE-2019-14835); userspace
    virtio-net keeps the datapath in qemu's process (covered by
    AppArmor). Slower, but smaller blast radius if the driver has
    a vulnerability.
    """
    bad_aliases: list[str] = []
    for iface in ctx.find_devices("interface"):
        driver = iface.find("driver")
        if driver is None:
            continue
        name = driver.get("name", "")
        if name == "vhost":
            alias = iface.find("alias")
            bad_aliases.append(alias.get("name", "?") if alias is not None else "?")

    return finding(
        fid="device.vhost_net_disabled",
        title="vhost_net disabled (userspace virtio-net)",
        category=IsolationCategory.ADVISORY,
        fix_kind=FixKind.AUTO_FIX,
        passing=not bad_aliases,
        summary_pass=("no <interface><driver name='vhost'/> declared (qemu userspace by default)"),
        summary_fail=(f"{len(bad_aliases)} interface(s) using vhost_net: {bad_aliases}"),
        details={"aliases": bad_aliases},
        fix_executor="device.swap_vhost_to_qemu",
    )
