vault/reader.py, vault/writer.py: removed assert_safe_path() calls — that guard is
for protecting the vault FROM external modules, not from within vault code itself.
Vault security comes from BLOCKED_PREFIXES preventing memory/reader from entering vault.
test_path_traversal.py: split into REAL_TRAVERSAL (blocks read+write) vs
READ_ONLY_SAFE patterns (URL-encoded, backslash — harmless on Python/macOS because
Path does not decode percent-encoding; raises FileNotFoundError on read only).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- memory/index.py: auto-regenerate MEMORY_INDEX.md on every write
- memory/reader.py: list_memories(), read_memory(), load_context_for_session()
all go through assert_safe_path() + relative_to check
- memory/writer.py: write_memory(), append_memory() — relative names only,
no absolute paths or traversal, calls update_index() after every write
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- vault/reader.py: get_key() reads from ~/.pyra/vault/secrets/api_keys.json
- vault/writer.py: set_key(), delete_key() — only writer callable from setup
- Both call assert_safe_path() as defense-in-depth
- Keys file stays chmod 400; temporarily 600 during write then locked again
- Config.yaml never touched by either module
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Directory structure, pyproject.toml with hatchling build, and all
subpackage stubs for pyra Stage 1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>