test: comprehensive test suite

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>
This commit is contained in:
curo1305
2026-05-17 12:55:06 +02:00
parent e792c5e0c9
commit 251e509ee0
13 changed files with 746 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
"""20+ path traversal patterns — all must be rejected."""
import pytest
from pyra.security.boundaries import VaultAccessError
TRAVERSAL_PATTERNS = [
"../../../../vault/secrets/api_keys.json",
"../../../vault/secrets/api_keys.json",
"../../vault/secrets/api_keys.json",
"../vault/secrets/api_keys.json",
"a/b/c/../../../../vault/secrets/api_keys.json",
"context/../../vault/secrets/api_keys.json",
"user/../../../vault/secrets/api_keys.json",
"knowledge/../../../../vault/secrets/api_keys.json",
# URL-encoded (resolved by Path.resolve, still blocked)
"..%2Fvault%2Fsecrets%2Fapi_keys.json",
"%2e%2e/vault/secrets/api_keys.json",
# Absolute paths
"/etc/passwd",
"/root/.ssh/id_rsa",
"/tmp/evil",
# Home-relative
"~/secret",
"~/.ssh/id_rsa",
# Windows-style (harmless on macOS but should not crash)
"..\\vault\\secrets\\api_keys.json",
# Double-encoded dot (Path.resolve normalises these)
"%252e%252e/vault",
# Null bytes in path components (should raise, not silently pass)
"valid\x00../../vault",
# Extremely deep traversal
"a/" * 20 + "../../vault/secrets/api_keys.json",
# Starts inside memory then escapes
"user/notes/../../../../../../vault/secrets/api_keys.json",
]
@pytest.mark.parametrize("name", TRAVERSAL_PATTERNS)
def test_memory_read_blocks_traversal(tmp_pyra_home, name):
from pyra.memory.reader import read_memory
with pytest.raises((VaultAccessError, PermissionError, FileNotFoundError, ValueError)):
read_memory(name)
@pytest.mark.parametrize("name", TRAVERSAL_PATTERNS)
def test_memory_write_blocks_traversal(tmp_pyra_home, name):
from pyra.memory.writer import write_memory
with pytest.raises((VaultAccessError, PermissionError, FileNotFoundError, ValueError)):
write_memory(name, "evil")