from __future__ import annotations import json import sqlite3 import sys from pathlib import Path import pytest sys.path.insert(0, str(Path(__file__).resolve().parents[1])) import gateway def test_authority_envelope_is_advisory_and_forbids_side_effects() -> None: env = gateway.build_envelope( service="classifier", operation="classify", mode="shadow", result={"labels": {"workflow_category": {"value": "devops"}}}, npu_busy_delta_us=123, input_scope="explicit_text", ) assert env["ok"] is True assert env["mode"] == "shadow" assert env["authority"] == { "may_route": False, "may_write_memory": False, "may_send_external": False, "may_process_private_dirs": False, "may_execute_tools": False, "may_restart_services": False, } assert env["npu_proof"] == {"required": True, "ok": True, "npu_busy_delta_us": 123} def test_bind_host_requires_explicit_docker_bridge_approval() -> None: gateway.validate_bind_host("127.0.0.1") with pytest.raises(ValueError, match="without --allow-docker-bridge"): gateway.validate_bind_host("172.19.0.1") gateway.validate_bind_host("172.19.0.1", allow_docker_bridge=True) with pytest.raises(ValueError, match="approved bridge IP"): gateway.validate_bind_host("0.0.0.0", allow_docker_bridge=True) def test_classify_calls_sidecar_and_logs_metadata_only(tmp_path: Path) -> None: calls: list[tuple[str, dict]] = [] def fake_post(url: str, payload: dict, timeout_s: float) -> dict: calls.append((url, payload)) return { "labels": {"tool_needed": {"value": True}}, "npu_busy_delta_us": 55, "sysfs_npu_busy_delta_us": 55, } logger = gateway.AdvisoryLogger(tmp_path / "events.sqlite") env = gateway.classify_text( "Inspect live service status", trace_id="t1", http_post_json=fake_post, logger=logger, ) assert calls[0][0].endswith(":18819/v1/classify") assert calls[0][1]["options"]["dry_run"] is True assert env["service"] == "classifier" assert env["authority"]["may_route"] is False assert env["npu_proof"]["ok"] is True with sqlite3.connect(tmp_path / "events.sqlite") as con: row = con.execute("select service, operation, input_ref, raw_payload from advisory_events").fetchone() assert row == ("classifier", "classify", "text:sha256:" + gateway.sha256_text("Inspect live service status"), None) def test_generate_allows_only_bounded_jobs() -> None: with pytest.raises(ValueError, match="unsupported advisory generation job"): gateway.generate_bounded("primary_chat", "hello", http_post_json=lambda *_: {}) def test_generate_wraps_draft_without_final_authority() -> None: def fake_post(url: str, payload: dict, timeout_s: float) -> dict: return {"text": "Short title", "npu_busy_delta_us": 99, "timing_ms": {"total": 10}} env = gateway.generate_bounded("title", "Summarize this local health check", http_post_json=fake_post) assert env["service"] == "genai" assert env["operation"] == "generate:title" assert env["result"]["draft_text"] == "Short title" assert env["result"]["final_authority"] is False assert env["authority"]["may_send_external"] is False def test_doc_triage_requires_explicit_file_under_allowed_root(tmp_path: Path) -> None: allowed = tmp_path / "allowed" allowed.mkdir() target = allowed / "synthetic.png" target.write_bytes(b"not real image for unit test") def fake_post(url: str, payload: dict, timeout_s: float) -> dict: assert payload["path"] == str(target.resolve()) assert payload["options"]["allowed_roots"] == [str(allowed.resolve())] return {"ok": True, "result": {"pages": [{"needs_attention": {"embedding": {"verified_npu": True, "npu_busy_delta_us": 42}}}]}} env = gateway.triage_file(str(target), allowed_roots=[str(allowed)], configured_roots=[allowed], http_post_json=fake_post) assert env["service"] == "doc_triage" assert env["input_scope"] == "explicit_file" assert env["npu_proof"]["ok"] is True def test_doc_triage_rejects_private_root_broadening(tmp_path: Path) -> None: allowed = tmp_path / "allowed" allowed.mkdir() with pytest.raises(ValueError, match="path must be inside an allowed root"): gateway.triage_file(str(tmp_path / "outside.png"), allowed_roots=[str(allowed)], configured_roots=[allowed], http_post_json=lambda *_: {}) def test_doc_triage_rejects_requested_root_outside_configured_roots(tmp_path: Path) -> None: configured = tmp_path / "configured" requested = tmp_path / "private" requested.mkdir() target = requested / "file.png" target.write_bytes(b"synthetic") with pytest.raises(ValueError, match="requested allowed root is outside configured roots"): gateway.triage_file( str(target), allowed_roots=[str(requested)], configured_roots=[configured], http_post_json=lambda *_: {}, ) def test_health_aggregates_dependencies_without_raw_private_data() -> None: def fake_get(url: str, timeout_s: float) -> dict: return {"ok": True, "service": url.rsplit(":", 1)[-1]} health = gateway.health(http_get_json=fake_get) assert health["ok"] is True assert set(health["dependencies"]) == {"classifier", "genai", "doc_triage"} assert "raw" not in json.dumps(health).lower()