test(issue-5): phase 1 delegation characterization suite
The three lib.sh delegation helpers (delegate_submit_job, delegate_publish_event, start_watchdog) had zero direct test coverage, so a "full suite green" gate would have been vacuous for the Phase 1 extraction. Add the regression oracle before the move: - C-01..C-09 golden tests for the shell helpers: the non-fatal contract (empty job id, missing script, non-zero interpreter exit), exact argv forwarding, stdout-is-the-job-id-alone, and the daemon's PID/dedup/log-path behaviour. All are parametrized over MAM_DELEGATION_PY so the legacy and python bodies must agree. - CLI contract snapshots taken from the argparse parsers rather than --help text, so wording stays free to change but option names, choices and defaults do not. - Auto-completion invariant guards for the three surfaces that decide job status: EVENT_TO_STATUS, the wrapper's exit-code mapping, and reconcile.sh's terminal mutation literals. - conftest: PV-2/PV-3 session guards asserting that every non-delegation lib_py.* module resolves to the real skills tree and that no temp-tree sys.path entry contributes a lib_py package. MAM_ENV_FILE is pointed at an absent file inside the sandbox so delegation code can never inject the real .mam.env into a test process. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrDNJkHmm18uu7n7JwV5Qd
This commit is contained in:
1 parent
fc0bd96d8a
commit
265a1f6c3d
7 files changed
+531
No files matched your search
@@ -42,6 +42,10 @@ def mam_sandbox(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("LOCAL_BIN", str(tmp_path / ".local" / "bin"))
|
||||
monkeypatch.setenv("AGENT_SESSIONS_YAML", str(yaml_path))
|
||||
monkeypatch.setenv("WORKSPACE_ROOT", str(tmp_path))
|
||||
# D6 (issue #5 phase 1): point the delegation env loader at a file that does not
|
||||
# exist, so importing or running delegation code inside a sandbox never injects the
|
||||
# real .mam.env into this process's os.environ.
|
||||
monkeypatch.setenv("MAM_ENV_FILE", str(tmp_path / ".mam.env.absent"))
|
||||
monkeypatch.delenv("HERDR_SESSION_NAME", raising=False)
|
||||
monkeypatch.delenv("HERDR_SERVER_NAME", raising=False)
|
||||
monkeypatch.delenv("HERDR_WORKSPACE_ID", raising=False)
|
||||
@@ -1044,3 +1048,61 @@ print(str(uuid.uuid4()))
|
||||
monkeypatch.setenv("PATH", f"{bin_dir}:{new_path}")
|
||||
|
||||
return bin_dir
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Issue #5 Phase 1 — tree provenance guards (PV-2 / PV-3)
|
||||
#
|
||||
# The delegation shims bind the `lib_py.delegation` package to the tree next to
|
||||
# themselves. Two invariants must hold for the whole session, and both are
|
||||
# checked once at teardown so a violation anywhere in the suite is caught:
|
||||
#
|
||||
# PV-2 every imported `lib_py.*` module OTHER than the delegation package
|
||||
# resolves to the real skills tree (a sandbox copy must never shadow
|
||||
# lib_py.agents / layout / state / ...).
|
||||
# PV-3 no sys.path entry under pytest's basetemp contributes a `lib_py`
|
||||
# package directory. (Sandbox *scripts* dirs are fine: they contain no
|
||||
# lib_py, which is why test_tier1_unit.py's inserts stay legal.)
|
||||
# ==============================================================================
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def delegation_tree_provenance_guard(tmp_path_factory):
|
||||
yield
|
||||
|
||||
real_skills = Path(SKILLS_DIR).resolve()
|
||||
basetemp = Path(tmp_path_factory.getbasetemp()).resolve()
|
||||
|
||||
def _under(path, root):
|
||||
try:
|
||||
Path(path).resolve().relative_to(root)
|
||||
return True
|
||||
except (ValueError, OSError):
|
||||
return False
|
||||
|
||||
# --- PV-2 -----------------------------------------------------------------
|
||||
offenders = []
|
||||
for name, mod in sorted(sys.modules.items()):
|
||||
if name != "lib_py" and not name.startswith("lib_py."):
|
||||
continue
|
||||
if name == "lib_py.delegation" or name.startswith("lib_py.delegation."):
|
||||
continue # delegation may legitimately bind to a sandbox copy (D2/PV-1)
|
||||
origin = getattr(mod, "__file__", None)
|
||||
if not origin:
|
||||
continue
|
||||
if not _under(origin, real_skills):
|
||||
offenders.append("{} -> {}".format(name, origin))
|
||||
assert not offenders, (
|
||||
"PV-2: non-delegation lib_py modules were loaded from outside the real skills "
|
||||
"tree ({}):\n {}".format(real_skills, "\n ".join(offenders))
|
||||
)
|
||||
|
||||
# --- PV-3 -----------------------------------------------------------------
|
||||
polluted = [
|
||||
entry for entry in sys.path
|
||||
if entry and _under(entry, basetemp) and (Path(entry) / "lib_py").is_dir()
|
||||
]
|
||||
assert not polluted, (
|
||||
"PV-3: sys.path carries temp-tree entries that provide a lib_py package "
|
||||
"(these would shadow the real tree for any later first-time import):\n "
|
||||
+ "\n ".join(polluted)
|
||||
)
|
||||
Reference in new issue
Block a user