Files
Pyra/tests/security/test_vault_ai_isolation.py
curo1305 251e509ee0 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>
2026-05-17 12:55:06 +02:00

48 lines
1.6 KiB
Python

"""
Verify that vault paths cannot be reached via the memory reader API
regardless of what string the AI might supply.
"""
import pytest
from pyra.security.boundaries import VaultAccessError
TRAVERSAL_NAMES = [
"../../../../vault/secrets/api_keys.json",
"../vault/secrets/api_keys.json",
"context/../../vault/secrets/api_keys.json",
"user/../../../vault/secrets/api_keys.json",
"%2e%2e/vault/secrets/api_keys.json",
"/root/anywhere",
"~/secret",
]
@pytest.mark.parametrize("name", TRAVERSAL_NAMES)
def test_memory_read_cannot_reach_vault(tmp_pyra_home, name):
from pyra.memory.reader import read_memory
with pytest.raises((VaultAccessError, PermissionError, FileNotFoundError)):
read_memory(name)
def test_memory_write_cannot_reach_vault(tmp_pyra_home):
from pyra.memory.writer import write_memory
with pytest.raises((VaultAccessError, PermissionError, ValueError)):
write_memory("../../vault/secrets/api_keys.json", "evil content")
def test_direct_vault_read_blocked(tmp_pyra_home):
"""assert_safe_path must block the vault path directly."""
from pyra.security.boundaries import assert_safe_path, VAULT_PATH
with pytest.raises(VaultAccessError):
assert_safe_path(VAULT_PATH / "secrets" / "api_keys.json")
def test_vault_lock_sentinel_required(tmp_pyra_home):
"""Deleting .vault_lock causes bootstrap to raise PyraSecurityError."""
from pyra.security.boundaries import PyraSecurityError
lock = tmp_pyra_home / "vault" / ".vault_lock"
lock.unlink()
with pytest.raises(PyraSecurityError):
from pyra.security.boundaries import check_vault_lock
check_vault_lock()