20230728 techdebt paydown ()

This commit is contained in:
Firstyear 2023-07-31 12:20:52 +10:00 committed by GitHub
parent ea4d755d7b
commit d731b20a9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 1611 additions and 1920 deletions

View file

@ -451,7 +451,7 @@ pub async fn domain_rename_core(config: &Configuration) {
let mut qs_write = qs.write(duration_from_epoch_now()).await;
let r = qs_write
.domain_rename(new_domain_name)
.danger_domain_rename(new_domain_name)
.and_then(|_| qs_write.commit());
match r {

View file

@ -1062,14 +1062,22 @@ impl<'a> IdlArcSqliteWriteTransaction<'a> {
self.db.create_idx(attr, itype)
}
pub unsafe fn purge_idxs(&mut self) -> Result<(), OperationError> {
self.db.purge_idxs().map(|()| {
/// ⚠️ - This function will destroy all indexes in the database.
///
/// It should only be called internally by the backend in limited and
/// specific situations.
pub fn danger_purge_idxs(&mut self) -> Result<(), OperationError> {
self.db.danger_purge_idxs().map(|()| {
self.idl_cache.clear();
})
}
pub unsafe fn purge_id2entry(&mut self) -> Result<(), OperationError> {
self.db.purge_id2entry().map(|()| {
/// ⚠️ - This function will destroy all entries in the database.
///
/// It should only be called internally by the backend in limited and
/// specific situations.
pub fn danger_purge_id2entry(&mut self) -> Result<(), OperationError> {
self.db.danger_purge_id2entry().map(|()| {
let mut ids = IDLBitRange::new();
ids.compress();
std::mem::swap(self.allids.deref_mut(), &mut ids);

View file

@ -541,14 +541,12 @@ pub trait IdlSqliteTransaction {
// This allow is critical as it resolves a life time issue in stmt.
#[allow(clippy::let_and_return)]
fn verify(&self) -> Vec<Result<(), ConsistencyError>> {
let conn = match self.get_conn() {
Ok(conn) => conn,
Err(_) => return vec![Err(ConsistencyError::SqliteIntegrityFailure)],
let Ok(conn) = self.get_conn() else {
return vec![Err(ConsistencyError::SqliteIntegrityFailure)]
};
let mut stmt = match conn.prepare("PRAGMA integrity_check;") {
Ok(r) => r,
Err(_) => return vec![Err(ConsistencyError::SqliteIntegrityFailure)],
let Ok(mut stmt) = conn.prepare("PRAGMA integrity_check;") else {
return vec![Err(ConsistencyError::SqliteIntegrityFailure)]
};
// Allow this as it actually extends the life of stmt
@ -1034,7 +1032,11 @@ impl IdlSqliteWriteTransaction {
.map_err(sqlite_error)
}
pub unsafe fn purge_idxs(&self) -> Result<(), OperationError> {
/// ⚠️ - This function will destroy all indexes in the database.
///
/// It should only be called internally by the backend in limited and
/// specific situations.
pub fn danger_purge_idxs(&self) -> Result<(), OperationError> {
let idx_table_list = self.list_idxs()?;
idx_table_list.iter().try_for_each(|idx_table| {
@ -1124,7 +1126,11 @@ impl IdlSqliteWriteTransaction {
Ok(slope)
}
pub unsafe fn purge_id2entry(&self) -> Result<(), OperationError> {
/// ⚠️ - This function will destroy all entries in the database.
///
/// It should only be called internally by the backend in limited and
/// specific situations.
pub fn danger_purge_id2entry(&self) -> Result<(), OperationError> {
self.get_conn()?
.execute(&format!("DELETE FROM {}.id2entry", self.get_db_name()), [])
.map(|_| ())

View file

@ -431,14 +431,11 @@ pub trait BackendTransaction {
for f in f_andnot.iter() {
f_rem_count -= 1;
let f_in = match f {
FilterResolved::AndNot(f_in, _) => f_in,
_ => {
filter_error!(
"Invalid server state, a cand filter leaked to andnot set!"
);
return Err(OperationError::InvalidState);
}
let FilterResolved::AndNot(f_in, _) = f else {
filter_error!(
"Invalid server state, a cand filter leaked to andnot set!"
);
return Err(OperationError::InvalidState);
};
let (inter, fp) = self.filter2idl(f_in, thres)?;
// It's an and not, so we need to wrap the plan accordingly.
@ -754,12 +751,9 @@ pub trait BackendTransaction {
// We only check these on live entries.
let (n2u_add, n2u_rem) = Entry::idx_name2uuid_diff(None, Some(e));
let n2u_set = match (n2u_add, n2u_rem) {
(Some(set), None) => set,
(_, _) => {
admin_error!("Invalid idx_name2uuid_diff state");
return Err(ConsistencyError::BackendIndexSync);
}
let (Some(n2u_set), None) = (n2u_add, n2u_rem) else {
admin_error!("Invalid idx_name2uuid_diff state");
return Err(ConsistencyError::BackendIndexSync);
};
// If the set.len > 1, check each item.
@ -1588,7 +1582,7 @@ impl<'a> BackendWriteTransaction<'a> {
pub fn reindex(&mut self) -> Result<(), OperationError> {
// Purge the idxs
unsafe { self.idlayer.purge_idxs()? };
self.idlayer.danger_purge_idxs()?;
// Using the index metadata on the txn, create all our idx tables
self.create_idxs()?;
@ -1632,17 +1626,23 @@ impl<'a> BackendWriteTransaction<'a> {
Ok(())
}
fn purge_idxs(&mut self) -> Result<(), OperationError> {
unsafe { self.get_idlayer().purge_idxs() }
/// ⚠️ - This function will destroy all indexes in the database.
///
/// It should only be called internally by the backend in limited and
/// specific situations.
fn danger_purge_idxs(&mut self) -> Result<(), OperationError> {
self.get_idlayer().danger_purge_idxs()
}
/// ⚠️ - This function will destroy all entries and indexes in the database.
///
/// It should only be called internally by the backend in limited and
/// specific situations.
pub(crate) fn danger_delete_all_db_content(&mut self) -> Result<(), OperationError> {
self.get_ruv().clear();
unsafe {
self.get_idlayer()
.purge_id2entry()
.and_then(|_| self.purge_idxs())
}
self.get_idlayer()
.danger_purge_id2entry()
.and_then(|_| self.danger_purge_idxs())
}
#[cfg(test)]
@ -1678,7 +1678,7 @@ impl<'a> BackendWriteTransaction<'a> {
OperationError::FsError
})?;
unsafe { idlayer.purge_id2entry() }.map_err(|e| {
idlayer.danger_purge_id2entry().map_err(|e| {
admin_error!("purge_id2entry failed {:?}", e);
e
})?;
@ -1997,10 +1997,10 @@ mod tests {
use crate::value::{IndexType, PartialValue, Value};
lazy_static! {
static ref CID_ZERO: Cid = unsafe { Cid::new_zero() };
static ref CID_ONE: Cid = unsafe { Cid::new_count(1) };
static ref CID_TWO: Cid = unsafe { Cid::new_count(2) };
static ref CID_THREE: Cid = unsafe { Cid::new_count(3) };
static ref CID_ZERO: Cid = Cid::new_zero();
static ref CID_ONE: Cid = Cid::new_count(1);
static ref CID_TWO: Cid = Cid::new_count(2);
static ref CID_THREE: Cid = Cid::new_count(3);
}
macro_rules! run_test {
@ -2053,12 +2053,11 @@ mod tests {
macro_rules! entry_exists {
($be:expr, $ent:expr) => {{
let ei = unsafe { $ent.clone().into_sealed_committed() };
let filt = unsafe {
ei.filter_from_attrs(&vec![AttrString::from("uuid")])
.expect("failed to generate filter")
.into_valid_resolved()
};
let ei = $ent.clone().into_sealed_committed();
let filt = ei
.filter_from_attrs(&vec![AttrString::from("uuid")])
.expect("failed to generate filter")
.into_valid_resolved();
let lims = Limits::unlimited();
let entries = $be.search(&lims, &filt).expect("failed to search");
entries.first().is_some()
@ -2067,12 +2066,11 @@ mod tests {
macro_rules! entry_attr_pres {
($be:expr, $ent:expr, $attr:expr) => {{
let ei = unsafe { $ent.clone().into_sealed_committed() };
let filt = unsafe {
ei.filter_from_attrs(&vec![AttrString::from("userid")])
.expect("failed to generate filter")
.into_valid_resolved()
};
let ei = $ent.clone().into_sealed_committed();
let filt = ei
.filter_from_attrs(&vec![AttrString::from("userid")])
.expect("failed to generate filter")
.into_valid_resolved();
let lims = Limits::unlimited();
let entries = $be.search(&lims, &filt).expect("failed to search");
match entries.first() {
@ -2104,7 +2102,7 @@ mod tests {
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
e.add_ava("userid", Value::from("william"));
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
let e = unsafe { e.into_sealed_new() };
let e = e.into_sealed_new();
let single_result = be.create(&CID_ZERO, vec![e.clone()]);
@ -2123,14 +2121,13 @@ mod tests {
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
e.add_ava("userid", Value::from("claire"));
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
let e = unsafe { e.into_sealed_new() };
let e = e.into_sealed_new();
let single_result = be.create(&CID_ZERO, vec![e]);
assert!(single_result.is_ok());
// Test a simple EQ search
let filt =
unsafe { filter_resolved!(f_eq("userid", PartialValue::new_utf8s("claire"))) };
let filt = filter_resolved!(f_eq("userid", PartialValue::new_utf8s("claire")));
let lims = Limits::unlimited();
@ -2159,8 +2156,8 @@ mod tests {
e2.add_ava("userid", Value::from("alice"));
e2.add_ava("uuid", Value::from("4b6228ab-1dbe-42a4-a9f5-f6368222438e"));
let ve1 = unsafe { e1.clone().into_sealed_new() };
let ve2 = unsafe { e2.clone().into_sealed_new() };
let ve1 = e1.clone().into_sealed_new();
let ve2 = e2.clone().into_sealed_new();
assert!(be.create(&CID_ZERO, vec![ve1, ve2]).is_ok());
assert!(entry_exists!(be, e1));
@ -2168,20 +2165,20 @@ mod tests {
// You need to now retrieve the entries back out to get the entry id's
let mut results = be
.search(&lims, unsafe { &filter_resolved!(f_pres("userid")) })
.search(&lims, &filter_resolved!(f_pres("userid")))
.expect("Failed to search");
// Get these out to usable entries.
let r1 = results.remove(0);
let r2 = results.remove(0);
let mut r1 = unsafe { r1.as_ref().clone().into_invalid() };
let mut r2 = unsafe { r2.as_ref().clone().into_invalid() };
let mut r1 = r1.as_ref().clone().into_invalid();
let mut r2 = r2.as_ref().clone().into_invalid();
// Modify no id (err)
// This is now impossible due to the state machine design.
// However, with some unsafe ....
let ue1 = unsafe { e1.clone().into_sealed_committed() };
let ue1 = e1.clone().into_sealed_committed();
assert!(be
.modify(&CID_ZERO, &[Arc::new(ue1.clone())], &[ue1])
.is_err());
@ -2189,15 +2186,15 @@ mod tests {
assert!(be.modify(&CID_ZERO, &[], &[]).is_err());
// Make some changes to r1, r2.
let pre1 = unsafe { Arc::new(r1.clone().into_sealed_committed()) };
let pre2 = unsafe { Arc::new(r2.clone().into_sealed_committed()) };
let pre1 = Arc::new(r1.clone().into_sealed_committed());
let pre2 = Arc::new(r2.clone().into_sealed_committed());
r1.add_ava("desc", Value::from("modified"));
r2.add_ava("desc", Value::from("modified"));
// Now ... cheat.
let vr1 = unsafe { r1.into_sealed_committed() };
let vr2 = unsafe { r2.into_sealed_committed() };
let vr1 = r1.into_sealed_committed();
let vr2 = r2.into_sealed_committed();
// Modify single
assert!(be.modify(&CID_ZERO, &[pre1], &[vr1.clone()]).is_ok());
@ -2238,9 +2235,9 @@ mod tests {
e3.add_ava("userid", Value::from("lucy"));
e3.add_ava("uuid", Value::from("7b23c99d-c06b-4a9a-a958-3afa56383e1d"));
let ve1 = unsafe { e1.clone().into_sealed_new() };
let ve2 = unsafe { e2.clone().into_sealed_new() };
let ve3 = unsafe { e3.clone().into_sealed_new() };
let ve1 = e1.clone().into_sealed_new();
let ve2 = e2.clone().into_sealed_new();
let ve3 = e3.clone().into_sealed_new();
assert!(be.create(&CID_ZERO, vec![ve1, ve2, ve3]).is_ok());
assert!(entry_exists!(be, e1));
@ -2249,7 +2246,7 @@ mod tests {
// You need to now retrieve the entries back out to get the entry id's
let mut results = be
.search(&lims, unsafe { &filter_resolved!(f_pres("userid")) })
.search(&lims, &filter_resolved!(f_pres("userid")))
.expect("Failed to search");
// Get these out to usable entries.
@ -2262,12 +2259,12 @@ mod tests {
// Put them into the tombstone state, and write that down.
// This sets up the RUV with the changes.
let r1_ts = unsafe { r1.to_tombstone(CID_ONE.clone()).into_sealed_committed() };
let r1_ts = r1.to_tombstone(CID_ONE.clone()).into_sealed_committed();
assert!(be.modify(&CID_ONE, &[r1], &[r1_ts.clone()]).is_ok());
let r2_ts = unsafe { r2.to_tombstone(CID_TWO.clone()).into_sealed_committed() };
let r3_ts = unsafe { r3.to_tombstone(CID_TWO.clone()).into_sealed_committed() };
let r2_ts = r2.to_tombstone(CID_TWO.clone()).into_sealed_committed();
let r3_ts = r3.to_tombstone(CID_TWO.clone()).into_sealed_committed();
assert!(be
.modify(&CID_TWO, &[r2, r3], &[r2_ts.clone(), r3_ts.clone()])
@ -2334,9 +2331,9 @@ mod tests {
e3.add_ava("userid", Value::from("lucy"));
e3.add_ava("uuid", Value::from("7b23c99d-c06b-4a9a-a958-3afa56383e1d"));
let ve1 = unsafe { e1.clone().into_sealed_new() };
let ve2 = unsafe { e2.clone().into_sealed_new() };
let ve3 = unsafe { e3.clone().into_sealed_new() };
let ve1 = e1.clone().into_sealed_new();
let ve2 = e2.clone().into_sealed_new();
let ve3 = e3.clone().into_sealed_new();
assert!(be.create(&CID_ZERO, vec![ve1, ve2, ve3]).is_ok());
assert!(entry_exists!(be, e1));
@ -2389,9 +2386,9 @@ mod tests {
e3.add_ava("userid", Value::from("lucy"));
e3.add_ava("uuid", Value::from("7b23c99d-c06b-4a9a-a958-3afa56383e1d"));
let ve1 = unsafe { e1.clone().into_sealed_new() };
let ve2 = unsafe { e2.clone().into_sealed_new() };
let ve3 = unsafe { e3.clone().into_sealed_new() };
let ve1 = e1.clone().into_sealed_new();
let ve2 = e2.clone().into_sealed_new();
let ve3 = e3.clone().into_sealed_new();
assert!(be.create(&CID_ZERO, vec![ve1, ve2, ve3]).is_ok());
assert!(entry_exists!(be, e1));
@ -2475,17 +2472,17 @@ mod tests {
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
e1.add_ava("name", Value::new_iname("william"));
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
let e1 = unsafe { e1.into_sealed_new() };
let e1 = e1.into_sealed_new();
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
e2.add_ava("name", Value::new_iname("claire"));
e2.add_ava("uuid", Value::from("bd651620-00dd-426b-aaa0-4494f7b7906f"));
let e2 = unsafe { e2.into_sealed_new() };
let e2 = e2.into_sealed_new();
be.create(&CID_ZERO, vec![e1, e2]).unwrap();
// purge indexes
be.purge_idxs().unwrap();
be.danger_purge_idxs().unwrap();
// Check they are gone
let missing = be.missing_idxs().unwrap();
assert!(missing.len() == 7);
@ -2572,7 +2569,7 @@ mod tests {
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
e1.add_ava("name", Value::from("william"));
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
let e1 = unsafe { e1.into_sealed_new() };
let e1 = e1.into_sealed_new();
let rset = be.create(&CID_ZERO, vec![e1]).unwrap();
let mut rset: Vec<_> = rset.into_iter().map(Arc::new).collect();
@ -2598,7 +2595,7 @@ mod tests {
assert!(be.uuid2rdn(william_uuid) == Ok(Some("name=william".to_string())));
// == Now we reap_tombstones, and assert we removed the items.
let e1_ts = unsafe { e1.to_tombstone(CID_ONE.clone()).into_sealed_committed() };
let e1_ts = e1.to_tombstone(CID_ONE.clone()).into_sealed_committed();
assert!(be.modify(&CID_ONE, &[e1], &[e1_ts]).is_ok());
be.reap_tombstones(&CID_TWO).unwrap();
@ -2633,17 +2630,17 @@ mod tests {
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
e1.add_ava("name", Value::new_iname("william"));
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
let e1 = unsafe { e1.into_sealed_new() };
let e1 = e1.into_sealed_new();
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
e2.add_ava("name", Value::new_iname("claire"));
e2.add_ava("uuid", Value::from("bd651620-00dd-426b-aaa0-4494f7b7906f"));
let e2 = unsafe { e2.into_sealed_new() };
let e2 = e2.into_sealed_new();
let mut e3: Entry<EntryInit, EntryNew> = Entry::new();
e3.add_ava("userid", Value::new_iname("lucy"));
e3.add_ava("uuid", Value::from("7b23c99d-c06b-4a9a-a958-3afa56383e1d"));
let e3 = unsafe { e3.into_sealed_new() };
let e3 = e3.into_sealed_new();
let mut rset = be.create(&CID_ZERO, vec![e1, e2, e3]).unwrap();
rset.remove(1);
@ -2652,8 +2649,8 @@ mod tests {
let e3 = rset.pop().unwrap();
// Now remove e1, e3.
let e1_ts = unsafe { e1.to_tombstone(CID_ONE.clone()).into_sealed_committed() };
let e3_ts = unsafe { e3.to_tombstone(CID_ONE.clone()).into_sealed_committed() };
let e1_ts = e1.to_tombstone(CID_ONE.clone()).into_sealed_committed();
let e3_ts = e3.to_tombstone(CID_ONE.clone()).into_sealed_committed();
assert!(be.modify(&CID_ONE, &[e1, e3], &[e1_ts, e3_ts]).is_ok());
be.reap_tombstones(&CID_TWO).unwrap();
@ -2702,12 +2699,12 @@ mod tests {
e1.add_ava("name", Value::new_iname("william"));
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
e1.add_ava("ta", Value::from("test"));
let e1 = unsafe { e1.into_sealed_new() };
let e1 = e1.into_sealed_new();
let rset = be.create(&CID_ZERO, vec![e1]).unwrap();
let rset: Vec<_> = rset.into_iter().map(Arc::new).collect();
// Now, alter the new entry.
let mut ce1 = unsafe { rset[0].as_ref().clone().into_invalid() };
let mut ce1 = rset[0].as_ref().clone().into_invalid();
// add something.
ce1.add_ava("tb", Value::from("test"));
// remove something.
@ -2716,7 +2713,7 @@ mod tests {
ce1.purge_ava("name");
ce1.add_ava("name", Value::new_iname("claire"));
let ce1 = unsafe { ce1.into_sealed_committed() };
let ce1 = ce1.into_sealed_committed();
be.modify(&CID_ZERO, &rset, &[ce1]).unwrap();
@ -2747,17 +2744,17 @@ mod tests {
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
e1.add_ava("name", Value::new_iname("william"));
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
let e1 = unsafe { e1.into_sealed_new() };
let e1 = e1.into_sealed_new();
let rset = be.create(&CID_ZERO, vec![e1]).unwrap();
let rset: Vec<_> = rset.into_iter().map(Arc::new).collect();
// Now, alter the new entry.
let mut ce1 = unsafe { rset[0].as_ref().clone().into_invalid() };
let mut ce1 = rset[0].as_ref().clone().into_invalid();
ce1.purge_ava("name");
ce1.purge_ava("uuid");
ce1.add_ava("name", Value::new_iname("claire"));
ce1.add_ava("uuid", Value::from("04091a7a-6ce4-42d2-abf5-c2ce244ac9e8"));
let ce1 = unsafe { ce1.into_sealed_committed() };
let ce1 = ce1.into_sealed_committed();
be.modify(&CID_ZERO, &rset, &[ce1]).unwrap();
@ -2805,17 +2802,16 @@ mod tests {
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
e1.add_ava("no-index", Value::from("william"));
e1.add_ava("other-no-index", Value::from("william"));
let e1 = unsafe { e1.into_sealed_new() };
let e1 = e1.into_sealed_new();
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
e2.add_ava("name", Value::new_iname("claire"));
e2.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d2"));
let e2 = unsafe { e2.into_sealed_new() };
let e2 = e2.into_sealed_new();
let _rset = be.create(&CID_ZERO, vec![e1, e2]).unwrap();
// Test fully unindexed
let f_un =
unsafe { filter_resolved!(f_eq("no-index", PartialValue::new_utf8s("william"))) };
let f_un = filter_resolved!(f_eq("no-index", PartialValue::new_utf8s("william")));
let (r, _plan) = be.filter2idl(f_un.to_inner(), 0).unwrap();
match r {
@ -2826,7 +2822,7 @@ mod tests {
}
// Test that a fully indexed search works
let feq = unsafe { filter_resolved!(f_eq("name", PartialValue::new_utf8s("william"))) };
let feq = filter_resolved!(f_eq("name", PartialValue::new_utf8s("william")));
let (r, _plan) = be.filter2idl(feq.to_inner(), 0).unwrap();
match r {
@ -2840,15 +2836,13 @@ mod tests {
// Test and/or
// full index and
let f_in_and = unsafe {
filter_resolved!(f_and!([
f_eq("name", PartialValue::new_utf8s("william")),
f_eq(
"uuid",
PartialValue::new_utf8s("db237e8a-0079-4b8c-8a56-593b22aa44d1")
)
]))
};
let f_in_and = filter_resolved!(f_and!([
f_eq("name", PartialValue::new_utf8s("william")),
f_eq(
"uuid",
PartialValue::new_utf8s("db237e8a-0079-4b8c-8a56-593b22aa44d1")
)
]));
let (r, _plan) = be.filter2idl(f_in_and.to_inner(), 0).unwrap();
match r {
@ -2861,19 +2855,15 @@ mod tests {
}
// partial index and
let f_p1 = unsafe {
filter_resolved!(f_and!([
f_eq("name", PartialValue::new_utf8s("william")),
f_eq("no-index", PartialValue::new_utf8s("william"))
]))
};
let f_p1 = filter_resolved!(f_and!([
f_eq("name", PartialValue::new_utf8s("william")),
f_eq("no-index", PartialValue::new_utf8s("william"))
]));
let f_p2 = unsafe {
filter_resolved!(f_and!([
f_eq("name", PartialValue::new_utf8s("william")),
f_eq("no-index", PartialValue::new_utf8s("william"))
]))
};
let f_p2 = filter_resolved!(f_and!([
f_eq("name", PartialValue::new_utf8s("william")),
f_eq("no-index", PartialValue::new_utf8s("william"))
]));
let (r, _plan) = be.filter2idl(f_p1.to_inner(), 0).unwrap();
match r {
@ -2896,12 +2886,10 @@ mod tests {
}
// no index and
let f_no_and = unsafe {
filter_resolved!(f_and!([
f_eq("no-index", PartialValue::new_utf8s("william")),
f_eq("other-no-index", PartialValue::new_utf8s("william"))
]))
};
let f_no_and = filter_resolved!(f_and!([
f_eq("no-index", PartialValue::new_utf8s("william")),
f_eq("other-no-index", PartialValue::new_utf8s("william"))
]));
let (r, _plan) = be.filter2idl(f_no_and.to_inner(), 0).unwrap();
match r {
@ -2912,9 +2900,8 @@ mod tests {
}
// full index or
let f_in_or = unsafe {
filter_resolved!(f_or!([f_eq("name", PartialValue::new_utf8s("william"))]))
};
let f_in_or =
filter_resolved!(f_or!([f_eq("name", PartialValue::new_utf8s("william"))]));
let (r, _plan) = be.filter2idl(f_in_or.to_inner(), 0).unwrap();
match r {
@ -2926,12 +2913,10 @@ mod tests {
}
}
// partial (aka allids) or
let f_un_or = unsafe {
filter_resolved!(f_or!([f_eq(
"no-index",
PartialValue::new_utf8s("william")
)]))
};
let f_un_or = filter_resolved!(f_or!([f_eq(
"no-index",
PartialValue::new_utf8s("william")
)]));
let (r, _plan) = be.filter2idl(f_un_or.to_inner(), 0).unwrap();
match r {
@ -2942,9 +2927,8 @@ mod tests {
}
// Test root andnot
let f_r_andnot = unsafe {
filter_resolved!(f_andnot(f_eq("name", PartialValue::new_utf8s("william"))))
};
let f_r_andnot =
filter_resolved!(f_andnot(f_eq("name", PartialValue::new_utf8s("william"))));
let (r, _plan) = be.filter2idl(f_r_andnot.to_inner(), 0).unwrap();
match r {
@ -2957,12 +2941,10 @@ mod tests {
}
// test andnot as only in and
let f_and_andnot = unsafe {
filter_resolved!(f_and!([f_andnot(f_eq(
"name",
PartialValue::new_utf8s("william")
))]))
};
let f_and_andnot = filter_resolved!(f_and!([f_andnot(f_eq(
"name",
PartialValue::new_utf8s("william")
))]));
let (r, _plan) = be.filter2idl(f_and_andnot.to_inner(), 0).unwrap();
match r {
@ -2974,12 +2956,10 @@ mod tests {
}
}
// test andnot as only in or
let f_or_andnot = unsafe {
filter_resolved!(f_or!([f_andnot(f_eq(
"name",
PartialValue::new_utf8s("william")
))]))
};
let f_or_andnot = filter_resolved!(f_or!([f_andnot(f_eq(
"name",
PartialValue::new_utf8s("william")
))]));
let (r, _plan) = be.filter2idl(f_or_andnot.to_inner(), 0).unwrap();
match r {
@ -2992,12 +2972,10 @@ mod tests {
}
// test andnot in and (first) with name
let f_and_andnot = unsafe {
filter_resolved!(f_and!([
f_andnot(f_eq("name", PartialValue::new_utf8s("claire"))),
f_pres("name")
]))
};
let f_and_andnot = filter_resolved!(f_and!([
f_andnot(f_eq("name", PartialValue::new_utf8s("claire"))),
f_pres("name")
]));
let (r, _plan) = be.filter2idl(f_and_andnot.to_inner(), 0).unwrap();
match r {
@ -3010,12 +2988,10 @@ mod tests {
}
}
// test andnot in and (last) with name
let f_and_andnot = unsafe {
filter_resolved!(f_and!([
f_pres("name"),
f_andnot(f_eq("name", PartialValue::new_utf8s("claire")))
]))
};
let f_and_andnot = filter_resolved!(f_and!([
f_pres("name"),
f_andnot(f_eq("name", PartialValue::new_utf8s("claire")))
]));
let (r, _plan) = be.filter2idl(f_and_andnot.to_inner(), 0).unwrap();
match r {
@ -3027,12 +3003,10 @@ mod tests {
}
}
// test andnot in and (first) with no-index
let f_and_andnot = unsafe {
filter_resolved!(f_and!([
f_andnot(f_eq("name", PartialValue::new_utf8s("claire"))),
f_pres("no-index")
]))
};
let f_and_andnot = filter_resolved!(f_and!([
f_andnot(f_eq("name", PartialValue::new_utf8s("claire"))),
f_pres("no-index")
]));
let (r, _plan) = be.filter2idl(f_and_andnot.to_inner(), 0).unwrap();
match r {
@ -3042,12 +3016,10 @@ mod tests {
}
}
// test andnot in and (last) with no-index
let f_and_andnot = unsafe {
filter_resolved!(f_and!([
f_pres("no-index"),
f_andnot(f_eq("name", PartialValue::new_utf8s("claire")))
]))
};
let f_and_andnot = filter_resolved!(f_and!([
f_pres("no-index"),
f_andnot(f_eq("name", PartialValue::new_utf8s("claire")))
]));
let (r, _plan) = be.filter2idl(f_and_andnot.to_inner(), 0).unwrap();
match r {
@ -3058,7 +3030,7 @@ mod tests {
}
// empty or
let f_e_or = unsafe { filter_resolved!(f_or!([])) };
let f_e_or = filter_resolved!(f_or!([]));
let (r, _plan) = be.filter2idl(f_e_or.to_inner(), 0).unwrap();
match r {
@ -3070,7 +3042,7 @@ mod tests {
}
}
let f_e_and = unsafe { filter_resolved!(f_and!([])) };
let f_e_and = filter_resolved!(f_and!([]));
let (r, _plan) = be.filter2idl(f_e_and.to_inner(), 0).unwrap();
match r {
@ -3089,10 +3061,9 @@ mod tests {
run_test!(|be: &mut BackendWriteTransaction| {
// Test where the index is in schema but not created (purge idxs)
// should fall back to an empty set because we can't satisfy the term
be.purge_idxs().unwrap();
be.danger_purge_idxs().unwrap();
debug!("{:?}", be.missing_idxs().unwrap());
let f_eq =
unsafe { filter_resolved!(f_eq("name", PartialValue::new_utf8s("william"))) };
let f_eq = filter_resolved!(f_eq("name", PartialValue::new_utf8s("william")));
let (r, _plan) = be.filter2idl(f_eq.to_inner(), 0).unwrap();
match r {
@ -3113,21 +3084,21 @@ mod tests {
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
e1.add_ava("ta", Value::from("dupe"));
e1.add_ava("tb", Value::from("1"));
let e1 = unsafe { e1.into_sealed_new() };
let e1 = e1.into_sealed_new();
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
e2.add_ava("name", Value::new_iname("claire"));
e2.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d2"));
e2.add_ava("ta", Value::from("dupe"));
e2.add_ava("tb", Value::from("1"));
let e2 = unsafe { e2.into_sealed_new() };
let e2 = e2.into_sealed_new();
let mut e3: Entry<EntryInit, EntryNew> = Entry::new();
e3.add_ava("name", Value::new_iname("benny"));
e3.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d3"));
e3.add_ava("ta", Value::from("dupe"));
e3.add_ava("tb", Value::from("2"));
let e3 = unsafe { e3.into_sealed_new() };
let e3 = e3.into_sealed_new();
let _rset = be.create(&CID_ZERO, vec![e1, e2, e3]).unwrap();
@ -3212,15 +3183,14 @@ mod tests {
e.add_ava("userid", Value::from("william"));
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
e.add_ava("nonexist", Value::from("x"));
let e = unsafe { e.into_sealed_new() };
let e = e.into_sealed_new();
let single_result = be.create(&CID_ZERO, vec![e.clone()]);
assert!(single_result.is_ok());
let filt = unsafe {
e.filter_from_attrs(&[AttrString::from("nonexist")])
.expect("failed to generate filter")
.into_valid_resolved()
};
let filt = e
.filter_from_attrs(&[AttrString::from("nonexist")])
.expect("failed to generate filter")
.into_valid_resolved();
// check allow on allids
let res = be.search(&lim_allow_allids, &filt);
assert!(res.is_ok());
@ -3248,15 +3218,14 @@ mod tests {
e.add_ava("userid", Value::from("william"));
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
e.add_ava("nonexist", Value::from("x"));
let e = unsafe { e.into_sealed_new() };
let e = e.into_sealed_new();
let single_result = be.create(&CID_ZERO, vec![e.clone()]);
assert!(single_result.is_ok());
let filt = unsafe {
e.filter_from_attrs(&[AttrString::from("nonexist")])
.expect("failed to generate filter")
.into_valid_resolved()
};
let filt = e
.filter_from_attrs(&[AttrString::from("nonexist")])
.expect("failed to generate filter")
.into_valid_resolved();
// --> This is the all ids path (unindexed)
// check allow on entry max
@ -3306,7 +3275,7 @@ mod tests {
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
e.add_ava("nonexist", Value::from("x"));
e.add_ava("nonexist", Value::from("y"));
let e = unsafe { e.into_sealed_new() };
let e = e.into_sealed_new();
let single_result = be.create(&CID_ZERO, vec![e]);
assert!(single_result.is_ok());
@ -3323,18 +3292,16 @@ mod tests {
//
// This creates a partial, and because it's the first iteration in the loop, this
// doesn't encounter partial threshold testing.
let filt = unsafe {
filter_resolved!(f_and!([
f_or!([
f_eq("nonexist", PartialValue::new_utf8s("x")),
f_eq("nonexist", PartialValue::new_utf8s("y"))
]),
f_or!([
f_eq("name", PartialValue::new_utf8s("claire")),
f_eq("name", PartialValue::new_utf8s("william"))
]),
]))
};
let filt = filter_resolved!(f_and!([
f_or!([
f_eq("nonexist", PartialValue::new_utf8s("x")),
f_eq("nonexist", PartialValue::new_utf8s("y"))
]),
f_or!([
f_eq("name", PartialValue::new_utf8s("claire")),
f_eq("name", PartialValue::new_utf8s("william"))
]),
]));
let res = be.search(&lim_allow, &filt);
assert!(res.is_ok());
@ -3375,14 +3342,14 @@ mod tests {
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
e.add_ava("userid", Value::from("william"));
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
let e = unsafe { e.into_sealed_new() };
let e = e.into_sealed_new();
let single_result = be_a_txn.create(&CID_ZERO, vec![e]);
assert!(single_result.is_ok());
// Assert it's in A but not B.
let filt = unsafe { filter_resolved!(f_eq("userid", PartialValue::new_utf8s("william"))) };
let filt = filter_resolved!(f_eq("userid", PartialValue::new_utf8s("william")));
let lims = Limits::unlimited();
@ -3396,14 +3363,14 @@ mod tests {
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
e.add_ava("userid", Value::from("claire"));
e.add_ava("uuid", Value::from("0c680959-0944-47d6-9dea-53304d124266"));
let e = unsafe { e.into_sealed_new() };
let e = e.into_sealed_new();
let single_result = be_b_txn.create(&CID_ZERO, vec![e]);
assert!(single_result.is_ok());
// Assert it's in B but not A
let filt = unsafe { filter_resolved!(f_eq("userid", PartialValue::new_utf8s("claire"))) };
let filt = filter_resolved!(f_eq("userid", PartialValue::new_utf8s("claire")));
let lims = Limits::unlimited();

View file

@ -522,12 +522,14 @@ impl Entry<EntryInit, EntryNew> {
compare_attrs(&self.attrs, &rhs.attrs)
}
/// ⚠️ This function bypasses the db commit and creates invalid replication metadata.
/// The entry it creates can never be replicated.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_invalid_new(mut self) -> Entry<EntryInvalid, EntryNew> {
pub fn into_invalid_new(mut self) -> Entry<EntryInvalid, EntryNew> {
let cid = Cid::new_zero();
self.set_last_changed(cid.clone());
// let eclog = EntryChangelog::new_without_schema(cid.clone(), self.attrs.clone());
let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
Entry {
@ -537,11 +539,13 @@ impl Entry<EntryInit, EntryNew> {
}
}
/// ⚠️ This function bypasses the db commit and creates invalid replication metadata.
/// The entry it creates can never be replicated.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_valid_new(mut self) -> Entry<EntryValid, EntryNew> {
pub fn into_valid_new(mut self) -> Entry<EntryValid, EntryNew> {
let cid = Cid::new_zero();
self.set_last_changed(cid.clone());
// let eclog = EntryChangelog::new_without_schema(cid.clone(), self.attrs.clone());
let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
Entry {
@ -554,11 +558,13 @@ impl Entry<EntryInit, EntryNew> {
}
}
/// ⚠️ This function bypasses the db commit, assigns fake db ids, and invalid replication metadata.
/// The entry it creates can never be committed safely or replicated.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_sealed_committed(mut self) -> Entry<EntrySealed, EntryCommitted> {
pub fn into_sealed_committed(mut self) -> Entry<EntrySealed, EntryCommitted> {
let cid = Cid::new_zero();
self.set_last_changed(cid.clone());
// let eclog = EntryChangelog::new_without_schema(cid, self.attrs.clone());
let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
Entry {
@ -568,11 +574,13 @@ impl Entry<EntryInit, EntryNew> {
}
}
/// ⚠️ This function bypasses the db commit and creates invalid replication metadata.
/// The entry it creates can never be replicated.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_sealed_new(mut self) -> Entry<EntrySealed, EntryNew> {
pub fn into_sealed_new(mut self) -> Entry<EntrySealed, EntryNew> {
let cid = Cid::new_zero();
self.set_last_changed(cid.clone());
// let eclog = EntryChangelog::new_without_schema(cid, self.attrs.clone());
let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
Entry {
@ -1103,13 +1111,12 @@ where
}
}
/*
* A series of unsafe transitions allowing entries to skip certain steps in
* the process to facilitate eq/checks.
*/
impl Entry<EntryInvalid, EntryCommitted> {
/// ⚠️ This function bypasses the schema validation and can panic if uuid is not found.
/// The entry it creates can never be committed safely or replicated.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
pub fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
let uuid = self.get_uuid().expect("Invalid uuid");
Entry {
valid: EntryValid {
@ -1156,8 +1163,11 @@ impl Entry<EntryInvalid, EntryCommitted> {
// Both invalid states can be reached from "entry -> invalidate"
impl Entry<EntryInvalid, EntryNew> {
/// ⚠️ This function bypasses the schema validation and can panic if uuid is not found.
/// The entry it creates can never be committed safely or replicated.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
pub fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
let uuid = self.get_uuid().expect("Invalid uuid");
Entry {
valid: EntryValid {
@ -1169,8 +1179,11 @@ impl Entry<EntryInvalid, EntryNew> {
}
}
/// ⚠️ This function bypasses the db commit, assigns fake db ids, and assigns an invalid uuid.
/// The entry it creates can never be committed safely or replicated.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
Entry {
valid: EntrySealed {
@ -1182,26 +1195,11 @@ impl Entry<EntryInvalid, EntryNew> {
}
}
/*
/// ⚠️ This function bypasses the schema validation and assigns a fake uuid.
/// The entry it creates can never be committed safely or replicated.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_valid_normal(self) -> Entry<EntryNormalised, EntryNew> {
Entry {
valid: EntryNormalised,
state: EntryNew,
attrs: self
.attrs
.into_iter()
.map(|(k, mut v)| {
v.sort_unstable();
(k, v)
})
.collect(),
}
}
*/
#[cfg(test)]
pub unsafe fn into_valid_committed(self) -> Entry<EntryValid, EntryCommitted> {
pub fn into_valid_committed(self) -> Entry<EntryValid, EntryCommitted> {
let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
Entry {
valid: EntryValid {
@ -1215,8 +1213,11 @@ impl Entry<EntryInvalid, EntryNew> {
}
impl Entry<EntryInvalid, EntryCommitted> {
/// ⚠️ This function bypasses the schema validation and assigns a fake uuid.
/// The entry it creates can never be committed safely or replicated.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
Entry {
valid: EntrySealed {
@ -1230,8 +1231,11 @@ impl Entry<EntryInvalid, EntryCommitted> {
}
impl Entry<EntrySealed, EntryNew> {
/// ⚠️ This function bypasses schema validation and assigns an invalid uuid.
/// The entry it creates can never be committed safely or replicated.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
Entry {
valid: self.valid,
state: EntryCommitted { id: 0 },
@ -1280,8 +1284,9 @@ impl Entry<EntrySealed, EntryCommitted> {
self.valid.ecstate.get_tail_cid()
}
/// State transititon to allow self to self for certain test macros.
#[cfg(test)]
pub unsafe fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
// NO-OP to satisfy macros.
self
}
@ -1782,13 +1787,15 @@ impl Entry<EntrySealed, EntryCommitted> {
})
}
/// # Safety
/// This function bypasses the access control validation logic and should NOT
/// ⚠️ This function bypasses the access control validation logic and should NOT
/// be used without special care and attention to ensure that no private data
/// is leaked incorrectly to clients. Generally this is ONLY used inside of
/// the access control processing functions which correctly applies the reduction
/// steps.
pub unsafe fn into_reduced(self) -> Entry<EntryReduced, EntryCommitted> {
///
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub(crate) fn into_reduced(self) -> Entry<EntryReduced, EntryCommitted> {
Entry {
valid: EntryReduced {
uuid: self.valid.uuid,
@ -2169,12 +2176,14 @@ where
&self.valid.ecstate
}
/// ⚠️ - Invalidate an entry by resetting it's change state to time-zero. This entry
/// can never be replicated after this.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_invalid(mut self) -> Entry<EntryInvalid, STATE> {
pub(crate) fn into_invalid(mut self) -> Entry<EntryInvalid, STATE> {
let cid = Cid::new_zero();
self.set_last_changed(cid.clone());
// let eclog = EntryChangelog::new_without_schema(cid.clone(), self.attrs.clone());
let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
Entry {
@ -3201,16 +3210,14 @@ mod tests {
#[test]
fn test_entry_apply_modlist() {
// Test application of changes to an entry.
let mut e: Entry<EntryInvalid, EntryNew> = unsafe { Entry::new().into_invalid_new() };
let mut e: Entry<EntryInvalid, EntryNew> = Entry::new().into_invalid_new();
e.add_ava("userid", Value::from("william"));
let present_single_mods = unsafe {
ModifyList::new_valid_list(vec![Modify::Present(
AttrString::from("attr"),
Value::new_iutf8("value"),
)])
};
let present_single_mods = ModifyList::new_valid_list(vec![Modify::Present(
AttrString::from("attr"),
Value::new_iutf8("value"),
)]);
assert!(e.apply_modlist(&present_single_mods).is_ok());
@ -3219,12 +3226,10 @@ mod tests {
assert!(e.attribute_equality("attr", &PartialValue::new_iutf8("value")));
// Assert present for multivalue
let present_multivalue_mods = unsafe {
ModifyList::new_valid_list(vec![
Modify::Present(AttrString::from("class"), Value::new_iutf8("test")),
Modify::Present(AttrString::from("class"), Value::new_iutf8("multi_test")),
])
};
let present_multivalue_mods = ModifyList::new_valid_list(vec![
Modify::Present(AttrString::from("class"), Value::new_iutf8("test")),
Modify::Present(AttrString::from("class"), Value::new_iutf8("multi_test")),
]);
assert!(e.apply_modlist(&present_multivalue_mods).is_ok());
@ -3233,14 +3238,14 @@ mod tests {
// Assert purge on single/multi/empty value
let purge_single_mods =
unsafe { ModifyList::new_valid_list(vec![Modify::Purged(AttrString::from("attr"))]) };
ModifyList::new_valid_list(vec![Modify::Purged(AttrString::from("attr"))]);
assert!(e.apply_modlist(&purge_single_mods).is_ok());
assert!(!e.attribute_pres("attr"));
let purge_multi_mods =
unsafe { ModifyList::new_valid_list(vec![Modify::Purged(AttrString::from("class"))]) };
ModifyList::new_valid_list(vec![Modify::Purged(AttrString::from("class"))]);
assert!(e.apply_modlist(&purge_multi_mods).is_ok());
@ -3251,12 +3256,10 @@ mod tests {
assert!(e.apply_modlist(&purge_empty_mods).is_ok());
// Assert removed on value that exists and doesn't exist
let remove_mods = unsafe {
ModifyList::new_valid_list(vec![Modify::Removed(
AttrString::from("attr"),
PartialValue::new_iutf8("value"),
)])
};
let remove_mods = ModifyList::new_valid_list(vec![Modify::Removed(
AttrString::from("attr"),
PartialValue::new_iutf8("value"),
)]);
assert!(e.apply_modlist(&present_single_mods).is_ok());
assert!(e.attribute_equality("attr", &PartialValue::new_iutf8("value")));
@ -3277,12 +3280,12 @@ mod tests {
let mut e1_mod = e1.clone();
e1_mod.add_ava("extra", Value::from("test"));
let e1 = unsafe { e1.into_sealed_committed() };
let e1_mod = unsafe { e1_mod.into_sealed_committed() };
let e1 = e1.into_sealed_committed();
let e1_mod = e1_mod.into_sealed_committed();
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
e2.add_ava("userid", Value::from("claire"));
let e2 = unsafe { e2.into_sealed_committed() };
let e2 = e2.into_sealed_committed();
let mut idxmeta = HashMap::with_capacity(8);
idxmeta.insert(
@ -3409,18 +3412,18 @@ mod tests {
fn test_entry_mask_recycled_ts() {
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
e1.add_ava("class", Value::new_class("person"));
let e1 = unsafe { e1.into_sealed_committed() };
let e1 = e1.into_sealed_committed();
assert!(e1.mask_recycled_ts().is_some());
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
e2.add_ava("class", Value::new_class("person"));
e2.add_ava("class", Value::new_class("recycled"));
let e2 = unsafe { e2.into_sealed_committed() };
let e2 = e2.into_sealed_committed();
assert!(e2.mask_recycled_ts().is_none());
let mut e3: Entry<EntryInit, EntryNew> = Entry::new();
e3.add_ava("class", Value::new_class("tombstone"));
let e3 = unsafe { e3.into_sealed_committed() };
let e3 = e3.into_sealed_committed();
assert!(e3.mask_recycled_ts().is_none());
}
@ -3434,7 +3437,7 @@ mod tests {
{
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
e.add_ava("class", Value::new_class("person"));
let e = unsafe { e.into_sealed_committed() };
let e = e.into_sealed_committed();
assert!(Entry::idx_name2uuid_diff(None, Some(&e)) == (Some(Set::new()), None));
}
@ -3449,7 +3452,7 @@ mod tests {
"uuid",
Value::Uuid(uuid!("9fec0398-c46c-4df4-9df5-b0016f7d563f")),
);
let e = unsafe { e.into_sealed_committed() };
let e = e.into_sealed_committed();
// Note the uuid isn't present!
assert!(
@ -3489,13 +3492,13 @@ mod tests {
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
e1.add_ava("class", Value::new_class("person"));
e1.add_ava("spn", Value::new_spn_str("testperson", "example.com"));
let e1 = unsafe { e1.into_sealed_committed() };
let e1 = e1.into_sealed_committed();
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
e2.add_ava("class", Value::new_class("person"));
e2.add_ava("name", Value::new_iname("testperson"));
e2.add_ava("spn", Value::new_spn_str("testperson", "example.com"));
let e2 = unsafe { e2.into_sealed_committed() };
let e2 = e2.into_sealed_committed();
// One attr added
assert!(
@ -3515,12 +3518,12 @@ mod tests {
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
e1.add_ava("class", Value::new_class("person"));
e1.add_ava("spn", Value::new_spn_str("testperson", "example.com"));
let e1 = unsafe { e1.into_sealed_committed() };
let e1 = e1.into_sealed_committed();
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
e2.add_ava("class", Value::new_class("person"));
e2.add_ava("spn", Value::new_spn_str("renameperson", "example.com"));
let e2 = unsafe { e2.into_sealed_committed() };
let e2 = e2.into_sealed_committed();
assert!(
Entry::idx_name2uuid_diff(Some(&e1), Some(&e2))
@ -3538,11 +3541,11 @@ mod tests {
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
e1.add_ava("spn", Value::new_spn_str("testperson", "example.com"));
let e1 = unsafe { e1.into_sealed_committed() };
let e1 = e1.into_sealed_committed();
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
e2.add_ava("spn", Value::new_spn_str("renameperson", "example.com"));
let e2 = unsafe { e2.into_sealed_committed() };
let e2 = e2.into_sealed_committed();
assert!(
Entry::idx_uuid2spn_diff(None, Some(&e1))
@ -3562,11 +3565,11 @@ mod tests {
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
e1.add_ava("spn", Value::new_spn_str("testperson", "example.com"));
let e1 = unsafe { e1.into_sealed_committed() };
let e1 = e1.into_sealed_committed();
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
e2.add_ava("spn", Value::new_spn_str("renameperson", "example.com"));
let e2 = unsafe { e2.into_sealed_committed() };
let e2 = e2.into_sealed_committed();
assert!(
Entry::idx_uuid2rdn_diff(None, Some(&e1))

View file

@ -200,9 +200,11 @@ impl SearchEvent {
})
}
// Just impersonate the account with no filter changes.
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_impersonate_entry_ser(e: &str, filter: Filter<FilterInvalid>) -> Self {
pub fn new_impersonate_entry_ser(e: &str, filter: Filter<FilterInvalid>) -> Self {
// Just impersonate the account with no filter changes.
let ei: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(e);
SearchEvent {
ident: Identity::from_impersonate_entry_readonly(Arc::new(ei.into_sealed_committed())),
@ -212,8 +214,10 @@ impl SearchEvent {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_impersonate_entry(
pub fn new_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
) -> Self {
@ -225,8 +229,10 @@ impl SearchEvent {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_impersonate_identity(ident: Identity, filter: Filter<FilterInvalid>) -> Self {
pub fn new_impersonate_identity(ident: Identity, filter: Filter<FilterInvalid>) -> Self {
SearchEvent {
ident,
filter: filter.clone().into_valid(),
@ -248,12 +254,14 @@ impl SearchEvent {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
/* Impersonate a request for recycled objects */
pub unsafe fn new_rec_impersonate_entry(
pub fn new_rec_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
) -> Self {
/* Impersonate a request for recycled objects */
let filter_orig = filter.into_valid();
let filter = filter_orig.clone().into_recycled();
SearchEvent {
@ -264,12 +272,14 @@ impl SearchEvent {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
/* Impersonate an external request AKA filter ts + recycle */
pub unsafe fn new_ext_impersonate_entry(
pub fn new_ext_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
) -> Self {
/* Impersonate an external request AKA filter ts + recycle */
SearchEvent {
ident: Identity::from_impersonate_entry_readonly(e),
filter: filter.clone().into_valid().into_ignore_hidden(),
@ -298,8 +308,10 @@ impl SearchEvent {
})
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
pub fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
SearchEvent {
ident: Identity::from_internal(),
filter: filter.clone().into_valid(),
@ -355,11 +367,10 @@ impl CreateEvent {
}
}
/// ⚠️ - Use an unsafe entry impersonation method.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_impersonate_entry_ser(
e: &str,
entries: Vec<Entry<EntryInit, EntryNew>>,
) -> Self {
pub fn new_impersonate_entry_ser(e: &str, entries: Vec<Entry<EntryInit, EntryNew>>) -> Self {
let ei: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(e);
CreateEvent {
ident: Identity::from_impersonate_entry_readwrite(Arc::new(ei.into_sealed_committed())),
@ -401,9 +412,10 @@ impl ExistsEvent {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
#[allow(dead_code)]
pub unsafe fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
pub fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
ExistsEvent {
ident: Identity::from_internal(),
filter: filter.clone().into_valid(),
@ -459,8 +471,10 @@ impl DeleteEvent {
})
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_impersonate_entry(
pub fn new_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
) -> Self {
@ -471,19 +485,21 @@ impl DeleteEvent {
}
}
/// ⚠️ - Bypass the schema state machine, allowing an invalid filter to be used in an impersonate request.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub fn new_impersonate_identity(ident: Identity, filter: Filter<FilterInvalid>) -> Self {
unsafe {
DeleteEvent {
ident,
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
}
DeleteEvent {
ident,
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_impersonate_entry_ser(e: &str, filter: Filter<FilterInvalid>) -> Self {
pub fn new_impersonate_entry_ser(e: &str, filter: Filter<FilterInvalid>) -> Self {
let ei: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(e);
DeleteEvent {
ident: Identity::from_impersonate_entry_readwrite(Arc::new(ei.into_sealed_committed())),
@ -492,8 +508,10 @@ impl DeleteEvent {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
pub fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
DeleteEvent {
ident: Identity::from_internal(),
filter: filter.clone().into_valid(),
@ -629,8 +647,10 @@ impl ModifyEvent {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_internal_invalid(
pub fn new_internal_invalid(
filter: Filter<FilterInvalid>,
modlist: ModifyList<ModifyInvalid>,
) -> Self {
@ -642,8 +662,10 @@ impl ModifyEvent {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_impersonate_entry_ser(
pub fn new_impersonate_entry_ser(
e: &str,
filter: Filter<FilterInvalid>,
modlist: ModifyList<ModifyInvalid>,
@ -657,8 +679,10 @@ impl ModifyEvent {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_impersonate_identity(
pub fn new_impersonate_identity(
ident: Identity,
filter: Filter<FilterInvalid>,
modlist: ModifyList<ModifyInvalid>,
@ -671,8 +695,10 @@ impl ModifyEvent {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_impersonate_entry(
pub fn new_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
modlist: ModifyList<ModifyInvalid>,
@ -808,8 +834,10 @@ impl ReviveRecycledEvent {
Ok(ReviveRecycledEvent { ident, filter })
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_impersonate_entry(
pub fn new_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
) -> Self {

View file

@ -412,8 +412,10 @@ impl Filter<FilterInvalid> {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_valid_resolved(self) -> Filter<FilterValidResolved> {
pub fn into_valid_resolved(self) -> Filter<FilterValidResolved> {
// There is a good reason this function only exists in tests ...
//
// YOLO.
@ -449,8 +451,10 @@ impl Filter<FilterInvalid> {
}
}
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn into_valid(self) -> Filter<FilterValid> {
pub fn into_valid(self) -> Filter<FilterValid> {
// There is a good reason this function only exists in tests ...
//
// YOLO.
@ -464,8 +468,10 @@ impl Filter<FilterInvalid> {
}
}
/// ⚠️ - Blindly accept a filter from a string, panicking if it fails to parse.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn from_str(fc: &str) -> Self {
pub fn from_str(fc: &str) -> Self {
let f: FC = serde_json::from_str(fc).expect("Failure parsing filter!");
Filter {
state: FilterInvalid {
@ -1007,8 +1013,10 @@ impl Ord for FilterResolved {
}
impl FilterResolved {
/// ⚠️ - Process a filter without verifying with schema.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
unsafe fn from_invalid(fc: FilterComp, idxmeta: &HashSet<(&AttrString, &IndexType)>) -> Self {
fn from_invalid(fc: FilterComp, idxmeta: &HashSet<(&AttrString, &IndexType)>) -> Self {
match fc {
FilterComp::Eq(a, v) => {
let idx = idxmeta.contains(&(&a, &IndexType::Equality));
@ -1378,9 +1386,9 @@ mod tests {
let f_init: Filter<FilterInvalid> = Filter::new($init);
let f_expect: Filter<FilterInvalid> = Filter::new($expect);
// Create a resolved filter, via the most unsafe means possible!
let f_init_r = unsafe { f_init.into_valid_resolved() };
let f_init_r = f_init.into_valid_resolved();
let f_init_o = f_init_r.optimise();
let f_init_e = unsafe { f_expect.into_valid_resolved() };
let f_init_e = f_expect.into_valid_resolved();
debug!("--");
debug!("init --> {:?}", f_init_r);
debug!("opt --> {:?}", f_init_o);
@ -1513,25 +1521,25 @@ mod tests {
// Test that we uphold the rules of partialOrd
// Basic equality
// Test the two major paths here (str vs list)
let f_t1a = unsafe { filter_resolved!(f_pres("userid")) };
let f_t1b = unsafe { filter_resolved!(f_pres("userid")) };
let f_t1a = filter_resolved!(f_pres("userid"));
let f_t1b = filter_resolved!(f_pres("userid"));
assert_eq!(f_t1a.partial_cmp(&f_t1b), Some(Ordering::Equal));
assert_eq!(f_t1b.partial_cmp(&f_t1a), Some(Ordering::Equal));
let f_t2a = unsafe { filter_resolved!(f_and!([])) };
let f_t2b = unsafe { filter_resolved!(f_and!([])) };
let f_t2a = filter_resolved!(f_and!([]));
let f_t2b = filter_resolved!(f_and!([]));
assert_eq!(f_t2a.partial_cmp(&f_t2b), Some(Ordering::Equal));
assert_eq!(f_t2b.partial_cmp(&f_t2a), Some(Ordering::Equal));
// antisymmetry: if a < b then !(a > b), as well as a > b implying !(a < b); and
// These are unindexed so we have to check them this way.
let f_t3b = unsafe { filter_resolved!(f_eq("userid", PartialValue::new_iutf8(""))) };
let f_t3b = filter_resolved!(f_eq("userid", PartialValue::new_iutf8("")));
assert_eq!(f_t1a.partial_cmp(&f_t3b), Some(Ordering::Greater));
assert_eq!(f_t3b.partial_cmp(&f_t1a), Some(Ordering::Less));
// transitivity: a < b and b < c implies a < c. The same must hold for both == and >.
let f_t4b = unsafe { filter_resolved!(f_sub("userid", PartialValue::new_iutf8(""))) };
let f_t4b = filter_resolved!(f_sub("userid", PartialValue::new_iutf8("")));
assert_eq!(f_t1a.partial_cmp(&f_t4b), Some(Ordering::Less));
assert_eq!(f_t3b.partial_cmp(&f_t4b), Some(Ordering::Less));
@ -1543,16 +1551,16 @@ mod tests {
fn test_filter_clone() {
// Test that cloning filters yields the same result regardless of
// complexity.
let f_t1a = unsafe { filter_resolved!(f_pres("userid")) };
let f_t1a = filter_resolved!(f_pres("userid"));
let f_t1b = f_t1a.clone();
let f_t1c = unsafe { filter_resolved!(f_pres("zzzz")) };
let f_t1c = filter_resolved!(f_pres("zzzz"));
assert!(f_t1a == f_t1b);
assert!(f_t1a != f_t1c);
let f_t2a = unsafe { filter_resolved!(f_and!([f_pres("userid")])) };
let f_t2a = filter_resolved!(f_and!([f_pres("userid")]));
let f_t2b = f_t2a.clone();
let f_t2c = unsafe { filter_resolved!(f_and!([f_pres("zzzz")])) };
let f_t2c = filter_resolved!(f_and!([f_pres("zzzz")]));
assert!(f_t2a == f_t2b);
assert!(f_t2a != f_t2c);
@ -1560,205 +1568,168 @@ mod tests {
#[test]
fn test_lessthan_entry_filter() {
let e = unsafe {
entry_init!(
("userid", Value::new_iutf8("william")),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new()
};
let e = entry_init!(
("userid", Value::new_iutf8("william")),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new();
let f_t1a = unsafe { filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(500))) };
let f_t1a = filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(500)));
assert!(!e.entry_match_no_index(&f_t1a));
let f_t1b = unsafe { filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(1000))) };
let f_t1b = filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(1000)));
assert!(!e.entry_match_no_index(&f_t1b));
let f_t1c = unsafe { filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(1001))) };
let f_t1c = filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(1001)));
assert!(e.entry_match_no_index(&f_t1c));
}
#[test]
fn test_or_entry_filter() {
let e = unsafe {
entry_init!(
("userid", Value::new_iutf8("william")),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new()
};
let e = entry_init!(
("userid", Value::new_iutf8("william")),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new();
let f_t1a = unsafe {
filter_resolved!(f_or!([
f_eq("userid", PartialValue::new_iutf8("william")),
f_eq("gidnumber", PartialValue::Uint32(1000)),
]))
};
let f_t1a = filter_resolved!(f_or!([
f_eq("userid", PartialValue::new_iutf8("william")),
f_eq("gidnumber", PartialValue::Uint32(1000)),
]));
assert!(e.entry_match_no_index(&f_t1a));
let f_t2a = unsafe {
filter_resolved!(f_or!([
f_eq("userid", PartialValue::new_iutf8("william")),
f_eq("gidnumber", PartialValue::Uint32(1000)),
]))
};
let f_t2a = filter_resolved!(f_or!([
f_eq("userid", PartialValue::new_iutf8("william")),
f_eq("gidnumber", PartialValue::Uint32(1000)),
]));
assert!(e.entry_match_no_index(&f_t2a));
let f_t3a = unsafe {
filter_resolved!(f_or!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("gidnumber", PartialValue::Uint32(1000)),
]))
};
let f_t3a = filter_resolved!(f_or!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("gidnumber", PartialValue::Uint32(1000)),
]));
assert!(e.entry_match_no_index(&f_t3a));
let f_t4a = unsafe {
filter_resolved!(f_or!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("gidnumber", PartialValue::Uint32(1001)),
]))
};
let f_t4a = filter_resolved!(f_or!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("gidnumber", PartialValue::Uint32(1001)),
]));
assert!(!e.entry_match_no_index(&f_t4a));
}
#[test]
fn test_and_entry_filter() {
let e = unsafe {
entry_init!(
("userid", Value::new_iutf8("william")),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new()
};
let e = entry_init!(
("userid", Value::new_iutf8("william")),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new();
let f_t1a = unsafe {
filter_resolved!(f_and!([
f_eq("userid", PartialValue::new_iutf8("william")),
f_eq("gidnumber", PartialValue::Uint32(1000)),
]))
};
let f_t1a = filter_resolved!(f_and!([
f_eq("userid", PartialValue::new_iutf8("william")),
f_eq("gidnumber", PartialValue::Uint32(1000)),
]));
assert!(e.entry_match_no_index(&f_t1a));
let f_t2a = unsafe {
filter_resolved!(f_and!([
f_eq("userid", PartialValue::new_iutf8("william")),
f_eq("gidnumber", PartialValue::Uint32(1001)),
]))
};
let f_t2a = filter_resolved!(f_and!([
f_eq("userid", PartialValue::new_iutf8("william")),
f_eq("gidnumber", PartialValue::Uint32(1001)),
]));
assert!(!e.entry_match_no_index(&f_t2a));
let f_t3a = unsafe {
filter_resolved!(f_and!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("gidnumber", PartialValue::Uint32(1000)),
]))
};
let f_t3a = filter_resolved!(f_and!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("gidnumber", PartialValue::Uint32(1000)),
]));
assert!(!e.entry_match_no_index(&f_t3a));
let f_t4a = unsafe {
filter_resolved!(f_and!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("gidnumber", PartialValue::Uint32(1001)),
]))
};
let f_t4a = filter_resolved!(f_and!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("gidnumber", PartialValue::Uint32(1001)),
]));
assert!(!e.entry_match_no_index(&f_t4a));
}
#[test]
fn test_not_entry_filter() {
let e1 = unsafe {
entry_init!(
("userid", Value::new_iutf8("william")),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new()
};
let e1 = entry_init!(
("userid", Value::new_iutf8("william")),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new();
let f_t1a =
unsafe { filter_resolved!(f_andnot(f_eq("userid", PartialValue::new_iutf8("alice")))) };
let f_t1a = filter_resolved!(f_andnot(f_eq("userid", PartialValue::new_iutf8("alice"))));
assert!(e1.entry_match_no_index(&f_t1a));
let f_t2a = unsafe {
filter_resolved!(f_andnot(f_eq("userid", PartialValue::new_iutf8("william"))))
};
let f_t2a = filter_resolved!(f_andnot(f_eq("userid", PartialValue::new_iutf8("william"))));
assert!(!e1.entry_match_no_index(&f_t2a));
}
#[test]
fn test_nested_entry_filter() {
let e1 = unsafe {
entry_init!(
("class", CLASS_PERSON.clone()),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new()
};
let e1 = entry_init!(
("class", CLASS_PERSON.clone()),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new();
let e2 = unsafe {
entry_init!(
("class", CLASS_PERSON.clone()),
(
"uuid",
Value::Uuid(uuid::uuid!("4b6228ab-1dbe-42a4-a9f5-f6368222438e"))
),
("gidnumber", Value::Uint32(1001))
)
.into_sealed_new()
};
let e2 = entry_init!(
("class", CLASS_PERSON.clone()),
(
"uuid",
Value::Uuid(uuid::uuid!("4b6228ab-1dbe-42a4-a9f5-f6368222438e"))
),
("gidnumber", Value::Uint32(1001))
)
.into_sealed_new();
let e3 = unsafe {
entry_init!(
("class", CLASS_PERSON.clone()),
(
"uuid",
Value::Uuid(uuid::uuid!("7b23c99d-c06b-4a9a-a958-3afa56383e1d"))
),
("gidnumber", Value::Uint32(1002))
)
.into_sealed_new()
};
let e3 = entry_init!(
("class", CLASS_PERSON.clone()),
(
"uuid",
Value::Uuid(uuid::uuid!("7b23c99d-c06b-4a9a-a958-3afa56383e1d"))
),
("gidnumber", Value::Uint32(1002))
)
.into_sealed_new();
let e4 = unsafe {
entry_init!(
("class", CLASS_GROUP.clone()),
(
"uuid",
Value::Uuid(uuid::uuid!("21d816b5-1f6a-4696-b7c1-6ed06d22ed81"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new()
};
let e4 = entry_init!(
("class", CLASS_GROUP.clone()),
(
"uuid",
Value::Uuid(uuid::uuid!("21d816b5-1f6a-4696-b7c1-6ed06d22ed81"))
),
("gidnumber", Value::Uint32(1000))
)
.into_sealed_new();
let f_t1a = unsafe {
filter_resolved!(f_and!([
f_eq("class", PVCLASS_PERSON.clone()),
f_or!([
f_eq("gidnumber", PartialValue::Uint32(1001)),
f_eq("gidnumber", PartialValue::Uint32(1000))
])
]))
};
let f_t1a = filter_resolved!(f_and!([
f_eq("class", PVCLASS_PERSON.clone()),
f_or!([
f_eq("gidnumber", PartialValue::Uint32(1001)),
f_eq("gidnumber", PartialValue::Uint32(1000))
])
]));
assert!(e1.entry_match_no_index(&f_t1a));
assert!(e2.entry_match_no_index(&f_t1a));
@ -1773,22 +1744,18 @@ mod tests {
f_expect.insert("class");
// Given filters, get their expected attribute sets - this is used by access control profiles
// to determine what attrs we are requesting regardless of the partialvalue.
let f_t1a = unsafe {
filter_valid!(f_and!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("class", PartialValue::new_iutf8("1001")),
]))
};
let f_t1a = filter_valid!(f_and!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("class", PartialValue::new_iutf8("1001")),
]));
assert!(f_t1a.get_attr_set() == f_expect);
let f_t2a = unsafe {
filter_valid!(f_and!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("class", PartialValue::new_iutf8("1001")),
f_eq("userid", PartialValue::new_iutf8("claire")),
]))
};
let f_t2a = filter_valid!(f_and!([
f_eq("userid", PartialValue::new_iutf8("alice")),
f_eq("class", PartialValue::new_iutf8("1001")),
f_eq("userid", PartialValue::new_iutf8("claire")),
]));
assert!(f_t2a.get_attr_set() == f_expect);
}
@ -1843,12 +1810,10 @@ mod tests {
let cr = server_txn.create(&ce);
assert!(cr.is_ok());
let de_sin = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
"name",
PartialValue::new_iname("testperson3")
)])))
};
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
"name",
PartialValue::new_iname("testperson3")
)])));
assert!(server_txn.delete(&de_sin).is_ok());
// Commit

View file

@ -821,15 +821,13 @@ mod tests {
assert!(uat.ui_hints.contains(&UiHint::CredentialUpdate));
// Modify the user to be a posix account, ensure they get the hint.
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testaccount"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
)
};
let me_posix = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testaccount"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
);
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
// Check the ui hints are as expected.

View file

@ -5,12 +5,9 @@ use kanidm_proto::internal::AppLink;
impl<'a> IdmServerProxyReadTransaction<'a> {
pub fn list_applinks(&mut self, ident: &Identity) -> Result<Vec<AppLink>, OperationError> {
// From the member-of of the ident.
let ident_mo = match ident.get_memberof() {
Some(mo) => mo,
None => {
debug!("Ident has no memberof, no applinks are present");
return Ok(Vec::with_capacity(0));
}
let Some(ident_mo) = ident.get_memberof() else {
debug!("Ident has no memberof, no applinks are present");
return Ok(Vec::with_capacity(0));
};
// Formerly we did an internal search here, but we no longer need to since we have
@ -143,12 +140,10 @@ mod tests {
// Add them to the group.
let mut idms_prox_write = idms.proxy_write(ct).await;
let me_inv_m = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("uuid", PartialValue::Refer(grp_uuid))),
ModifyList::new_append("member", Value::Refer(usr_uuid)),
)
};
let me_inv_m = ModifyEvent::new_internal_invalid(
filter!(f_eq("uuid", PartialValue::Refer(grp_uuid))),
ModifyList::new_append("member", Value::Refer(usr_uuid)),
);
assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok());
assert!(idms_prox_write.commit().is_ok());

View file

@ -3,6 +3,8 @@ use crate::prelude::*;
use kanidm_proto::v1::OperationError;
use kanidm_proto::v1::{AuthCredential, AuthIssueSession, AuthMech, AuthRequest, AuthStep};
#[cfg(test)]
use std::sync::Arc;
#[cfg(test)]
use webauthn_rs::prelude::PublicKeyCredential;
@ -109,8 +111,8 @@ impl RadiusAuthTokenEvent {
}
#[cfg(test)]
pub fn new_internal(target: Uuid) -> Self {
let ident = Identity::from_internal();
pub fn new_impersonate(e: Arc<Entry<EntrySealed, EntryCommitted>>, target: Uuid) -> Self {
let ident = Identity::from_impersonate_entry_readonly(e);
RadiusAuthTokenEvent { ident, target }
}
@ -155,8 +157,8 @@ impl UnixGroupTokenEvent {
}
#[cfg(test)]
pub fn new_internal(target: Uuid) -> Self {
let ident = Identity::from_internal();
pub fn new_impersonate(e: Arc<Entry<EntrySealed, EntryCommitted>>, target: Uuid) -> Self {
let ident = Identity::from_impersonate_entry_readonly(e);
UnixGroupTokenEvent { ident, target }
}

View file

@ -624,15 +624,13 @@ mod tests {
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
// make the admin a valid posix account
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
)
};
let me_posix = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
);
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
let pce = UnixPasswordChangeEvent::new_internal(UUID_ADMIN, TEST_PASSWORD);
@ -1010,18 +1008,16 @@ mod tests {
assert!(server_txn.qs_write.create(&ce).is_ok());
// idm_people_read_priv
let me = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq(
"name",
PartialValue::new_iname("idm_people_read_priv")
)),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("member"),
Value::Refer(sa_uuid),
)]),
)
};
let me = ModifyEvent::new_internal_invalid(
filter!(f_eq(
"name",
PartialValue::new_iname("idm_people_read_priv")
)),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("member"),
Value::Refer(sa_uuid),
)]),
);
assert!(server_txn.qs_write.modify(&me).is_ok());
// Issue a token
@ -1206,15 +1202,13 @@ mod tests {
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
// make the admin a valid posix account
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("uuid", PartialValue::Uuid(UUID_DOMAIN_INFO))),
ModifyList::new_purge_and_set(
"domain_ldap_basedn",
Value::new_iutf8("o=kanidmproject"),
),
)
};
let me_posix = ModifyEvent::new_internal_invalid(
filter!(f_eq("uuid", PartialValue::Uuid(UUID_DOMAIN_INFO))),
ModifyList::new_purge_and_set(
"domain_ldap_basedn",
Value::new_iutf8("o=kanidmproject"),
),
);
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
assert!(idms_prox_write.commit().is_ok());

View file

@ -895,15 +895,12 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
.check_oauth2_account_uuid_valid(uuid, session_id, parent_session_id, iat, ct)
.map_err(|_| admin_error!("Account is not valid"));
let entry = match valid {
Ok(Some(entry)) => entry,
_ => {
security_info!(
?uuid,
"access token has no account not valid, returning inactive"
);
return Err(Oauth2Error::InvalidToken);
}
let Ok(Some(entry)) = valid else {
security_info!(
?uuid,
"access token has no account not valid, returning inactive"
);
return Err(Oauth2Error::InvalidToken);
};
// Check the not issued before of the session relative to this refresh iat
@ -1612,15 +1609,12 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
.check_oauth2_account_uuid_valid(uuid, session_id, parent_session_id, iat, ct)
.map_err(|_| admin_error!("Account is not valid"));
let entry = match valid {
Ok(Some(entry)) => entry,
_ => {
security_info!(
?uuid,
"access token has no account not valid, returning inactive"
);
return Ok(AccessTokenIntrospectResponse::inactive());
}
let Ok(Some(entry)) = valid else {
security_info!(
?uuid,
"access token has no account not valid, returning inactive"
);
return Ok(AccessTokenIntrospectResponse::inactive());
};
let account = match Account::try_from_entry_no_groups(&entry) {
@ -1718,15 +1712,12 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
.check_oauth2_account_uuid_valid(uuid, session_id, parent_session_id, iat, ct)
.map_err(|_| admin_error!("Account is not valid"));
let entry = match valid {
Ok(Some(entry)) => entry,
_ => {
security_info!(
?uuid,
"access token has account not valid, returning inactive"
);
return Err(Oauth2Error::InvalidToken);
}
let Ok(Some(entry)) = valid else {
security_info!(
?uuid,
"access token has account not valid, returning inactive"
);
return Err(Oauth2Error::InvalidToken);
};
let account = match Account::try_from_entry_ro(&entry, &mut self.qs_read) {
@ -2900,15 +2891,13 @@ mod tests {
let mut idms_prox_write = idms.proxy_write(ct).await;
// Expire the account, should cause introspect to return inactive.
let v_expire = Value::new_datetime_epoch(Duration::from_secs(TEST_CURRENT_TIME - 1));
let me_inv_m = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("account_expire"),
v_expire,
)]),
)
};
let me_inv_m = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("account_expire"),
v_expire,
)]),
);
// go!
assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok());
assert!(idms_prox_write.commit().is_ok());
@ -3144,12 +3133,10 @@ mod tests {
// Delete the resource server.
let de = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_eq(
"oauth2_rs_name",
PartialValue::new_iname("test_resource_server")
)))
};
let de = DeleteEvent::new_internal_invalid(filter!(f_eq(
"oauth2_rs_name",
PartialValue::new_iname("test_resource_server")
)));
assert!(idms_prox_write.qs_write.delete(&de).is_ok());
@ -3962,22 +3949,20 @@ mod tests {
// Great! Now change the scopes on the oauth2 instance, this revokes the permit.
let mut idms_prox_write = idms.proxy_write(ct).await;
let me_extend_scopes = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq(
"oauth2_rs_name",
PartialValue::new_iname("test_resource_server")
)),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("oauth2_rs_scope_map"),
Value::new_oauthscopemap(
UUID_IDM_ALL_ACCOUNTS,
btreeset!["email".to_string(), "openid".to_string()],
)
.expect("invalid oauthscope"),
)]),
)
};
let me_extend_scopes = ModifyEvent::new_internal_invalid(
filter!(f_eq(
"oauth2_rs_name",
PartialValue::new_iname("test_resource_server")
)),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("oauth2_rs_scope_map"),
Value::new_oauthscopemap(
UUID_IDM_ALL_ACCOUNTS,
btreeset!["email".to_string(), "openid".to_string()],
)
.expect("invalid oauthscope"),
)]),
);
assert!(idms_prox_write.qs_write.modify(&me_extend_scopes).is_ok());
assert!(idms_prox_write.commit().is_ok());
@ -4027,22 +4012,17 @@ mod tests {
// Now change the supplemental scopes on the oauth2 instance, this revokes the permit.
let mut idms_prox_write = idms.proxy_write(ct).await;
let me_extend_scopes = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq(
"oauth2_rs_name",
PartialValue::new_iname("test_resource_server")
)),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("oauth2_rs_sup_scope_map"),
Value::new_oauthscopemap(
UUID_IDM_ALL_ACCOUNTS,
btreeset!["newscope".to_string()],
)
let me_extend_scopes = ModifyEvent::new_internal_invalid(
filter!(f_eq(
"oauth2_rs_name",
PartialValue::new_iname("test_resource_server")
)),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("oauth2_rs_sup_scope_map"),
Value::new_oauthscopemap(UUID_IDM_ALL_ACCOUNTS, btreeset!["newscope".to_string()])
.expect("invalid oauthscope"),
)]),
)
};
)]),
);
assert!(idms_prox_write.qs_write.modify(&me_extend_scopes).is_ok());
assert!(idms_prox_write.commit().is_ok());
@ -4143,12 +4123,10 @@ mod tests {
);
// Now trigger the delete of the RS
let de = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_eq(
"oauth2_rs_name",
PartialValue::new_iname("test_resource_server")
)))
};
let de = DeleteEvent::new_internal_invalid(filter!(f_eq(
"oauth2_rs_name",
PartialValue::new_iname("test_resource_server")
)));
assert!(idms_prox_write.qs_write.delete(&de).is_ok());
// Assert the consent maps are gone.

View file

@ -27,12 +27,9 @@ impl<'a> IdmServerAuthTransaction<'a> {
) -> Result<AuthResult, OperationError> {
// re-auth only works on users, so lets get the user account.
// hint - it's in the ident!
let entry = match ident.get_user_entry() {
Some(entry) => entry,
None => {
error!("Ident is not a user and has no entry associated. Unable to proceed.");
return Err(OperationError::InvalidState);
}
let Some(entry) = ident.get_user_entry() else {
error!("Ident is not a user and has no entry associated. Unable to proceed.");
return Err(OperationError::InvalidState);
};
// Setup the account record.

View file

@ -1604,12 +1604,10 @@ mod tests {
// -- Revoke the session
let mut idms_prox_write = idms.proxy_write(ct).await;
let me_inv_m = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("test_scim_sync"))),
ModifyList::new_list(vec![Modify::Purged(AttrString::from("sync_token_session"))]),
)
};
let me_inv_m = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("test_scim_sync"))),
ModifyList::new_list(vec![Modify::Purged(AttrString::from("sync_token_session"))]),
);
assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok());
assert!(idms_prox_write.commit().is_ok());
@ -1628,14 +1626,12 @@ mod tests {
.scim_sync_generate_token(&gte, ct)
.expect("failed to generate new scim sync token");
let me_inv_m = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("test_scim_sync"))),
ModifyList::new_list(vec![Modify::Purged(AttrString::from(
"jws_es256_private_key",
))]),
)
};
let me_inv_m = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("test_scim_sync"))),
ModifyList::new_list(vec![Modify::Purged(AttrString::from(
"jws_es256_private_key",
))]),
);
assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok());
assert!(idms_prox_write.commit().is_ok());

View file

@ -1629,15 +1629,14 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
e
})?;
let mp = unsafe {
self.qs_write
.modify_pre_apply(&me)
.and_then(|opt_mp| opt_mp.ok_or(OperationError::NoMatchingEntries))
.map_err(|e| {
request_error!(error = ?e);
e
})?
};
let mp = self
.qs_write
.modify_pre_apply(&me)
.and_then(|opt_mp| opt_mp.ok_or(OperationError::NoMatchingEntries))
.map_err(|e| {
request_error!(error = ?e);
e
})?;
// If we got here, then pre-apply succeeded, and that means access control
// passed. Now we can do the extra checks.
@ -1708,15 +1707,14 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
e
})?;
let mp = unsafe {
self.qs_write
.modify_pre_apply(&me)
.and_then(|opt_mp| opt_mp.ok_or(OperationError::NoMatchingEntries))
.map_err(|e| {
request_error!(error = ?e);
e
})?
};
let mp = self
.qs_write
.modify_pre_apply(&me)
.and_then(|opt_mp| opt_mp.ok_or(OperationError::NoMatchingEntries))
.map_err(|e| {
request_error!(error = ?e);
e
})?;
// If we got here, then pre-apply succeeded, and that means access control
// passed. Now we can do the extra checks.
@ -2249,15 +2247,13 @@ mod tests {
let mut idms_write = idms.proxy_write(duration_from_epoch_now()).await;
// now modify and provide a primary credential.
let me_inv_m = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("primary_credential"),
v_cred,
)]),
)
};
let me_inv_m = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("primary_credential"),
v_cred,
)]),
);
// go!
assert!(idms_write.qs_write.modify(&me_inv_m).is_ok());
@ -2542,7 +2538,12 @@ mod tests {
idms_prox_write.commit().expect("failed to commit");
let mut idms_prox_read = idms.proxy_read().await;
let rate = RadiusAuthTokenEvent::new_internal(UUID_ADMIN);
let admin_entry = idms_prox_read
.qs_read
.internal_search_uuid(UUID_ADMIN)
.expect("Can't access admin entry.");
let rate = RadiusAuthTokenEvent::new_impersonate(admin_entry, UUID_ADMIN);
let tok_r = idms_prox_read
.get_radiusauthtoken(&rate, duration_from_epoch_now())
.expect("Failed to generate radius auth token");
@ -2603,15 +2604,13 @@ mod tests {
async fn test_idm_unixusertoken(idms: &IdmServer, _idms_delayed: &IdmServerDelayed) {
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
// Modify admin to have posixaccount
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
)
};
let me_posix = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
);
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
// Add a posix group that has the admin as a member.
let e: Entry<EntryInit, EntryNew> = entry_init!(
@ -2638,7 +2637,16 @@ mod tests {
let mut idms_prox_read = idms.proxy_read().await;
let ugte = UnixGroupTokenEvent::new_internal(uuid!("01609135-a1c4-43d5-966b-a28227644445"));
// Get the account that will be doing the actual reads.
let admin_entry = idms_prox_read
.qs_read
.internal_search_uuid(UUID_ADMIN)
.expect("Can't access admin entry.");
let ugte = UnixGroupTokenEvent::new_impersonate(
admin_entry.clone(),
uuid!("01609135-a1c4-43d5-966b-a28227644445"),
);
let tok_g = idms_prox_read
.get_unixgrouptoken(&ugte)
.expect("Failed to generate unix group token");
@ -2659,7 +2667,10 @@ mod tests {
assert!(tok_r.valid);
// Show we can get the admin as a unix group token too
let ugte = UnixGroupTokenEvent::new_internal(uuid!("00000000-0000-0000-0000-000000000000"));
let ugte = UnixGroupTokenEvent::new_impersonate(
admin_entry,
uuid!("00000000-0000-0000-0000-000000000000"),
);
let tok_g = idms_prox_read
.get_unixgrouptoken(&ugte)
.expect("Failed to generate unix group token");
@ -2675,15 +2686,13 @@ mod tests {
) {
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
// make the admin a valid posix account
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
)
};
let me_posix = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
);
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
let pce = UnixPasswordChangeEvent::new_internal(UUID_ADMIN, TEST_PASSWORD);
@ -2715,12 +2724,10 @@ mod tests {
// Check deleting the password
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
let me_purge_up = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![Modify::Purged(AttrString::from("unix_password"))]),
)
};
let me_purge_up = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![Modify::Purged(AttrString::from("unix_password"))]),
);
assert!(idms_prox_write.qs_write.modify(&me_purge_up).is_ok());
assert!(idms_prox_write.commit().is_ok());
@ -2748,15 +2755,14 @@ mod tests {
{
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
// now modify and provide a primary credential.
let me_inv_m = unsafe {
let me_inv_m =
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("password_import"),
Value::from("{SSHA512}JwrSUHkI7FTAfHRVR6KoFlSN0E3dmaQWARjZ+/UsShYlENOqDtFVU77HJLLrY2MuSp0jve52+pwtdVl2QUAHukQ0XUf5LDtM")
)]),
)
};
);
// go!
assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok());
assert!(idms_prox_write.commit().is_ok());
@ -2830,16 +2836,14 @@ mod tests {
let cred = Credential::new_from_password(pw);
let v_cred = Value::new_credential("unix", cred);
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
Modify::Present(AttrString::from("unix_password"), v_cred),
]),
)
};
let me_posix = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
Modify::Present(AttrString::from("unix_password"), v_cred),
]),
);
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
assert!(idms_prox_write.commit().is_ok());
idms_delayed.check_is_empty_or_panic();
@ -2887,15 +2891,13 @@ mod tests {
let v_expire = Value::new_datetime_epoch(Duration::from_secs(TEST_EXPIRE_TIME));
// now modify and provide a primary credential.
let me_inv_m = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("account_expire"), v_expire),
Modify::Present(AttrString::from("account_valid_from"), v_valid_from),
]),
)
};
let me_inv_m = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("account_expire"), v_expire),
Modify::Present(AttrString::from("account_valid_from"), v_valid_from),
]),
);
// go!
assert!(idms_write.qs_write.modify(&me_inv_m).is_ok());
@ -2979,15 +2981,13 @@ mod tests {
// make the admin a valid posix account
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
)
};
let me_posix = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
);
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
let pce = UnixPasswordChangeEvent::new_internal(UUID_ADMIN, TEST_PASSWORD);
@ -3056,7 +3056,12 @@ mod tests {
idms_prox_write.commit().expect("failed to commit");
let mut idms_prox_read = idms.proxy_read().await;
let rate = RadiusAuthTokenEvent::new_internal(UUID_ADMIN);
let admin_entry = idms_prox_read
.qs_read
.internal_search_uuid(UUID_ADMIN)
.expect("Can't access admin entry.");
let rate = RadiusAuthTokenEvent::new_impersonate(admin_entry, UUID_ADMIN);
let tok_r = idms_prox_read.get_radiusauthtoken(&rate, time_low);
if tok_r.is_err() {
@ -3339,15 +3344,13 @@ mod tests {
.expect("Failed to setup admin account");
// make the admin a valid posix account
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
)
};
let me_posix = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
]),
);
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
let pce = UnixPasswordChangeEvent::new_internal(UUID_ADMIN, TEST_PASSWORD);
@ -3718,16 +3721,14 @@ mod tests {
// fernet_private_key_str
// es256_private_key_der
let mut idms_prox_write = idms.proxy_write(ct).await;
let me_reset_tokens = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("uuid", PartialValue::Uuid(UUID_DOMAIN_INFO))),
ModifyList::new_list(vec![
Modify::Purged(AttrString::from("fernet_private_key_str")),
Modify::Purged(AttrString::from("es256_private_key_der")),
Modify::Purged(AttrString::from("domain_token_key")),
]),
)
};
let me_reset_tokens = ModifyEvent::new_internal_invalid(
filter!(f_eq("uuid", PartialValue::Uuid(UUID_DOMAIN_INFO))),
ModifyList::new_list(vec![
Modify::Purged(AttrString::from("fernet_private_key_str")),
Modify::Purged(AttrString::from("es256_private_key_der")),
Modify::Purged(AttrString::from("domain_token_key")),
]),
);
assert!(idms_prox_write.qs_write.modify(&me_reset_tokens).is_ok());
assert!(idms_prox_write.commit().is_ok());
// Check the old token is invalid, due to reload.

View file

@ -4,6 +4,10 @@
#![deny(warnings)]
#![recursion_limit = "512"]
#![warn(unused_extern_crates)]
// Enable some groups of clippy lints.
#![deny(clippy::suspicious)]
#![deny(clippy::perf)]
// Specific lints to enforce.
// TODO: can't use this until we have a better way to handle the 'todo' lint?
// #![deny(clippy::todo)]
#![warn(clippy::todo)]
@ -15,6 +19,7 @@
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
#![deny(clippy::disallowed_types)]
#![deny(clippy::manual_let_else)]
#![allow(clippy::unreachable)]
#[cfg(all(jemallocator, test, not(target_family = "windows")))]

View file

@ -69,7 +69,7 @@ macro_rules! entry_to_account {
use crate::idm::account::Account;
use crate::value::Value;
let mut e: Entry<EntryInvalid, EntryNew> = unsafe { $entry.clone().into_invalid_new() };
let mut e: Entry<EntryInvalid, EntryNew> = $entry.clone().into_invalid_new();
// Add spn, because normally this is generated but in tests we can't.
let spn = e
.get_ava_single_iname("name")
@ -77,7 +77,7 @@ macro_rules! entry_to_account {
.expect("Failed to munge spn from name!");
e.set_ava("spn", once(spn));
let e = unsafe { e.into_sealed_committed() };
let e = e.into_sealed_committed();
Account::try_from_entry_no_groups(&e).expect("Account conversion failure")
}};
@ -171,10 +171,8 @@ macro_rules! run_modify_test {
}
let me = match $internal {
None => unsafe { ModifyEvent::new_internal_invalid($modify_filter, $modify_list) },
Some(ent) => unsafe {
ModifyEvent::new_impersonate_entry(ent, $modify_filter, $modify_list)
},
None => ModifyEvent::new_internal_invalid($modify_filter, $modify_list),
Some(ent) => ModifyEvent::new_impersonate_entry(ent, $modify_filter, $modify_list),
};
{
@ -227,8 +225,8 @@ macro_rules! run_delete_test {
let qs = setup_test!($preload_entries);
let de = match $internal {
Some(ent) => unsafe { DeleteEvent::new_impersonate_entry(ent, $delete_filter.clone()) },
None => unsafe { DeleteEvent::new_internal_invalid($delete_filter.clone()) },
Some(ent) => DeleteEvent::new_impersonate_entry(ent, $delete_filter.clone()),
None => DeleteEvent::new_internal_invalid($delete_filter.clone()),
};
{

View file

@ -227,8 +227,10 @@ impl ModifyList<ModifyInvalid> {
})
}
/// ⚠️ - Convert a modlist to be considered valid, bypassing schema.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub(crate) unsafe fn into_valid(self) -> ModifyList<ModifyValid> {
pub(crate) fn into_valid(self) -> ModifyList<ModifyValid> {
ModifyList {
valid: ModifyValid,
mods: self.mods,
@ -237,8 +239,10 @@ impl ModifyList<ModifyInvalid> {
}
impl ModifyList<ModifyValid> {
/// ⚠️ - Create a new modlist that is considered valid, bypassing schema.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_valid_list(mods: Vec<Modify>) -> Self {
pub fn new_valid_list(mods: Vec<Modify>) -> Self {
ModifyList {
valid: ModifyValid,
mods,

View file

@ -302,7 +302,7 @@ mod tests {
pub static ref PRELOAD: Vec<EntryInitNew> =
vec![TEST_ACCOUNT.clone(), TEST_GROUP.clone(), ALLOW_ALL.clone()];
pub static ref E_TEST_ACCOUNT: Arc<EntrySealedCommitted> =
Arc::new(unsafe { TEST_ACCOUNT.clone().into_sealed_committed() });
Arc::new(TEST_ACCOUNT.clone().into_sealed_committed());
}
// check create where no uuid

View file

@ -169,10 +169,10 @@ mod tests {
.get_ava_set("name_history")
.expect("failed to get primary cred.");
dbg!(c.clone());
return assert!(
assert!(
c.contains(&PartialValue::new_utf8s("old_name"))
&& c.contains(&PartialValue::new_utf8s("new_name_1"))
);
)
}
);
}
@ -207,7 +207,7 @@ mod tests {
.get_ava_set("name_history")
.expect("failed to get name_history ava");
return assert!(name_history.contains(&PartialValue::new_utf8s(&"old_name")));
assert!(name_history.contains(&PartialValue::new_utf8s("old_name")))
}
);
}
@ -257,10 +257,10 @@ mod tests {
let c = e
.get_ava_set("name_history")
.expect("failed to get name_history ava :/");
return assert!(
!c.contains(&PartialValue::new_utf8s(&"old_name1"))
&& c.contains(&PartialValue::new_utf8s(&"new_name"))
);
assert!(
!c.contains(&PartialValue::new_utf8s("old_name1"))
&& c.contains(&PartialValue::new_utf8s("new_name"))
)
}
);
}

View file

@ -371,7 +371,7 @@ mod tests {
pub static ref PRELOAD: Vec<EntryInitNew> =
vec![TEST_ACCOUNT.clone(), TEST_GROUP.clone(), ALLOW_ALL.clone()];
pub static ref E_TEST_ACCOUNT: Arc<EntrySealedCommitted> =
Arc::new(unsafe { TEST_ACCOUNT.clone().into_sealed_committed() });
Arc::new(TEST_ACCOUNT.clone().into_sealed_committed());
}
#[test]

View file

@ -605,12 +605,11 @@ mod tests {
None,
|qs: &mut QueryServerWriteTransaction| {
// Any pre_hooks we need. In this case, we need to trigger the delete of testgroup_a
let de_sin = unsafe {
let de_sin =
crate::event::DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
"name",
PartialValue::new_iname("testgroup_a")
)])))
};
)])));
assert!(qs.delete(&de_sin).is_ok());
},
|_| {}

View file

@ -98,17 +98,14 @@ impl Plugin for Spn {
let mut r = Vec::new();
for e in all_cand {
let g_spn = match e.generate_spn(&domain_name) {
Some(s) => s,
None => {
admin_error!(
uuid = ?e.get_uuid(),
"Entry SPN could not be generated (missing name!?)",
);
debug_assert!(false);
r.push(Err(ConsistencyError::InvalidSpn(e.get_id())));
continue;
}
let Some(g_spn) = e.generate_spn(&domain_name) else {
admin_error!(
uuid = ?e.get_uuid(),
"Entry SPN could not be generated (missing name!?)",
);
debug_assert!(false);
r.push(Err(ConsistencyError::InvalidSpn(e.get_id())));
continue;
};
match e.get_ava_single("spn") {
Some(r_spn) => {
@ -182,9 +179,8 @@ impl Spn {
}
});
let domain_name = match domain_name_changed {
Some(s) => s,
None => return Ok(()),
let Some(domain_name) = domain_name_changed else {
return Ok(())
};
admin_info!(
@ -337,11 +333,9 @@ mod tests {
// trigger the domain_name change (this will be a cli option to the server
// in the final version), but it will still call the same qs function to perform the
// change.
unsafe {
server_txn
.domain_rename_inner("new.example.com")
.expect("should not fail!");
}
server_txn
.danger_domain_rename("new.example.com")
.expect("should not fail!");
// check the spn on admin is admin@<new domain>
let e_post = server_txn

View file

@ -33,27 +33,23 @@ impl Cid {
Cid { ts, s_uuid }
}
/// ⚠️ - Create a new cid at timestamp zero.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_zero() -> Self {
pub fn new_zero() -> Self {
Self::new_count(0)
}
/// ⚠️ - Create a new cid with a manually defined timestamp.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub unsafe fn new_count(c: u64) -> Self {
pub fn new_count(c: u64) -> Self {
Cid {
s_uuid: uuid!("00000000-0000-0000-0000-000000000000"),
ts: Duration::new(c, 0),
}
}
#[cfg(test)]
pub fn new_random_s_d(ts: Duration) -> Self {
Cid {
s_uuid: Uuid::new_v4(),
ts,
}
}
#[allow(clippy::expect_used)]
pub fn sub_secs(&self, secs: u64) -> Result<Self, OperationError> {
self.ts
@ -113,7 +109,7 @@ mod tests {
let ts10 = Duration::new(10, 0);
let ts15 = Duration::new(15, 0);
let cid_z = unsafe { Cid::new_zero() };
let cid_z = Cid::new_zero();
let cid_a = Cid::new_lamport(s_uuid, ts5, &ts5);
assert!(cid_a.cmp(&cid_z) == Ordering::Greater);

View file

@ -234,16 +234,13 @@ pub trait ReplicationUpdateVectorTransaction {
// For each server and range low to high, iterate over
// the list of CID's in the main RUV.
let ruv_range = match range.get(s_uuid) {
Some(r) => r,
None => {
// This is valid because if we clean up a server range on
// this node, but the other server isn't aware yet, so we
// just no-op this. The changes we have will still be
// correctly found and sent.
debug!(?s_uuid, "range not found in ruv.");
continue;
}
let Some(ruv_range) = range.get(s_uuid) else {
// This is valid because if we clean up a server range on
// this node, but the other server isn't aware yet, so we
// just no-op this. The changes we have will still be
// correctly found and sent.
debug!(?s_uuid, "range not found in ruv.");
continue;
};
// Get from the min to the max. Unbounded and

View file

@ -2002,7 +2002,7 @@ mod tests {
$type:ty
) => {{
let e1: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str($e);
let ev1 = unsafe { e1.into_sealed_committed() };
let ev1 = e1.into_sealed_committed();
let r1 = <$type>::try_from(&ev1);
assert!(r1.is_ok());
@ -2015,7 +2015,7 @@ mod tests {
$type:ty
) => {{
let e1: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str($e);
let ev1 = unsafe { e1.into_sealed_committed() };
let ev1 = e1.into_sealed_committed();
let r1 = <$type>::try_from(&ev1);
assert!(r1.is_err());
@ -2363,94 +2363,84 @@ mod tests {
let schema_outer = Schema::new().expect("failed to create schema");
let schema = schema_outer.read();
let e_no_uuid = unsafe { entry_init!().into_invalid_new() };
let e_no_uuid = entry_init!().into_invalid_new();
assert_eq!(
e_no_uuid.validate(&schema),
Err(SchemaError::MissingMustAttribute(vec!["uuid".to_string()]))
);
let e_no_class = unsafe {
entry_init!((
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
))
.into_invalid_new()
};
let e_no_class = entry_init!((
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
))
.into_invalid_new();
assert_eq!(e_no_class.validate(&schema), Err(SchemaError::NoClassFound));
let e_bad_class = unsafe {
entry_init!(
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("class", Value::new_class("zzzzzz"))
)
.into_invalid_new()
};
let e_bad_class = entry_init!(
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("class", Value::new_class("zzzzzz"))
)
.into_invalid_new();
assert_eq!(
e_bad_class.validate(&schema),
Err(SchemaError::InvalidClass(vec!["zzzzzz".to_string()]))
);
let e_attr_invalid = unsafe {
entry_init!(
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("class", CLASS_OBJECT.clone()),
("class", CLASS_ATTRIBUTETYPE.clone())
)
.into_invalid_new()
};
let e_attr_invalid = entry_init!(
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("class", CLASS_OBJECT.clone()),
("class", CLASS_ATTRIBUTETYPE.clone())
)
.into_invalid_new();
let res = e_attr_invalid.validate(&schema);
assert!(match res {
Err(SchemaError::MissingMustAttribute(_)) => true,
_ => false,
});
let e_attr_invalid_may = unsafe {
entry_init!(
("class", CLASS_OBJECT.clone()),
("class", CLASS_ATTRIBUTETYPE.clone()),
("attributename", Value::new_iutf8("testattr")),
("description", Value::Utf8("testattr".to_string())),
("multivalue", Value::Bool(false)),
("unique", Value::Bool(false)),
("syntax", Value::Syntax(SyntaxType::Utf8String)),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("zzzzz", Value::Utf8("zzzz".to_string()))
)
.into_invalid_new()
};
let e_attr_invalid_may = entry_init!(
("class", CLASS_OBJECT.clone()),
("class", CLASS_ATTRIBUTETYPE.clone()),
("attributename", Value::new_iutf8("testattr")),
("description", Value::Utf8("testattr".to_string())),
("multivalue", Value::Bool(false)),
("unique", Value::Bool(false)),
("syntax", Value::Syntax(SyntaxType::Utf8String)),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("zzzzz", Value::Utf8("zzzz".to_string()))
)
.into_invalid_new();
assert_eq!(
e_attr_invalid_may.validate(&schema),
Err(SchemaError::AttributeNotValidForClass("zzzzz".to_string()))
);
let e_attr_invalid_syn = unsafe {
entry_init!(
("class", CLASS_OBJECT.clone()),
("class", CLASS_ATTRIBUTETYPE.clone()),
("attributename", Value::new_iutf8("testattr")),
("description", Value::Utf8("testattr".to_string())),
("multivalue", Value::Utf8("false".to_string())),
("unique", Value::Bool(false)),
("syntax", Value::Syntax(SyntaxType::Utf8String)),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
)
let e_attr_invalid_syn = entry_init!(
("class", CLASS_OBJECT.clone()),
("class", CLASS_ATTRIBUTETYPE.clone()),
("attributename", Value::new_iutf8("testattr")),
("description", Value::Utf8("testattr".to_string())),
("multivalue", Value::Utf8("false".to_string())),
("unique", Value::Bool(false)),
("syntax", Value::Syntax(SyntaxType::Utf8String)),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
)
.into_invalid_new()
};
)
.into_invalid_new();
assert_eq!(
e_attr_invalid_syn.validate(&schema),
@ -2460,41 +2450,37 @@ mod tests {
);
// You may not have the phantom.
let e_phantom = unsafe {
entry_init!(
("class", CLASS_OBJECT.clone()),
("class", CLASS_ATTRIBUTETYPE.clone()),
("attributename", Value::new_iutf8("testattr")),
("description", Value::Utf8("testattr".to_string())),
("multivalue", Value::Bool(false)),
("unique", Value::Bool(false)),
("syntax", Value::Syntax(SyntaxType::Utf8String)),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("password_import", Value::Utf8("password".to_string()))
)
.into_invalid_new()
};
let e_phantom = entry_init!(
("class", CLASS_OBJECT.clone()),
("class", CLASS_ATTRIBUTETYPE.clone()),
("attributename", Value::new_iutf8("testattr")),
("description", Value::Utf8("testattr".to_string())),
("multivalue", Value::Bool(false)),
("unique", Value::Bool(false)),
("syntax", Value::Syntax(SyntaxType::Utf8String)),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
),
("password_import", Value::Utf8("password".to_string()))
)
.into_invalid_new();
assert!(e_phantom.validate(&schema).is_err());
let e_ok = unsafe {
entry_init!(
("class", CLASS_OBJECT.clone()),
("class", CLASS_ATTRIBUTETYPE.clone()),
("attributename", Value::new_iutf8("testattr")),
("description", Value::Utf8("testattr".to_string())),
("multivalue", Value::Bool(true)),
("unique", Value::Bool(false)),
("syntax", Value::Syntax(SyntaxType::Utf8String)),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
)
let e_ok = entry_init!(
("class", CLASS_OBJECT.clone()),
("class", CLASS_ATTRIBUTETYPE.clone()),
("attributename", Value::new_iutf8("testattr")),
("description", Value::Utf8("testattr".to_string())),
("multivalue", Value::Bool(true)),
("unique", Value::Bool(false)),
("syntax", Value::Syntax(SyntaxType::Utf8String)),
(
"uuid",
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
)
.into_invalid_new()
};
)
.into_invalid_new();
assert!(e_ok.validate(&schema).is_ok());
}
@ -2508,9 +2494,8 @@ mod tests {
// check index to upper
// insense to lower
// attr name to lower
let e_test: Entry<EntryInvalid, EntryNew> = unsafe {
Entry::unsafe_from_entry_str(
r#"{
let e_test: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
r#"{
"attrs": {
"class": ["extensibleobject"],
"name": ["TestPerson"],
@ -2519,13 +2504,11 @@ mod tests {
"InDeX": ["equality"]
}
}"#,
)
.into_invalid_new()
};
)
.into_invalid_new();
let e_expect: Entry<EntryValid, EntryNew> = unsafe {
Entry::unsafe_from_entry_str(
r#"{
let e_expect: Entry<EntryValid, EntryNew> = Entry::unsafe_from_entry_str(
r#"{
"attrs": {
"class": ["extensibleobject"],
"name": ["testperson"],
@ -2534,9 +2517,8 @@ mod tests {
"index": ["EQUALITY"]
}
}"#,
)
.into_valid_new()
};
)
.into_valid_new();
let e_valid = e_test.validate(&schema).expect("validation failure");
@ -2549,18 +2531,16 @@ mod tests {
let schema = schema_outer.read();
// Just because you are extensible, doesn't mean you can be lazy
let e_extensible_bad: Entry<EntryInvalid, EntryNew> = unsafe {
Entry::unsafe_from_entry_str(
r#"{
let e_extensible_bad: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
r#"{
"attrs": {
"class": ["extensibleobject"],
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
"multivalue": ["zzzz"]
}
}"#,
)
.into_invalid_new()
};
)
.into_invalid_new();
assert_eq!(
e_extensible_bad.validate(&schema),
@ -2570,36 +2550,32 @@ mod tests {
);
// Extensible doesn't mean you can have the phantoms
let e_extensible_phantom: Entry<EntryInvalid, EntryNew> = unsafe {
Entry::unsafe_from_entry_str(
r#"{
let e_extensible_phantom: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
r#"{
"attrs": {
"class": ["extensibleobject"],
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
"password_import": ["zzzz"]
}
}"#,
)
.into_invalid_new()
};
)
.into_invalid_new();
assert_eq!(
e_extensible_phantom.validate(&schema),
Err(SchemaError::PhantomAttribute("password_import".to_string()))
);
let e_extensible: Entry<EntryInvalid, EntryNew> = unsafe {
Entry::unsafe_from_entry_str(
r#"{
let e_extensible: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
r#"{
"attrs": {
"class": ["extensibleobject"],
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
"multivalue": ["true"]
}
}"#,
)
.into_invalid_new()
};
)
.into_invalid_new();
/* Is okay because extensible! */
assert!(e_extensible.validate(&schema).is_ok());
@ -2628,7 +2604,10 @@ mod tests {
let f_insense = filter_all!(f_eq("class", PartialValue::new_class("AttributeType")));
assert_eq!(
f_insense.validate(&schema),
Ok(unsafe { filter_valid!(f_eq("class", PartialValue::new_class("attributetype"))) })
Ok(filter_valid!(f_eq(
"class",
PartialValue::new_class("attributetype")
)))
);
// Test the recursive structures validate
let f_or_empty = filter_all!(f_or!([]));
@ -2658,13 +2637,11 @@ mod tests {
])));
assert_eq!(
f_or_ok.validate(&schema),
Ok(unsafe {
filter_valid!(f_andnot(f_and!([
f_eq("class", PartialValue::new_class("attributetype")),
f_sub("class", PartialValue::new_class("classtype")),
f_pres("class")
])))
})
Ok(filter_valid!(f_andnot(f_and!([
f_eq("class", PartialValue::new_class("attributetype")),
f_sub("class", PartialValue::new_class("classtype")),
f_pres("class")
]))))
);
}
@ -2744,13 +2721,11 @@ mod tests {
.is_ok());
// Missing person or service account.
let e_account = unsafe {
entry_init!(
("class", Value::new_class("account")),
("uuid", Value::Uuid(Uuid::new_v4()))
)
.into_invalid_new()
};
let e_account = entry_init!(
("class", Value::new_class("account")),
("uuid", Value::Uuid(Uuid::new_v4()))
)
.into_invalid_new();
assert_eq!(
e_account.validate(&schema),
@ -2774,15 +2749,13 @@ mod tests {
*/
// Service can't have person
let e_service_person = unsafe {
entry_init!(
("class", Value::new_class("service")),
("class", Value::new_class("account")),
("class", Value::new_class("person")),
("uuid", Value::Uuid(Uuid::new_v4()))
)
.into_invalid_new()
};
let e_service_person = entry_init!(
("class", Value::new_class("service")),
("class", Value::new_class("account")),
("class", Value::new_class("person")),
("uuid", Value::Uuid(Uuid::new_v4()))
)
.into_invalid_new();
assert_eq!(
e_service_person.validate(&schema),
@ -2792,35 +2765,29 @@ mod tests {
);
// These are valid configurations.
let e_service_valid = unsafe {
entry_init!(
("class", Value::new_class("service")),
("class", Value::new_class("account")),
("uuid", Value::Uuid(Uuid::new_v4()))
)
.into_invalid_new()
};
let e_service_valid = entry_init!(
("class", Value::new_class("service")),
("class", Value::new_class("account")),
("uuid", Value::Uuid(Uuid::new_v4()))
)
.into_invalid_new();
assert!(e_service_valid.validate(&schema).is_ok());
let e_person_valid = unsafe {
entry_init!(
("class", Value::new_class("person")),
("class", Value::new_class("account")),
("uuid", Value::Uuid(Uuid::new_v4()))
)
.into_invalid_new()
};
let e_person_valid = entry_init!(
("class", Value::new_class("person")),
("class", Value::new_class("account")),
("uuid", Value::Uuid(Uuid::new_v4()))
)
.into_invalid_new();
assert!(e_person_valid.validate(&schema).is_ok());
let e_person_valid = unsafe {
entry_init!(
("class", Value::new_class("person")),
("uuid", Value::Uuid(Uuid::new_v4()))
)
.into_invalid_new()
};
let e_person_valid = entry_init!(
("class", Value::new_class("person")),
("uuid", Value::Uuid(Uuid::new_v4()))
)
.into_invalid_new();
assert!(e_person_valid.validate(&schema).is_ok());
}

File diff suppressed because it is too large Load diff

View file

@ -41,8 +41,10 @@ impl AccessControlSearch {
Ok(AccessControlSearch { acp, attrs })
}
/// ⚠️ - Manually create a search access profile from values.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub(super) unsafe fn from_raw(
pub(super) fn from_raw(
name: &str,
uuid: Uuid,
receiver: Uuid,
@ -83,8 +85,10 @@ impl AccessControlDelete {
})
}
/// ⚠️ - Manually create a delete access profile from values.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub(super) unsafe fn from_raw(
pub(super) fn from_raw(
name: &str,
uuid: Uuid,
receiver: Uuid,
@ -137,8 +141,10 @@ impl AccessControlCreate {
})
}
/// ⚠️ - Manually create a create access profile from values.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub(super) unsafe fn from_raw(
pub(super) fn from_raw(
name: &str,
uuid: Uuid,
receiver: Uuid,
@ -202,8 +208,10 @@ impl AccessControlModify {
})
}
/// ⚠️ - Manually create a modify access profile from values.
/// This is a TEST ONLY method and will never be exposed in production.
#[cfg(test)]
pub(super) unsafe fn from_raw(
pub(super) fn from_raw(
name: &str,
uuid: Uuid,
receiver: Uuid,

View file

@ -172,7 +172,7 @@ mod tests {
let filt = filter!(f_eq("name", PartialValue::new_iname("testperson")));
let admin = server_txn.internal_search_uuid(UUID_ADMIN).expect("failed");
let se1 = unsafe { SearchEvent::new_impersonate_entry(admin, filt) };
let se1 = SearchEvent::new_impersonate_entry(admin, filt);
let mut e = entry_init!(
("class", Value::new_class("object")),
@ -212,7 +212,7 @@ mod tests {
Value::AuditLogString(server_txn.get_txn_cid().clone(), "testperson".to_string()),
);
let expected = unsafe { vec![Arc::new(e.into_sealed_committed())] };
let expected = vec![Arc::new(e.into_sealed_committed())];
assert_eq!(r2, expected);
@ -230,12 +230,12 @@ mod tests {
let admin = server_a_txn
.internal_search_uuid(UUID_ADMIN)
.expect("failed");
let se_a = unsafe { SearchEvent::new_impersonate_entry(admin, filt.clone()) };
let se_a = SearchEvent::new_impersonate_entry(admin, filt.clone());
let admin = server_b_txn
.internal_search_uuid(UUID_ADMIN)
.expect("failed");
let se_b = unsafe { SearchEvent::new_impersonate_entry(admin, filt) };
let se_b = SearchEvent::new_impersonate_entry(admin, filt);
let e = entry_init!(
("class", Value::new_class("person")),

View file

@ -234,35 +234,28 @@ mod tests {
assert!(cr.is_ok());
// Delete filter is syntax invalid
let de_inv =
unsafe { DeleteEvent::new_internal_invalid(filter!(f_pres("nhtoaunaoehtnu"))) };
let de_inv = DeleteEvent::new_internal_invalid(filter!(f_pres("nhtoaunaoehtnu")));
assert!(server_txn.delete(&de_inv).is_err());
// Delete deletes nothing
let de_empty = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_eq(
"uuid",
PartialValue::Uuid(uuid!("cc8e95b4-c24f-4d68-ba54-000000000000"))
)))
};
let de_empty = DeleteEvent::new_internal_invalid(filter!(f_eq(
"uuid",
PartialValue::Uuid(uuid!("cc8e95b4-c24f-4d68-ba54-000000000000"))
)));
assert!(server_txn.delete(&de_empty).is_err());
// Delete matches one
let de_sin = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_eq(
"name",
PartialValue::new_iname("testperson3")
)))
};
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_eq(
"name",
PartialValue::new_iname("testperson3")
)));
assert!(server_txn.delete(&de_sin).is_ok());
// Delete matches many
let de_mult = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_eq(
"description",
PartialValue::new_utf8s("testperson")
)))
};
let de_mult = DeleteEvent::new_internal_invalid(filter!(f_eq(
"description",
PartialValue::new_utf8s("testperson")
)));
assert!(server_txn.delete(&de_mult).is_ok());
assert!(server_txn.commit().is_ok());

View file

@ -153,9 +153,8 @@ impl<'a> QueryServerWriteTransaction<'a> {
// correctly!
trace!("internal_migrate_or_create operating on {:?}", e.get_uuid());
let filt = match e.filter_from_attrs(&[AttrString::from("uuid")]) {
Some(f) => f,
None => return Err(OperationError::FilterGeneration),
let Some(filt) = e.filter_from_attrs(&[AttrString::from("uuid")]) else {
return Err(OperationError::FilterGeneration)
};
trace!("internal_migrate_or_create search {:?}", filt);

View file

@ -1479,13 +1479,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
/// Initiate a domain rename process. This is generally an internal function but it's
/// exposed to the cli for admins to be able to initiate the process.
pub fn domain_rename(&mut self, new_domain_name: &str) -> Result<(), OperationError> {
// We can't use the d_info struct here, because this has the database version of the domain
// name, not the in memory (config) version. We need to accept the domain's
// new name from the caller so we can change this.
unsafe { self.domain_rename_inner(new_domain_name) }
}
///
/// # Safety
/// This is UNSAFE because while it may change the domain name, it doesn't update
/// the running configured version of the domain name that is resident to the
@ -1495,10 +1489,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
/// that impacts spns, but in the future we may need to reconsider how this is
/// approached, especially if we have a domain re-name replicated to us. It could
/// be that we end up needing to have this as a cow cell or similar?
pub(crate) unsafe fn domain_rename_inner(
&mut self,
new_domain_name: &str,
) -> Result<(), OperationError> {
pub fn danger_domain_rename(&mut self, new_domain_name: &str) -> Result<(), OperationError> {
let modl = ModifyList::new_purge_and_set("domain_name", Value::new_iname(new_domain_name));
let udi = PVUUID_DOMAIN_INFO.clone();
let filt = filter_all!(f_eq("uuid", udi));
@ -1830,12 +1821,10 @@ mod tests {
// Start a new write
let mut server_txn = server.write(duration_from_epoch_now()).await;
// delete the class
let de_class = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_eq(
"classname",
PartialValue::new_class("testclass")
)))
};
let de_class = DeleteEvent::new_internal_invalid(filter!(f_eq(
"classname",
PartialValue::new_class("testclass")
)));
assert!(server_txn.delete(&de_class).is_ok());
// Commit
server_txn.commit().expect("should not fail");
@ -1908,12 +1897,10 @@ mod tests {
// Start a new write
let mut server_txn = server.write(duration_from_epoch_now()).await;
// delete the attr
let de_attr = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_eq(
"attributename",
PartialValue::new_iutf8("testattr")
)))
};
let de_attr = DeleteEvent::new_internal_invalid(filter!(f_eq(
"attributename",
PartialValue::new_iutf8("testattr")
)));
assert!(server_txn.delete(&de_attr).is_ok());
// Commit
server_txn.commit().expect("should not fail");

View file

@ -12,7 +12,7 @@ pub(crate) struct ModifyPartial<'a> {
impl<'a> QueryServerWriteTransaction<'a> {
#[instrument(level = "debug", skip_all)]
pub fn modify(&mut self, me: &ModifyEvent) -> Result<(), OperationError> {
let mp = unsafe { self.modify_pre_apply(me)? };
let mp = self.modify_pre_apply(me)?;
if let Some(mp) = mp {
self.modify_apply(mp)
} else {
@ -25,7 +25,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
/// the Ok(None) case which occurs during internal operations, and that you DO NOT re-order
/// and call multiple pre-applies at the same time, else you can cause DB corruption.
#[instrument(level = "debug", skip_all)]
pub(crate) unsafe fn modify_pre_apply<'x>(
pub(crate) fn modify_pre_apply<'x>(
&mut self,
me: &'x ModifyEvent,
) -> Result<Option<ModifyPartial<'x>>, OperationError> {
@ -511,25 +511,21 @@ mod tests {
assert!(cr.is_ok());
// Empty Modlist (filter is valid)
let me_emp = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_pres("class")),
ModifyList::new_list(vec![]),
)
};
let me_emp = ModifyEvent::new_internal_invalid(
filter!(f_pres("class")),
ModifyList::new_list(vec![]),
);
assert!(server_txn.modify(&me_emp) == Err(OperationError::EmptyRequest));
// Mod changes no objects
let me_nochg = unsafe {
ModifyEvent::new_impersonate_entry_ser(
JSON_ADMIN_V1,
filter!(f_eq("name", PartialValue::new_iname("flarbalgarble"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("description"),
Value::from("anusaosu"),
)]),
)
};
let me_nochg = ModifyEvent::new_impersonate_entry_ser(
JSON_ADMIN_V1,
filter!(f_eq("name", PartialValue::new_iname("flarbalgarble"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("description"),
Value::from("anusaosu"),
)]),
);
assert!(server_txn.modify(&me_nochg) == Err(OperationError::NoMatchingEntries));
// Filter is invalid to schema - to check this due to changes in the way events are
@ -551,15 +547,13 @@ mod tests {
);
// Mod is invalid to schema
let me_inv_m = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_pres("class")),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("htnaonu"),
Value::from("anusaosu"),
)]),
)
};
let me_inv_m = ModifyEvent::new_internal_invalid(
filter!(f_pres("class")),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("htnaonu"),
Value::from("anusaosu"),
)]),
);
assert!(
server_txn.modify(&me_inv_m)
== Err(OperationError::SchemaViolation(
@ -568,30 +562,26 @@ mod tests {
);
// Mod single object
let me_sin = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson2"))),
ModifyList::new_list(vec![
Modify::Purged(AttrString::from("description")),
Modify::Present(AttrString::from("description"), Value::from("anusaosu")),
]),
)
};
let me_sin = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson2"))),
ModifyList::new_list(vec![
Modify::Purged(AttrString::from("description")),
Modify::Present(AttrString::from("description"), Value::from("anusaosu")),
]),
);
assert!(server_txn.modify(&me_sin).is_ok());
// Mod multiple object
let me_mult = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_or!([
f_eq("name", PartialValue::new_iname("testperson1")),
f_eq("name", PartialValue::new_iname("testperson2")),
])),
ModifyList::new_list(vec![
Modify::Purged(AttrString::from("description")),
Modify::Present(AttrString::from("description"), Value::from("anusaosu")),
]),
)
};
let me_mult = ModifyEvent::new_internal_invalid(
filter!(f_or!([
f_eq("name", PartialValue::new_iname("testperson1")),
f_eq("name", PartialValue::new_iname("testperson2")),
])),
ModifyList::new_list(vec![
Modify::Purged(AttrString::from("description")),
Modify::Present(AttrString::from("description"), Value::from("anusaosu")),
]),
);
assert!(server_txn.modify(&me_mult).is_ok());
assert!(server_txn.commit().is_ok());
@ -659,52 +649,44 @@ mod tests {
assert!(cr.is_ok());
// Add class but no values
let me_sin = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("class"),
Value::new_class("system_info"),
)]),
)
};
let me_sin = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("class"),
Value::new_class("system_info"),
)]),
);
assert!(server_txn.modify(&me_sin).is_err());
// Add multivalue where not valid
let me_sin = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("name"),
Value::new_iname("testpersonx"),
)]),
)
};
let me_sin = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("name"),
Value::new_iname("testpersonx"),
)]),
);
assert!(server_txn.modify(&me_sin).is_err());
// add class and valid values?
let me_sin = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("system_info")),
// Modify::Present("domain".to_string(), Value::new_iutf8("domain.name")),
Modify::Present(AttrString::from("version"), Value::new_uint32(1)),
]),
)
};
let me_sin = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
ModifyList::new_list(vec![
Modify::Present(AttrString::from("class"), Value::new_class("system_info")),
// Modify::Present("domain".to_string(), Value::new_iutf8("domain.name")),
Modify::Present(AttrString::from("version"), Value::new_uint32(1)),
]),
);
assert!(server_txn.modify(&me_sin).is_ok());
// Replace a value
let me_sin = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
ModifyList::new_list(vec![
Modify::Purged(AttrString::from("name")),
Modify::Present(AttrString::from("name"), Value::new_iname("testpersonx")),
]),
)
};
let me_sin = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
ModifyList::new_list(vec![
Modify::Purged(AttrString::from("name")),
Modify::Present(AttrString::from("name"), Value::new_iname("testpersonx")),
]),
);
assert!(server_txn.modify(&me_sin).is_ok());
}
@ -736,15 +718,13 @@ mod tests {
assert!(v_cred.validate());
// now modify and provide a primary credential.
let me_inv_m = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("primary_credential"),
v_cred,
)]),
)
};
let me_inv_m = ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("primary_credential"),
v_cred,
)]),
);
// go!
assert!(server_txn.modify(&me_inv_m).is_ok());

View file

@ -258,31 +258,25 @@ mod tests {
let filt_i_per = filter_all!(f_eq("class", PartialValue::new_class("person")));
// Create fake external requests. Probably from admin later
let me_rc = unsafe {
ModifyEvent::new_impersonate_entry(
admin.clone(),
filt_i_rc.clone(),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("class"),
Value::new_class("recycled"),
)]),
)
};
let me_rc = ModifyEvent::new_impersonate_entry(
admin.clone(),
filt_i_rc.clone(),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("class"),
Value::new_class("recycled"),
)]),
);
let de_rc = unsafe { DeleteEvent::new_impersonate_entry(admin.clone(), filt_i_rc.clone()) };
let de_rc = DeleteEvent::new_impersonate_entry(admin.clone(), filt_i_rc.clone());
let se_rc =
unsafe { SearchEvent::new_ext_impersonate_entry(admin.clone(), filt_i_rc.clone()) };
let se_rc = SearchEvent::new_ext_impersonate_entry(admin.clone(), filt_i_rc.clone());
let sre_rc =
unsafe { SearchEvent::new_rec_impersonate_entry(admin.clone(), filt_i_rc.clone()) };
let sre_rc = SearchEvent::new_rec_impersonate_entry(admin.clone(), filt_i_rc.clone());
let rre_rc = unsafe {
ReviveRecycledEvent::new_impersonate_entry(
admin,
filter_all!(f_eq("name", PartialValue::new_iname("testperson1"))),
)
};
let rre_rc = ReviveRecycledEvent::new_impersonate_entry(
admin,
filter_all!(f_eq("name", PartialValue::new_iname("testperson1"))),
);
// Create some recycled objects
let e1 = entry_init!(
@ -314,12 +308,10 @@ mod tests {
assert!(cr.is_ok());
// Now we immediately delete these to force them to the correct state.
let de_sin = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_or!([
f_eq("name", PartialValue::new_iname("testperson1")),
f_eq("name", PartialValue::new_iname("testperson2")),
])))
};
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_or!([
f_eq("name", PartialValue::new_iname("testperson1")),
f_eq("name", PartialValue::new_iname("testperson2")),
])));
assert!(server_txn.delete(&de_sin).is_ok());
// Can it be seen (external search)
@ -409,16 +401,14 @@ mod tests {
let cr = server_txn.create(&ce);
assert!(cr.is_ok());
// Delete and ensure they became recycled.
let de_sin = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_eq(
"name",
PartialValue::new_iname("testperson1")
)))
};
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_eq(
"name",
PartialValue::new_iname("testperson1")
)));
assert!(server_txn.delete(&de_sin).is_ok());
// Can in be seen by special search? (external recycle search)
let filt_rc = filter_all!(f_eq("class", PartialValue::new_class("recycled")));
let sre_rc = unsafe { SearchEvent::new_rec_impersonate_entry(admin, filt_rc) };
let sre_rc = SearchEvent::new_rec_impersonate_entry(admin, filt_rc);
let r2 = server_txn.search(&sre_rc).expect("search failed");
assert!(r2.len() == 1);
@ -463,12 +453,10 @@ mod tests {
assert!(server_txn.name_to_uuid("testperson1") == Ok(tuuid));
// delete
let de_sin = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_eq(
"name",
PartialValue::new_iname("testperson1")
)))
};
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_eq(
"name",
PartialValue::new_iname("testperson1")
)));
assert!(server_txn.delete(&de_sin).is_ok());
// all should fail
@ -483,12 +471,10 @@ mod tests {
// revive
let admin = server_txn.internal_search_uuid(UUID_ADMIN).expect("failed");
let rre_rc = unsafe {
ReviveRecycledEvent::new_impersonate_entry(
admin,
filter_all!(f_eq("name", PartialValue::new_iname("testperson1"))),
)
};
let rre_rc = ReviveRecycledEvent::new_impersonate_entry(
admin,
filter_all!(f_eq("name", PartialValue::new_iname("testperson1"))),
);
assert!(server_txn.revive_recycled(&rre_rc).is_ok());
// all checks pass
@ -518,19 +504,17 @@ mod tests {
// Create fake external requests. Probably from admin later
// Should we do this with impersonate instead of using the external
let me_ts = unsafe {
ModifyEvent::new_impersonate_entry(
admin.clone(),
filt_i_ts.clone(),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("class"),
Value::new_class("tombstone"),
)]),
)
};
let me_ts = ModifyEvent::new_impersonate_entry(
admin.clone(),
filt_i_ts.clone(),
ModifyList::new_list(vec![Modify::Present(
AttrString::from("class"),
Value::new_class("tombstone"),
)]),
);
let de_ts = unsafe { DeleteEvent::new_impersonate_entry(admin.clone(), filt_i_ts.clone()) };
let se_ts = unsafe { SearchEvent::new_ext_impersonate_entry(admin, filt_i_ts.clone()) };
let de_ts = DeleteEvent::new_impersonate_entry(admin.clone(), filt_i_ts.clone());
let se_ts = SearchEvent::new_ext_impersonate_entry(admin, filt_i_ts.clone());
// First, create an entry, then push it through the lifecycle.
let e_ts = entry_init!(
@ -549,12 +533,10 @@ mod tests {
let cr = server_txn.create(&ce);
assert!(cr.is_ok());
let de_sin = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
"name",
PartialValue::new_iname("testperson1")
)])))
};
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
"name",
PartialValue::new_iname("testperson1")
)])));
assert!(server_txn.delete(&de_sin).is_ok());
// Commit
@ -696,25 +678,21 @@ mod tests {
assert!(cr.is_ok());
// Now recycle the needed entries.
let de = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_or(vec![
f_eq("name", PartialValue::new_iname("u1")),
f_eq("name", PartialValue::new_iname("u2")),
f_eq("name", PartialValue::new_iname("u3")),
f_eq("name", PartialValue::new_iname("g3")),
f_eq("name", PartialValue::new_iname("u4")),
f_eq("name", PartialValue::new_iname("g4"))
])))
};
let de = DeleteEvent::new_internal_invalid(filter!(f_or(vec![
f_eq("name", PartialValue::new_iname("u1")),
f_eq("name", PartialValue::new_iname("u2")),
f_eq("name", PartialValue::new_iname("u3")),
f_eq("name", PartialValue::new_iname("g3")),
f_eq("name", PartialValue::new_iname("u4")),
f_eq("name", PartialValue::new_iname("g4"))
])));
assert!(server_txn.delete(&de).is_ok());
// Now revive and check each one, one at a time.
let rev1 = unsafe {
ReviveRecycledEvent::new_impersonate_entry(
admin.clone(),
filter_all!(f_eq("name", PartialValue::new_iname("u1"))),
)
};
let rev1 = ReviveRecycledEvent::new_impersonate_entry(
admin.clone(),
filter_all!(f_eq("name", PartialValue::new_iname("u1"))),
);
assert!(server_txn.revive_recycled(&rev1).is_ok());
// check u1 contains MO ->
assert!(check_entry_has_mo(
@ -724,12 +702,10 @@ mod tests {
));
// Revive u2 and check it has two mo.
let rev2 = unsafe {
ReviveRecycledEvent::new_impersonate_entry(
admin.clone(),
filter_all!(f_eq("name", PartialValue::new_iname("u2"))),
)
};
let rev2 = ReviveRecycledEvent::new_impersonate_entry(
admin.clone(),
filter_all!(f_eq("name", PartialValue::new_iname("u2"))),
);
assert!(server_txn.revive_recycled(&rev2).is_ok());
assert!(check_entry_has_mo(
&mut server_txn,
@ -743,15 +719,13 @@ mod tests {
));
// Revive u3 and g3 at the same time.
let rev3 = unsafe {
ReviveRecycledEvent::new_impersonate_entry(
admin.clone(),
filter_all!(f_or(vec![
f_eq("name", PartialValue::new_iname("u3")),
f_eq("name", PartialValue::new_iname("g3"))
])),
)
};
let rev3 = ReviveRecycledEvent::new_impersonate_entry(
admin.clone(),
filter_all!(f_or(vec![
f_eq("name", PartialValue::new_iname("u3")),
f_eq("name", PartialValue::new_iname("g3"))
])),
);
assert!(server_txn.revive_recycled(&rev3).is_ok());
assert!(!check_entry_has_mo(
&mut server_txn,
@ -760,12 +734,10 @@ mod tests {
));
// Revive u4, should NOT have the MO.
let rev4a = unsafe {
ReviveRecycledEvent::new_impersonate_entry(
admin.clone(),
filter_all!(f_eq("name", PartialValue::new_iname("u4"))),
)
};
let rev4a = ReviveRecycledEvent::new_impersonate_entry(
admin.clone(),
filter_all!(f_eq("name", PartialValue::new_iname("u4"))),
);
assert!(server_txn.revive_recycled(&rev4a).is_ok());
assert!(!check_entry_has_mo(
&mut server_txn,
@ -774,12 +746,10 @@ mod tests {
));
// Now revive g4, should allow MO onto u4.
let rev4b = unsafe {
ReviveRecycledEvent::new_impersonate_entry(
admin,
filter_all!(f_eq("name", PartialValue::new_iname("g4"))),
)
};
let rev4b = ReviveRecycledEvent::new_impersonate_entry(
admin,
filter_all!(f_eq("name", PartialValue::new_iname("g4"))),
);
assert!(server_txn.revive_recycled(&rev4b).is_ok());
assert!(!check_entry_has_mo(
&mut server_txn,

View file

@ -78,14 +78,6 @@ pub type ValueSet = Box<dyn ValueSetT + Send + Sync + 'static>;
dyn_clone::clone_trait_object!(ValueSetT);
pub trait ValueSetT: std::fmt::Debug + DynClone {
/// # Safety
/// This is unsafe as you are unable to distinguish the case between
/// the value already existing, OR the value being an incorrect type to add
/// to the set.
unsafe fn insert(&mut self, value: Value) -> bool {
self.insert_checked(value).unwrap_or(false)
}
fn insert_checked(&mut self, value: Value) -> Result<bool, OperationError>;
fn clear(&mut self);
@ -577,9 +569,7 @@ pub fn uuid_to_proto_string(u: Uuid) -> String {
pub fn from_result_value_iter(
mut iter: impl Iterator<Item = Result<Value, OperationError>>,
) -> Result<ValueSet, OperationError> {
let init = if let Some(v) = iter.next() {
v
} else {
let Some(init) = iter.next() else {
admin_error!("Empty value iterator");
return Err(OperationError::InvalidValueState);
};
@ -638,9 +628,7 @@ pub fn from_result_value_iter(
}
pub fn from_value_iter(mut iter: impl Iterator<Item = Value>) -> Result<ValueSet, OperationError> {
let init = if let Some(v) = iter.next() {
v
} else {
let Some(init) = iter.next() else {
admin_error!("Empty value iterator");
return Err(OperationError::InvalidValueState);
};

View file

@ -31,10 +31,7 @@ impl From<UnixUserToken> for UserToken {
valid,
} = value;
let groups = groups
.into_iter()
.map(GroupToken::from)
.collect();
let groups = groups.into_iter().map(GroupToken::from).collect();
UserToken {
name,