Files
Unraid-AppOps-Gateway-Public/backend/tests/test_run_repopulse_adoption.py
T

124 lines
4.3 KiB
Python

from __future__ import annotations
import importlib.util
import json
from pathlib import Path
from types import SimpleNamespace
import pytest
_SCRIPT = Path(__file__).resolve().parents[2] / "scripts" / "run_repopulse_adoption.py"
_SPEC = importlib.util.spec_from_file_location("run_repopulse_adoption", _SCRIPT)
assert _SPEC is not None and _SPEC.loader is not None
handoff = importlib.util.module_from_spec(_SPEC)
_SPEC.loader.exec_module(handoff)
def test_fixed_operator_sequence_keeps_credential_out_of_result(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(handoff, "_require_root", lambda: None)
intent_id = "rpa-" + "a" * 20
calls: list[str] = []
secret = "operator-secret-value" * 4
def appops(
*arguments: str, payload: bytes | None = None, **_kwargs: object
) -> dict:
if "prepare" in arguments:
calls.append("prepare")
return {"status": "prepared", "intentId": intent_id}
if "backend.app.services.repopulse_proxy_stage" in arguments:
calls.append("proxy")
return {"status": "ready", "intentId": intent_id}
if "-c" in arguments:
calls.append("handoff")
return {
"intentId": intent_id,
"idempotencySha256": "b" * 64,
"preflightSha256": "c" * 64,
"preflightProjection": {},
"targetCredential": secret,
}
assert "finalize" in arguments
assert payload is not None and secret.encode() not in payload
calls.append("finalize")
return {"status": "completed", "intentId": intent_id}
def controller(
command: list[str], *, payload: bytes | None = None, **_kwargs: object
) -> dict:
if command[-1].endswith("stage_repopulse_target_attestation.py"):
calls.append("attestation")
return {"status": "staged", "intentId": intent_id}
assert command[-1].endswith("repopulse_adoption_cli.py")
assert json.loads(payload or b"{}")["targetCredential"] == secret
calls.append("controller")
return {"status": "deployment_verified", "intentId": intent_id}
monkeypatch.setattr(handoff, "_appops", appops)
monkeypatch.setattr(handoff, "_run", controller)
result = handoff.run()
assert result == {"status": "completed", "intentId": intent_id}
assert secret not in json.dumps(result)
assert calls == [
"prepare",
"proxy",
"attestation",
"handoff",
"controller",
"finalize",
]
def test_proxy_failure_prevents_secret_handoff(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(handoff, "_require_root", lambda: None)
calls: list[str] = []
def appops(*arguments: str, **_kwargs: object) -> dict:
calls.append(arguments[-1])
if "prepare" in arguments:
return {"status": "prepared", "intentId": "rpa-" + "a" * 20}
return {"status": "blocked"}
monkeypatch.setattr(handoff, "_appops", appops)
monkeypatch.setattr(
handoff,
"_run",
lambda *_args, **_kwargs: pytest.fail("controller must not execute"),
)
with pytest.raises(handoff.AdoptionHandoffError, match="operator_step_blocked"):
handoff.run()
assert len(calls) == 2
def test_operator_subprocess_uses_a_fixed_environment(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("PYTHONPATH", "/untrusted/modules")
observed: dict = {}
def invoke(command, **kwargs):
observed.update(kwargs)
assert command == ["python3", "fixed.py"]
return SimpleNamespace(returncode=0, stdout=b'{"status":"ready"}', stderr=b"")
monkeypatch.setattr(handoff.subprocess, "run", invoke)
assert handoff._run(["python3", "fixed.py"]) == {"status": "ready"}
assert "PYTHONPATH" not in observed["env"]
assert observed["env"]["PATH"].startswith("/usr/local/sbin:")
def test_operator_rejects_ambiguous_child_json(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
handoff.subprocess,
"run",
lambda *_args, **_kwargs: SimpleNamespace(
returncode=0,
stdout=b'{"status":"ready","status":"blocked"}',
stderr=b"",
),
)
with pytest.raises(handoff.AdoptionHandoffError, match="operator_result_invalid"):
handoff._run(["python3", "fixed.py"])