From 2c1fb91eb9124e11ecc83397b32ec5571a8a8abb Mon Sep 17 00:00:00 2001 From: Neeraj Sathish Kumar Date: Tue, 30 Jun 2026 14:51:51 +0530 Subject: [PATCH] fix adapter tenant and privacy isolation --- src/adapters/neo4j.rs | 11 +++++++---- src/adapters/qdrant.rs | 6 ++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/adapters/neo4j.rs b/src/adapters/neo4j.rs index 03b9dd9..994b12a 100644 --- a/src/adapters/neo4j.rs +++ b/src/adapters/neo4j.rs @@ -104,8 +104,8 @@ impl Neo4jPort for Neo4jAdapter { fn merge_edge(&self, edge: &GraphEdge) -> CoreResult<()> { let statement = r#" - MATCH (a:NextralEntity {user_id:$user_id, key:$from_key}) - MATCH (b:NextralEntity {user_id:$user_id, key:$to_key}) + MATCH (a:NextralEntity {tenant_id:$tenant_id, user_id:$user_id, key:$from_key}) + MATCH (b:NextralEntity {tenant_id:$tenant_id, user_id:$user_id, key:$to_key}) MERGE (a)-[r:NEXTRAL_RELATES_TO {tenant_id:$tenant_id, user_id:$user_id, relationship_type:$relationship_type, from_key:$from_key, to_key:$to_key}]->(b) ON CREATE SET r.confidence=$confidence, r.source_memory_ids=$source_memory_ids, r.created_at=$created_at, r.last_confirmed_at=$last_confirmed_at ON MATCH SET r.confidence=CASE WHEN r.confidence > $confidence THEN r.confidence ELSE $confidence END, @@ -141,9 +141,10 @@ impl Neo4jPort for Neo4jAdapter { } let statement = format!( r#" - MATCH (n:NextralEntity {{user_id:$user_id}}) + MATCH (n:NextralEntity {{tenant_id:$tenant_id, user_id:$user_id}}) WHERE any(term in $query_entities WHERE toLower(n.name) CONTAINS toLower(term)) MATCH p=(n)-[r:NEXTRAL_RELATES_TO*1..{}]-() + WHERE all(rel in relationships(p) WHERE rel.tenant_id = $tenant_id AND rel.user_id = $user_id) UNWIND relationships(p) as rel UNWIND rel.source_memory_ids as memory_id RETURN DISTINCT memory_id @@ -154,6 +155,7 @@ impl Neo4jPort for Neo4jAdapter { let body = self.cypher( &statement, json!({ + "tenant_id": scope.tenant_id, "user_id": scope.user_id, "query_entities": query_entities, }), @@ -171,7 +173,7 @@ impl Neo4jPort for Neo4jAdapter { fn redact_memory_edges(&self, scope: &TenantUserScope, memory_id: &str) -> CoreResult<()> { let statement = r#" - MATCH ()-[r:NEXTRAL_RELATES_TO {user_id:$user_id}]-() + MATCH ()-[r:NEXTRAL_RELATES_TO {tenant_id:$tenant_id, user_id:$user_id}]-() WHERE any(id in r.source_memory_ids WHERE id = $memory_id) SET r.source_memory_ids = [id IN r.source_memory_ids WHERE id <> $memory_id] WITH r @@ -181,6 +183,7 @@ impl Neo4jPort for Neo4jAdapter { self.cypher( statement, json!({ + "tenant_id": scope.tenant_id, "user_id": scope.user_id, "memory_id": memory_id }), diff --git a/src/adapters/qdrant.rs b/src/adapters/qdrant.rs index 887d1e8..843bd41 100644 --- a/src/adapters/qdrant.rs +++ b/src/adapters/qdrant.rs @@ -139,6 +139,11 @@ impl QdrantPort for QdrantAdapter { collection: &str, request: &VectorSearchRequest, ) -> CoreResult> { + let privacy_levels: Vec = request + .privacy_scope + .iter() + .map(|level| json!(level)) + .collect(); let payload = json!({ "vector": request.query_vector, "limit": request.top_k, @@ -147,6 +152,7 @@ impl QdrantPort for QdrantAdapter { "must": [ { "key": "tenant_id", "match": { "value": request.scope.tenant_id }}, { "key": "user_id", "match": { "value": request.scope.user_id }}, + { "key": "privacy_level", "match": { "any": privacy_levels }}, { "key": "status", "match": { "value": "active" }}, ] }