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

250 lines
8.8 KiB
Python

from sqlmodel import Session, SQLModel, create_engine, select
from backend.app.api import routes_jobs
from backend.app.db.models import AppSetting, AuditEvent, JobRun
from backend.app.services import action_execution, mcp_operations
from backend.app.services import privatemuse_deployment_recovery as recovery
from backend.app.services.action_execution import approval_execution_supported
from backend.app.services.action_registry import (
ACTION_RISK,
ACTIONS,
action_default_target,
)
def test_privatemuse_target_registration_is_a_typed_high_risk_action():
action = "deployment.target.register_privatemuse"
assert action in ACTIONS
assert ACTION_RISK[action] == "high"
assert action_default_target(action) == "jens/privatemuse"
assert approval_execution_supported(action) is True
def test_privatemuse_target_registration_rejects_any_other_target():
result = action_execution.execute_governed_action(
None, # type: ignore[arg-type]
action="deployment.target.register_privatemuse",
target="jens/not-privatemuse",
source="chatgpt-mcp",
risk="high",
reason="Regression test for exact-target enforcement.",
original_policy_decision="allowed",
)
assert result["success"] is False
assert result["result"] == "blocked"
assert result["policyDecision"] == "blocked"
assert result["message"] == "PrivateMuse target registration accepts only jens/privatemuse."
def test_privatemuse_target_registration_dispatches_only_fixed_executor(monkeypatch):
observed = {}
def fake_executor(session, **kwargs):
observed["session"] = session
observed.update(kwargs)
return {
"success": True,
"status": "success",
"result": "success",
"message": "enrolled",
"jobId": "job-private-muse",
"auditId": "audit-private-muse",
"policyDecision": "allowed",
"originalPolicyDecision": kwargs["original_policy_decision"],
}
monkeypatch.setattr(
action_execution,
"_execute_privatemuse_target_enrollment",
fake_executor,
)
sentinel_session = object()
result = action_execution.execute_governed_action(
sentinel_session, # type: ignore[arg-type]
action="deployment.target.register_privatemuse",
target="JENS/PrivateMuse",
source="chatgpt-mcp",
risk="high",
reason="Enroll the fixed PrivateMuse deployment target.",
original_policy_decision="allowed",
)
assert result["success"] is True
assert observed == {
"session": sentinel_session,
"source": "chatgpt-mcp",
"risk": "high",
"reason": "Enroll the fixed PrivateMuse deployment target.",
"original_policy_decision": "allowed",
}
def test_privatemuse_unknown_outcome_keeps_job_running_and_retains_exec_evidence(
tmp_path, monkeypatch
):
engine = create_engine(f"sqlite:///{tmp_path / 'unknown-action.db'}")
SQLModel.metadata.create_all(engine)
def uncertain_run(self, *, session, job_id):
return {
"status": "outcome_unknown",
"reason": "Detached recovery outcome is unknown; do not retry.",
"execution_id": "exec-action-unknown",
"original_job_id": job_id,
}
monkeypatch.setattr(recovery.PrivateMuseDeploymentRecovery, "run", uncertain_run)
with Session(engine) as session:
result = action_execution.execute_governed_action(
session,
action="deployment.target.register_privatemuse",
target="jens/privatemuse",
source="chatgpt-mcp",
risk="high",
reason="Exercise durable unknown-outcome reporting.",
original_policy_decision="allowed",
)
job = session.get(JobRun, result["jobId"])
audit = session.get(AuditEvent, result["auditId"])
assert result["success"] is False
assert result["status"] == "outcome_unknown"
assert result["result"] == "outcome_unknown"
assert result["executionId"] == "exec-action-unknown"
assert job is not None
assert job.status == "running"
assert "exec-action-unknown" in str(job.result_summary)
assert audit is not None
assert audit.result == "outcome_unknown"
assert audit.after_state["executionId"] == "exec-action-unknown"
assert audit.after_state["originalJobId"] == result["jobId"]
def test_unknown_privatemuse_recovery_job_cannot_be_cancelled(tmp_path):
engine = create_engine(f"sqlite:///{tmp_path / 'cancel-guard.db'}")
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
session.add(
JobRun(
id="job-unknown-recovery",
type="deployment.target.register_privatemuse",
status="running",
source="chatgpt-mcp",
action_id="deployment.target.register_privatemuse",
target="jens/privatemuse",
risk="high",
policy_decision="allowed",
result_summary="outcome_unknown; executionId=exec-cancel-guard",
)
)
session.add(
AppSetting(
key=recovery._RECOVERY_STATE_SETTING,
value_json={
"state": "outcome_unknown",
"executionId": "exec-cancel-guard",
"controllerId": "controller-id",
"jobId": "job-unknown-recovery",
},
is_secret=False,
)
)
session.commit()
result = mcp_operations.cancel_operation_job(
session, "job-unknown-recovery"
)
route_result = routes_jobs.cancel("job-unknown-recovery", session=session)
persisted = session.exec(
select(JobRun).where(JobRun.id == "job-unknown-recovery")
).one()
assert result == {
"jobId": "job-unknown-recovery",
"status": "running",
"cancelled": False,
"changed": False,
"reason": (
"This job owns an unresolved detached PrivateMuse recovery execution; "
"reconcile that execution before changing the job record."
),
}
assert route_result == {
"success": False,
"message": (
"This job owns an unresolved detached PrivateMuse recovery execution; "
"reconcile that execution before changing the job record."
),
"id": "job-unknown-recovery",
"status": "running",
}
assert persisted.status == "running"
def test_privatemuse_job_is_cancellation_guarded_at_admission(tmp_path):
engine = create_engine(f"sqlite:///{tmp_path / 'admission-cancel.db'}")
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
_state, admitted = recovery.PrivateMuseDeploymentRecovery.admit_job(
session,
JobRun(
id="job-admitted-recovery",
type="deployment.target.register_privatemuse",
status="queued",
source="chatgpt-mcp",
action_id="deployment.target.register_privatemuse",
target="jens/privatemuse",
risk="high",
policy_decision="allowed",
),
)
result = mcp_operations.cancel_operation_job(
session, "job-admitted-recovery"
)
assert admitted is True
assert result["cancelled"] is False
assert result["changed"] is False
assert result["status"] == "queued"
assert "unresolved detached PrivateMuse recovery" in result["reason"]
def test_privatemuse_cancellation_guard_applies_only_to_the_owner(tmp_path):
engine = create_engine(f"sqlite:///{tmp_path / 'owner-cancel.db'}")
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
recovery.PrivateMuseDeploymentRecovery.admit_job(
session,
JobRun(
id="job-owner",
type="deployment.target.register_privatemuse",
status="queued",
source="chatgpt-mcp",
action_id="deployment.target.register_privatemuse",
target="jens/privatemuse",
risk="high",
policy_decision="allowed",
),
)
unrelated = JobRun(
id="job-unrelated",
type="deployment.target.register_privatemuse",
status="running",
source="chatgpt-mcp",
action_id="deployment.target.register_privatemuse",
target="jens/privatemuse",
risk="high",
policy_decision="allowed",
)
session.add(unrelated)
session.commit()
result = mcp_operations.cancel_operation_job(session, unrelated.id)
assert result["cancelled"] is True
assert result["changed"] is True
assert result["status"] == "cancelled"