Search end-to-end encrypted nodes through an encrypted local index

- Crypto backend: use native AES-GCM from `cryptography` when importable
  (~1.5 GiB/s), falling back to the pure-Python implementation with a
  byte-identical format and identical authentication failures.
- E2E shard: decrypted E2E text is indexed in an in-memory SQLite
  database, persisted only as serialize() -> AES-256-GCM with an HKDF key
  bound to the project and memory-secret identity, authenticated header,
  fresh nonce, 0600 atomic writes. It loads only while the project is
  unlocked; tampered, foreign, wrong-key or rotated shards fail closed and
  rebuild. Search merges shard hits (search_source local_e2e) and reports
  locked/unavailable/slow states explicitly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
HumbleTurtle
2026-09-28 22:56:38 -03:00
co-authored by Claude Opus 5.5
parent bf6acaacc8
commit d86610da8e
4 changed files with 1988 additions and 86 deletions
+16 -2
View File
@@ -472,8 +472,22 @@ def run():
indexed["metadata"] = {"private": "secret metadata"}
mod.index_node(indexed)
assert mod.search_local_index({"q": "alpha", "limit": 5})["items"]
assert mod.search_local_index({"q": "needle", "limit": 5})["items"] == []
assert mod.search_local_index({"q": "metadata", "limit": 5})["items"] == []
# E2E body/metadata text never reaches the on-disk index; with the
# memory secret unlocked it is found only via the encrypted shard.
for term in ("needle", "metadata"):
hits = mod.search_local_index({"q": term, "limit": 5})["items"]
assert hits and all(item.get("search_source") == "local_e2e" for item in hits)
mod.e2e_shards_close(flush=True)
for path in state_dir.iterdir():
if path.is_file():
raw = path.read_bytes()
assert b"secret needle" not in raw and b"secret metadata" not in raw, path.name
mod.MEMORY_SECRET_CACHE.clear()
mod.ACTIVE_MEMORY_SECRET_VERSIONS.clear()
mod.PROJECT_VAULT_PASSPHRASE = None
locked = mod.search_local_index({"q": "needle", "limit": 5})
assert locked["items"] == []
assert [warning["code"] for warning in locked["warnings"]] == ["e2e_index_locked"]
print("ok: local MCP memory node encryption smoke passed")