""" 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()