"""SC-15 directory-traversal guard for the corpus readers.

`read_standard` / `read_recipe` / `read_design` resolve
``<corpus-dir>/<name>.md``. A crafted ``name`` (a path separator, a
parent-dir reference, an absolute path) must NOT be able to escape the
corpus directory and read an arbitrary ``.md`` file elsewhere on disk.

Before the SC-15 fix, ``read_standard("../../README")`` returned the
repo-root ``README.md``. These tests pin that the guard rejects every
traversal shape with the same `FileNotFoundError` the readers raise for
an unknown topic, while a legitimate bare stem still resolves.
"""

from __future__ import annotations

import pytest

import mgf.standard as ds

# (reader, a known-good bare stem that MUST still resolve)
_READERS = [
    (ds.read_standard, "LOGGING"),
    (ds.read_recipe, "federation-sync-prompt"),
    (ds.read_design, "federation"),
]

_TRAVERSAL_STEMS = [
    "../../README",
    "../../../etc/hostname",
    "/etc/hostname",
    "..",
    "sub/dir",
    "a/../b",
]


class TestCorpusReaderTraversalGuard:
    @pytest.mark.parametrize("reader,_good", _READERS)
    @pytest.mark.parametrize("evil", _TRAVERSAL_STEMS)
    def test_traversal_stem_is_rejected(self, reader, _good, evil) -> None:
        with pytest.raises(FileNotFoundError):
            reader(evil)

    @pytest.mark.parametrize("reader,good", _READERS)
    def test_legitimate_stem_still_resolves(self, reader, good) -> None:
        assert reader(good).strip()
