Files
Cortex-Inara/cortex/tests/test_persona.py
Scott Idem 92a8f5d894 test: add Cortex test suite (77 tests, no LLM calls)
Tests cover:
  - Smoke: /health, /auth/status, /distill/status (test_health.py)
  - Persona validation: path traversal, bad names, list_personas (test_persona.py)
  - Chat API: persona routing, session persistence, error handling (test_api_chat.py)
  - Files API: ALLOWED set enforcement, read/write, missing files (test_api_files.py)
  - Webhooks: NC Talk HMAC accept/reject, Google Chat JWT (test_webhooks.py)
  - Tools: scratch read/write/append/clear, tasks CRUD, cron parser + tools (test_tools.py)
  - Security: path traversal, replay attack, known gaps documented (test_security.py)

All LLM calls mocked — suite runs in ~1.4s.
Run: cd cortex && .venv/bin/pytest

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 22:03:42 -04:00

95 lines
3.2 KiB
Python

"""
Unit tests for persona.py — validation, routing, path traversal.
No HTTP involved.
"""
import pytest
from pathlib import Path
from unittest.mock import patch
def _make_temp_personas(tmp_path: Path) -> Path:
root = tmp_path / "personas"
for name in ("alice", "bob"):
p = root / name
p.mkdir(parents=True)
(p / "IDENTITY.md").write_text(f"# {name}")
# A directory WITHOUT IDENTITY.md — should not appear in list_personas()
(root / "incomplete").mkdir()
return root
def test_validate_good(tmp_path):
root = _make_temp_personas(tmp_path)
import config, persona
with patch.object(config.settings, "personas_dir", root):
assert persona.validate("alice") == "alice"
assert persona.validate("bob") == "bob"
def test_validate_unknown(tmp_path):
root = _make_temp_personas(tmp_path)
import config, persona
with patch.object(config.settings, "personas_dir", root):
with pytest.raises(ValueError, match="Unknown persona"):
persona.validate("charlie")
def test_validate_path_traversal(tmp_path):
root = _make_temp_personas(tmp_path)
import config, persona
with patch.object(config.settings, "personas_dir", root):
with pytest.raises(ValueError, match="Invalid persona name"):
persona.validate("../../etc/passwd")
with pytest.raises(ValueError, match="Invalid persona name"):
persona.validate("../alice")
with pytest.raises(ValueError, match="Invalid persona name"):
persona.validate("alice/../../etc")
def test_validate_special_chars(tmp_path):
root = _make_temp_personas(tmp_path)
import config, persona
with patch.object(config.settings, "personas_dir", root):
for bad in ("alice bob", "alice;bob", "alice\x00bob", "A" * 33, ""):
with pytest.raises(ValueError):
persona.validate(bad)
def test_validate_allows_hyphen_underscore(tmp_path):
root = _make_temp_personas(tmp_path)
# Create a persona with hyphen and underscore in name
p = root / "my_ai-agent"
p.mkdir(parents=True)
(p / "IDENTITY.md").write_text("# My Agent")
import config, persona
with patch.object(config.settings, "personas_dir", root):
assert persona.validate("my_ai-agent") == "my_ai-agent"
def test_list_personas(tmp_path):
root = _make_temp_personas(tmp_path)
import config, persona
with patch.object(config.settings, "personas_dir", root):
names = persona.list_personas()
assert "alice" in names
assert "bob" in names
assert "incomplete" not in names # no IDENTITY.md
def test_persona_path_uses_contextvar(tmp_path):
root = _make_temp_personas(tmp_path)
import config, persona
with patch.object(config.settings, "personas_dir", root):
persona.set_persona("alice")
assert persona.persona_path() == root / "alice"
persona.set_persona("bob")
assert persona.persona_path() == root / "bob"
def test_persona_path_explicit_name(tmp_path):
root = _make_temp_personas(tmp_path)
import config, persona
with patch.object(config.settings, "personas_dir", root):
persona.set_persona("alice")
assert persona.persona_path("bob") == root / "bob"