"""SC-* negative-pattern pins (TS-10).

A grep-style guard over ``src/mgf/common`` so a future change cannot
reintroduce a forbidden-by-SECURITY.md pattern (shell injection, unsafe
deserialisation, weak crypto) without a test going red. This is the
"forbidden pattern absent in src" half of TS-10 / SECURITY.md §15; the
positive behaviour (redaction, constant-time compares, KDF) is pinned by
the vault + redaction suites.
"""

from __future__ import annotations

import re
from pathlib import Path

_PKG = Path(__file__).resolve().parents[3] / "src" / "mgf" / "common"
_SRC_ROOT = _PKG.parents[2]  # the `src` dir, for tidy relative paths


def _src_files() -> list[Path]:
    return [p for p in _PKG.rglob("*.py") if "__pycache__" not in p.parts]


def _grep(pattern: str, *, allow_noqa: str | None = None) -> list[str]:
    """Lines in package source matching ``pattern``. Lines carrying a
    ``# noqa: <allow_noqa>`` suppression (an intentional, reviewed use) are
    excluded."""
    rx = re.compile(pattern)
    hits: list[str] = []
    for p in _src_files():
        for i, line in enumerate(p.read_text(encoding="utf-8").splitlines(), 1):
            if not rx.search(line):
                continue
            if allow_noqa and f"noqa: {allow_noqa}" in line:
                continue
            hits.append(f"{p.relative_to(_SRC_ROOT)}:{i}")
    return hits


class TestNoShellInjection:
    def test_no_shell_true(self) -> None:  # SC-02
        assert _grep(r"shell\s*=\s*True") == []

    def test_no_os_system(self) -> None:  # SC-02
        assert _grep(r"\bos\.system\s*\(") == []


class TestSafeDeserialisation:
    def test_yaml_safe_load_only(self) -> None:  # SC-03
        # `yaml.load(` is forbidden; `yaml.safe_load(` is the only allowed form.
        assert _grep(r"yaml\.load\s*\(") == []

    def test_no_pickle(self) -> None:  # SC-03
        assert _grep(r"\bpickle\.(load|loads)\s*\(") == []

    def test_no_eval_exec(self) -> None:  # SC-03
        assert _grep(r"(?<![.\w])eval\s*\(") == []
        assert _grep(r"(?<![.\w])exec\s*\(") == []


class TestCryptoChoices:
    def test_no_weak_crypto_hash(self) -> None:  # SC-05
        # md5/sha1 are forbidden for SECURITY purposes; a non-crypto use
        # (e.g. a filesystem id) must carry an explicit S324 ruff waiver.
        offenders = _grep(r"hashlib\.(md5|sha1)\b", allow_noqa="S324")
        assert offenders == [], f"weak crypto hash without S324 waiver: {offenders}"
