use mentedb::CognitiveConfig;
use mentedb::MenteDb;
use mentedb::prelude::*;
use mentedb::process_turn::{ProcessTurnInput, ProcessTurnResult};
use mentedb_context::DeltaTracker;
use mentedb_embedding::{EmbeddingProvider, HashEmbeddingProvider};
use uuid::Uuid;
const DIM: usize = 384;
fn now_us() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_micros() as u64
}
fn open_db() -> (MenteDb, tempfile::TempDir) {
let dir = tempfile::tempdir().unwrap();
let db = MenteDb::open_with_embedder_and_config(
dir.path(),
Box::new(HashEmbeddingProvider::new(DIM)),
CognitiveConfig::default(),
)
.unwrap();
(db, dir)
}
fn emb(text: &str) -> Vec<f32> {
HashEmbeddingProvider::new(DIM).embed(text).unwrap()
}
fn store_owned(db: &MenteDb, agent: AgentId, content: &str) -> MemoryId {
let node = MemoryNode::new(
agent,
MemoryType::Semantic,
content.to_string(),
emb(content),
);
let id = node.id;
db.store(node).unwrap();
id
}
fn result_text(r: &ProcessTurnResult) -> String {
let mut s = String::new();
for c in &r.context {
s.push_str(&c.memory.content);
s.push('\n');
}
for p in &r.proactive_recalls {
s.push_str(&p.content);
s.push('\n');
}
for w in &r.pain_warnings {
s.push_str(&w.description);
s.push('\n');
}
for t in &r.predicted_topics {
s.push_str(t);
s.push('\n');
}
s
}
const ALICE_SECRET: &str = "ALICE_SECRET the deployment key is falcon9 do not share";
const GLOBAL_NOTE: &str = "GLOBAL the office deploy runbook lives in the wiki";
#[test]
fn other_users_memory_never_leaks_into_a_turn() {
let (db, _dir) = open_db();
let mut delta = DeltaTracker::new();
let alice = Uuid::new_v4();
let bob = Uuid::new_v4();
store_owned(&db, AgentId(alice), ALICE_SECRET);
store_owned(&db, AgentId::nil(), GLOBAL_NOTE);
let input = ProcessTurnInput {
user_message: "help me deploy the new release to production".to_string(),
assistant_response: Some("sure, starting the deploy now".to_string()),
turn_id: 0,
project_context: None,
agent_id: Some(bob),
user_id: None,
session_id: None,
};
let bob_result = db.process_turn(&input, &mut delta).unwrap();
let leaked = result_text(&bob_result);
assert!(
!leaked.contains("ALICE_SECRET") && !leaked.contains("falcon9"),
"SECURITY: another user's private memory leaked into Bob's turn output:\n{leaked}"
);
}
#[test]
fn scoped_user_still_sees_own_and_global() {
let (db, _dir) = open_db();
let bob = AgentId::new();
let bob_own = store_owned(&db, bob, "bob prefers dark mode in the deploy dashboard");
let global = store_owned(&db, AgentId::nil(), GLOBAL_NOTE);
let alice_secret = store_owned(&db, AgentId::new(), ALICE_SECRET);
let hits = db
.recall_hybrid_scoped_at_mode(
&emb("deploy dashboard runbook"),
Some("deploy dashboard runbook"),
10,
now_us(),
None,
false,
None,
Some(bob),
None,
)
.unwrap();
let ids: Vec<MemoryId> = hits.iter().map(|(id, _)| *id).collect();
assert!(ids.contains(&bob_own), "user must see their own memory");
assert!(
ids.contains(&global),
"user must see global (nil owned) memory"
);
assert!(
!ids.contains(&alice_secret),
"user must never see another user's private memory"
);
}
#[test]
fn scoped_recall_excludes_other_users_even_as_top_match() {
let (db, _dir) = open_db();
let bob = AgentId::new();
let secret = store_owned(&db, AgentId::new(), ALICE_SECRET);
store_owned(&db, bob, "bob's unrelated note about lunch plans");
let hits = db
.recall_hybrid_scoped_at_mode(
&emb(ALICE_SECRET),
Some("deployment key falcon9"),
10,
now_us(),
None,
false,
None,
Some(bob),
None,
)
.unwrap();
let ids: Vec<MemoryId> = hits.iter().map(|(id, _)| *id).collect();
assert!(
!ids.contains(&secret),
"SECURITY: another user's private memory must never appear, even as the top match"
);
}
#[test]
fn enrichment_helpers_are_owner_scoped() {
let (db, _dir) = open_db();
let alice = AgentId::new();
let bob = AgentId::new();
let a = MemoryNode::new(
alice,
MemoryType::Semantic,
"alice likes falcons".into(),
emb("alice likes falcons"),
);
db.store(a).unwrap();
let b = MemoryNode::new(
bob,
MemoryType::Semantic,
"bob likes turtles".into(),
emb("bob likes turtles"),
);
db.store(b).unwrap();
let alice_facts = db.profile_facts(UserId::nil(), alice);
assert!(
alice_facts.iter().any(|f| f.contains("falcons")),
"alice sees her own fact"
);
assert!(
!alice_facts.iter().any(|f| f.contains("turtles")),
"alice must NOT see bob's fact in her profile facts"
);
let bob_facts = db.profile_facts(UserId::nil(), bob);
assert!(
!bob_facts.iter().any(|f| f.contains("falcons")),
"bob must NOT see alice's fact"
);
assert!(
bob_facts.iter().any(|f| f.contains("turtles")),
"bob sees his own fact"
);
}
#[test]
fn user_scoping_is_orthogonal_to_agent() {
let (db, _dir) = open_db();
let agent = AgentId::new();
let ua = UserId::new();
let ub = UserId::new();
let a = MemoryNode::new(
agent,
MemoryType::Semantic,
"user A secret plan".into(),
emb("user A secret plan"),
)
.with_user_id(ua);
let a_id = a.id;
db.store(a).unwrap();
let b = MemoryNode::new(
agent,
MemoryType::Semantic,
"user B secret plan".into(),
emb("user B secret plan"),
)
.with_user_id(ub);
db.store(b).unwrap();
let hits = db
.recall_hybrid_scoped_at_mode(
&emb("secret plan"),
Some("secret plan"),
10,
now_us(),
None,
false,
None,
Some(agent),
Some(ua),
)
.unwrap();
let ids: Vec<MemoryId> = hits.iter().map(|(id, _)| *id).collect();
assert!(ids.contains(&a_id), "user A sees own memory");
assert!(
hits.iter()
.filter_map(|(id, _)| db.get_memory(*id).ok())
.all(|m| !m.content.contains("user B")),
"user A must never see user B's memory under the same agent"
);
}
#[test]
fn profile_facts_are_orthogonal_to_agent() {
let (db, _dir) = open_db();
let agent = AgentId::new();
let ua = UserId::new();
let ub = UserId::new();
let a = MemoryNode::new(
agent,
MemoryType::Semantic,
"user A likes falcons".into(),
emb("user A likes falcons"),
)
.with_user_id(ua);
db.store(a).unwrap();
let b = MemoryNode::new(
agent,
MemoryType::Semantic,
"user B likes turtles".into(),
emb("user B likes turtles"),
)
.with_user_id(ub);
db.store(b).unwrap();
let a_facts = db.profile_facts(ua, agent);
assert!(
a_facts.iter().any(|f| f.contains("falcons")),
"user A sees own fact"
);
assert!(
!a_facts.iter().any(|f| f.contains("turtles")),
"user A must NOT see user B's fact under the same agent"
);
let b_facts = db.profile_facts(ub, agent);
assert!(
b_facts.iter().any(|f| f.contains("turtles")),
"user B sees own fact"
);
assert!(
!b_facts.iter().any(|f| f.contains("falcons")),
"user B must NOT see user A's fact under the same agent"
);
}