Initial curated Unraid-AppOps-Gateway source from 3bd6f6fee310125bfbb4d4650389a817f498724d
This commit is contained in:
commit
1dfbca08a1
528 files changed
+131054
No files matched your search
@@ -0,0 +1,249 @@
|
||||
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"
|
||||
Reference in new issue
Block a user