Files
codexpi/tests/test_master_agent.py

115 lines
5.0 KiB
Python
Raw Normal View History

2026-11-14 20:23:59 +01:00
from __future__ import annotations
import json
import os
import socket
import threading
import uuid
from pathlib import Path
from codexpi.database import utcnow
def fake_host_channel(path: Path, token: str):
ready = threading.Event()
def serve():
if path.exists():
path.unlink()
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as server:
server.bind(str(path))
server.listen(1)
ready.set()
connection, _ = server.accept()
with connection:
request = json.loads(connection.recv(100_000).split(b"\n", 1)[0])
assert request["token"] == token
connection.sendall(json.dumps({"ok": True, "exit_code": 0, "answer": "Action hôte de test terminée."}).encode() + b"\n")
thread = threading.Thread(target=serve, daemon=True)
thread.start()
ready.wait(2)
return thread
def test_master_agent_channel_is_separate_confirmed_and_audited(logged_in):
client, app, _, _, headers = logged_in
base = app.state.settings.data_dir / "host-agent"
base.mkdir()
token_file, socket_path = base / "agent.token", base / "agent.sock"
token = "fixture-token-which-is-longer-than-thirty-two-characters"
token_file.write_text(token, encoding="utf-8")
os.chmod(token_file, 0o600)
thread = fake_host_channel(socket_path, token)
created = client.post(
"/api/master-agent/sessions", headers=headers,
json={"title": "Maintenance de test", "privileged": True},
)
assert created.status_code == 201
session_id = created.json()["id"]
refused = client.post(
f"/api/master-agent/sessions/{session_id}/messages", headers=headers,
json={"prompt": "Effectuer une action réversible de test.", "acknowledge_privileged": False},
)
assert refused.status_code == 409
accepted = client.post(
f"/api/master-agent/sessions/{session_id}/messages", headers=headers,
json={"prompt": "Effectuer une action réversible de test.", "acknowledge_privileged": True},
)
assert accepted.status_code == 200, accepted.text
assert accepted.json()["answer"] == "Action hôte de test terminée."
thread.join(2)
history = client.get("/api/master-agent").json()["sessions"]
assert [message["role"] for message in history[0]["messages"]] == ["user", "assistant"]
def test_project_user_cannot_access_master_agent(logged_in):
client, app, _, _, headers = logged_in
app.state.auth.create_user("member", "a-different-long-test-password", is_admin=False)
client.post("/api/auth/logout", headers=headers)
login = client.post("/api/auth/login", json={"username": "member", "password": "a-different-long-test-password"}).json()
member_headers = {"X-CSRF-Token": login["csrf_token"]}
assert client.get("/api/master-agent").status_code == 403
assert client.post("/api/master-agent/sessions", headers=member_headers, json={"title": "No", "privileged": False}).status_code == 403
def test_additional_admin_is_not_the_host_owner(logged_in):
client, app, _, _, headers = logged_in
app.state.auth.create_user("other-admin", "another-long-administrator-password", is_admin=True)
client.post("/api/auth/logout", headers=headers)
login = client.post("/api/auth/login", json={"username": "other-admin", "password": "another-long-administrator-password"}).json()
admin_headers = {"X-CSRF-Token": login["csrf_token"]}
assert client.get("/api/master-agent").status_code == 403
assert client.post("/api/master-agent/sessions", headers=admin_headers, json={"title": "No", "privileged": False}).status_code == 403
def test_additional_admin_cannot_queue_the_privileged_pi_doctor(logged_in):
client, app, projects, _, headers = logged_in
owner_id = str(app.state.db.one("SELECT id FROM users LIMIT 1")["id"])
project_id = str(uuid.uuid4())
conversation_id = str(uuid.uuid4())
root = projects / "pi-doctor"
root.mkdir()
stamp = utcnow()
app.state.db.execute(
"INSERT INTO projects(id,name,path,owner_id,full_access,execution_group,created_at) VALUES(?,?,?,?,?,?,?)",
(project_id, "Pi Doctor", str(root), owner_id, 1, "__global_agent__", stamp),
)
app.state.db.execute(
"INSERT INTO conversations(id,project_id,user_id,title,status,created_at,updated_at) VALUES(?,?,?,?,?,?,?)",
(conversation_id, project_id, owner_id, "Host", "idle", stamp, stamp),
)
app.state.auth.create_user("other-host-admin", "another-long-administrator-password", is_admin=True)
client.post("/api/auth/logout", headers=headers)
login = client.post(
"/api/auth/login",
json={"username": "other-host-admin", "password": "another-long-administrator-password"},
).json()
response = client.post(
f"/api/conversations/{conversation_id}/queue",
headers={"X-CSRF-Token": login["csrf_token"]},
json={"content": "Inspecter l’hôte.", "attachment_ids": []},
)
assert response.status_code == 403