mirror of
https://github.com/razzant/ouroboros.git
synced 2026-10-03 12:18:39 +00:00
tests/test_git_ops_default_roots.py is the D13 hook suite (pre-init roots
follow the env per call; pinned roots win; the _log_supervisor writer
lands in the env root; the issue #455 subprocess repro under a throwaway
HOME). tests/test_hermetic_data_root.py pins the class: append_jsonl
fails closed on a live-root write, and the serial E2E pin runs the exact
leaking suites under throwaway HOME + full env isolation with an empty
pre/post inventory delta of the live-shaped root. All six pins verified
RED on a git-archive copy of base 8827fd2c. D13 flips pending->done;
lane section appended to LEDGER_CORRECTIONS.
102 lines
4.2 KiB
Python
102 lines
4.2 KiB
Python
"""D13 pin: supervisor/git_ops pre-init roots follow the OUROBOROS_* env.
|
|
|
|
The defect class (issue #455): ``git_ops.REPO_DIR`` / ``DRIVE_ROOT`` were
|
|
hardcoded ``~/Ouroboros`` defaults, resolved once and blind to the env, so a
|
|
fully env-isolated process still wrote ``managed_update_stash_restored
|
|
(context=test)`` into the LIVE ``data/logs/supervisor.jsonl`` through
|
|
``update_merge._log_supervisor``. Pre-init the roots now resolve PER CALL from
|
|
the env via the config path SSOT (module ``__getattr__``); ``init()``, worker
|
|
rebinds and test monkeypatches pin them as real module attributes.
|
|
"""
|
|
|
|
import os
|
|
import pathlib
|
|
import subprocess
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
import supervisor.git_ops as git_ops
|
|
import supervisor.update_merge as update_merge
|
|
|
|
REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent
|
|
|
|
_UNSET = object()
|
|
|
|
|
|
def _unpin(request, name: str) -> None:
|
|
"""Remove a pinned root attribute for the test, restoring it afterwards.
|
|
|
|
``monkeypatch.delattr`` cannot do this: module ``__getattr__`` makes
|
|
``hasattr`` true while the attribute is absent from ``__dict__``.
|
|
"""
|
|
saved = git_ops.__dict__.get(name, _UNSET)
|
|
git_ops.__dict__.pop(name, None)
|
|
|
|
def _restore():
|
|
git_ops.__dict__.pop(name, None)
|
|
if saved is not _UNSET:
|
|
setattr(git_ops, name, saved)
|
|
|
|
request.addfinalizer(_restore)
|
|
|
|
|
|
def test_unpinned_roots_follow_env_per_call(request, monkeypatch, tmp_path):
|
|
_unpin(request, "DRIVE_ROOT")
|
|
_unpin(request, "REPO_DIR")
|
|
monkeypatch.setenv("OUROBOROS_DATA_DIR", str(tmp_path / "iso-data"))
|
|
monkeypatch.setenv("OUROBOROS_REPO_DIR", str(tmp_path / "iso-repo"))
|
|
assert git_ops.DRIVE_ROOT == tmp_path / "iso-data"
|
|
assert git_ops.REPO_DIR == tmp_path / "iso-repo"
|
|
# PER CALL: a later env change is followed, not cached.
|
|
monkeypatch.setenv("OUROBOROS_DATA_DIR", str(tmp_path / "late-data"))
|
|
assert git_ops.DRIVE_ROOT == tmp_path / "late-data"
|
|
assert git_ops.current_drive_root() == tmp_path / "late-data"
|
|
|
|
|
|
def test_pinned_roots_win_over_env(monkeypatch, tmp_path):
|
|
monkeypatch.setattr(git_ops, "DRIVE_ROOT", tmp_path / "pinned")
|
|
monkeypatch.setenv("OUROBOROS_DATA_DIR", str(tmp_path / "env-root"))
|
|
assert git_ops.DRIVE_ROOT == tmp_path / "pinned"
|
|
assert git_ops.current_drive_root() == tmp_path / "pinned"
|
|
|
|
|
|
def test_log_supervisor_writes_into_env_root_when_unpinned(request, monkeypatch, tmp_path):
|
|
"""The issue #455 writer path itself: _log_supervisor lands in the env root."""
|
|
_unpin(request, "DRIVE_ROOT")
|
|
monkeypatch.setenv("OUROBOROS_DATA_DIR", str(tmp_path / "iso"))
|
|
update_merge._log_supervisor({"type": "hermetic_probe", "context": "test"})
|
|
probe = tmp_path / "iso" / "logs" / "supervisor.jsonl"
|
|
assert probe.is_file()
|
|
assert "hermetic_probe" in probe.read_text(encoding="utf-8")
|
|
|
|
|
|
@pytest.mark.serial
|
|
def test_pre_isolation_import_still_writes_isolated_root(tmp_path):
|
|
"""Red on the pre-fix tree: all four OUROBOROS_* set, module imported, and
|
|
the write STILL went to the (fake) home live root instead of the isolated
|
|
one — the exact issue #455 reproduction, hermetic via a throwaway HOME."""
|
|
fake_home = tmp_path / "home"
|
|
iso = tmp_path / "iso"
|
|
fake_home.mkdir()
|
|
env = {**os.environ,
|
|
"HOME": str(fake_home),
|
|
"OUROBOROS_APP_ROOT": str(iso),
|
|
"OUROBOROS_REPO_DIR": str(iso / "repo"),
|
|
"OUROBOROS_DATA_DIR": str(iso / "data"),
|
|
"OUROBOROS_SETTINGS_PATH": str(iso / "data" / "settings.json")}
|
|
env.pop("OUROBOROS_PYTEST_ACTIVE", None)
|
|
env.pop("OUROBOROS_TEST_LIVE_DATA_ROOT", None)
|
|
script = (
|
|
"import supervisor.update_merge as um\n"
|
|
"um._log_supervisor({'type': 'hermetic_probe', 'context': 'test'})\n"
|
|
)
|
|
proc = subprocess.run(
|
|
[sys.executable, "-c", script], cwd=str(REPO_ROOT), env=env,
|
|
capture_output=True, text=True, timeout=120,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr[-2000:]
|
|
live_shaped = fake_home / "Ouroboros" / "data"
|
|
leaked = [str(p) for p in live_shaped.rglob("*") if p.is_file()] if live_shaped.exists() else []
|
|
assert not leaked, f"write leaked into the live-shaped root: {leaked}"
|
|
assert (iso / "data" / "logs" / "supervisor.jsonl").is_file()
|