v0.8.6 — Security hardening + infrastructure consolidation
Security
- Graph discovery permission bypass (
search.pyGC1):check_visibility()now applied when fetching graph-discovered memories — workspace scoping, CEO status, and lead permissions were previously bypassed - MCP server crash on validate_link:
validate_linktool now wrapped in try/except; unhandledRuntimeErrorpreviously crashed the entire MCP server - IDOR oracle fixes (
memories.py):delete_memory,unarchive_memory, andvalidate_linknow return uniform 403 for both missing and unauthorized access — prevents existence enumeration - Path traversal in MCP tools: UUID format validated before use in all memory and document tools;
quote()usessafe=''to encode all special characters
Infrastructure
- MCP media volume: mounted with write access for
save_memory(image_path=...)support - MCP startup without API key: empty default allows first boot before key generation
- Backup/restore container name: default corrected to
ecodb-postgres - NER Dockerfile: versions pinned (
fastapi==0.118.0,uvicorn==0.40.0,gliner==0.2.26), dedicated group GID 1001 - MCP dependency cap:
mcp[cli]>=1.0.0,<2.0.0
Robustness
- search() input validation:
limit(1–100) anddeep_factor(1–10) validated at MCP layer - search_recent() tag param: corrected
tag→tagsto match API contract - AGE hop retry: hop=2 still attempted if hop=1 fails
- AGE node creation race guard: defense-in-depth try/except on
_age_create - Worker stuck document recovery:
recover_stuck_documents()at startup resets or fails documents stuck after process crash
Documentation
- MCP tool count: 22+ → 32
- stdio transport config example added
- Spanish runtime error strings translated to English
- Stale container name references cleaned up
16 files changed, +394/-46 lines. 10 original tasks + 12 adversarial fixes. 2 full review loops. 300/304 tests pass (3 pre-existing). 0 regressions.