251e509ee0
Unit tests: - test_security_boundaries.py: vault block, vault lock sentinel - test_security_injection.py: all 4 injection categories, case-insensitive - test_vault_rw.py: roundtrip, file permissions (chmod 400), no key in config - test_config.py: schema roundtrip, no api_key field, chmod 600 on config.yaml - test_memory_reader.py: list, read, sandboxing, context loading - test_memory_writer.py: write, append, index update, traversal blocked, chmod 600 - test_providers.py: required fields, unique IDs, litellm prefix format - test_renderer.py: key redaction for sk-ant-, sk-, AIza patterns Security tests: - test_vault_ai_isolation.py: 7 traversal patterns blocked via memory read/write - test_path_traversal.py: 20+ traversal patterns — all rejected for read and write - test_prompt_injection.py: 21-item corpus + 5 clean texts (no false positives) Integration tests: - test_lmstudio.py: live call to localhost:1234, streaming, full stack session, injection scan on real output (skips if LM Studio not running) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
import pytest
|
|
from pyra.security.boundaries import VaultAccessError
|
|
|
|
|
|
def test_list_memories_empty(tmp_pyra_home):
|
|
from pyra.memory.reader import list_memories
|
|
memories = list_memories()
|
|
assert isinstance(memories, list)
|
|
|
|
|
|
def test_write_and_read_memory(tmp_pyra_home):
|
|
from pyra.memory.writer import write_memory
|
|
from pyra.memory.reader import read_memory
|
|
|
|
write_memory("user/test_note.md", "# Test\n\nHello world")
|
|
content = read_memory("user/test_note.md")
|
|
assert "Hello world" in content
|
|
|
|
|
|
def test_read_nonexistent_raises(tmp_pyra_home):
|
|
from pyra.memory.reader import read_memory
|
|
with pytest.raises(FileNotFoundError):
|
|
read_memory("does_not_exist.md")
|
|
|
|
|
|
def test_read_vault_path_blocked(tmp_pyra_home):
|
|
from pyra.memory.reader import read_memory
|
|
with pytest.raises((VaultAccessError, PermissionError, FileNotFoundError)):
|
|
read_memory("../../../../vault/secrets/api_keys.json")
|
|
|
|
|
|
def test_list_memories_after_writes(tmp_pyra_home):
|
|
from pyra.memory.writer import write_memory
|
|
from pyra.memory.reader import list_memories
|
|
|
|
write_memory("user/profile.md", "# Profile")
|
|
write_memory("context/project.md", "# Project")
|
|
memories = list_memories()
|
|
names = [m.name for m in memories]
|
|
assert any("profile" in n for n in names)
|
|
assert any("project" in n for n in names)
|
|
|
|
|
|
def test_load_context_returns_string(tmp_pyra_home):
|
|
from pyra.memory.writer import write_memory
|
|
from pyra.memory.reader import load_context_for_session
|
|
|
|
write_memory("user/profile.md", "# Profile\n\nI am a developer.")
|
|
ctx = load_context_for_session()
|
|
assert isinstance(ctx, str)
|
|
assert "developer" in ctx
|