Files
Pyra/src/pyra/security/boundaries.py
T
curo1305 a96b540234 feat(security): vault wall, path guard, and utils
- utils/paths.py: pyra_home(), ensure_dir(), safe_chmod(), expand()
- security/boundaries.py: VaultAccessError, PyraSecurityError,
  assert_safe_path() (called before every file read), check_vault_lock()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:48:50 +02:00

42 lines
1.1 KiB
Python

from pathlib import Path
from pyra.utils.paths import pyra_home
class VaultAccessError(PermissionError):
pass
class PyraSecurityError(RuntimeError):
pass
VAULT_PATH: Path = pyra_home() / "vault"
BLOCKED_PREFIXES: list[Path] = [VAULT_PATH]
def assert_safe_path(path: Path) -> None:
"""Raise VaultAccessError if path resolves into a blocked prefix."""
resolved = path.resolve()
for blocked in BLOCKED_PREFIXES:
blocked_resolved = blocked.resolve()
try:
resolved.relative_to(blocked_resolved)
raise VaultAccessError(
f"Access denied: '{resolved}' is inside the protected vault. "
"The vault is never accessible to the AI."
)
except ValueError:
pass
def check_vault_lock() -> None:
"""Raise PyraSecurityError if the vault sentinel is missing."""
lock = VAULT_PATH / ".vault_lock"
if not lock.exists():
raise PyraSecurityError(
f"Vault sentinel missing: {lock}\n"
"This may indicate tampering. Refusing to start.\n"
"Run 'pyra setup' to reinitialise the vault."
)