"""Mechanical security pins (TS-10 / SC-02·03·06).

The audit found the security posture clean; these pins keep it that way — a future
edit that reintroduces a shell, disables TLS verification, or reaches for unsafe
deserialization fails here rather than in review. ruff's bandit-``S`` rules run in
CI too; this is the belt to that suspenders, expressed as a test so it travels
with the code.
"""

from __future__ import annotations

import pathlib

_SRC = pathlib.Path(__file__).resolve().parents[2] / "src" / "mgf" / "uitest_web"
_PY = sorted(_SRC.glob("*.py"))


def _all_source() -> str:
    return "\n".join(p.read_text(encoding="utf-8") for p in _PY)


def test_source_tree_found() -> None:
    assert _PY, f"no source files under {_SRC}"


def test_no_shell_true() -> None:
    assert "shell=True" not in _all_source()


def test_no_tls_verification_disabled() -> None:
    src = _all_source()
    assert "verify=False" not in src
    assert "CERT_NONE" not in src


def test_no_unsafe_deserialization() -> None:
    src = _all_source()
    assert "yaml.load(" not in src  # yaml.safe_load only
    assert "pickle.load" not in src


def test_the_one_subprocess_site_stays_argv_list() -> None:
    # server.py launches the console under test; it MUST stay an argv list with the
    # default shell=False. If this ever grows a shell=True, that is a real finding.
    server = (_SRC / "server.py").read_text(encoding="utf-8")
    assert "subprocess.Popen(" in server
    assert "shell=True" not in server
