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:
co-authored by
Claude Opus 5.5
parent
bf6acaacc8
commit
d86610da8e
@@ -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")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user