use khive_score::DeterministicScore;
use std::hash::Hash;
#[cfg(feature = "policy")]
use khive_gate::GateContext as PolicyContext;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum ClearanceLevel {
#[default]
Public = 0,
Internal = 1,
Confidential = 2,
Secret = 3,
}
impl ClearanceLevel {
#[inline]
pub fn can_access(&self, document_level: ClearanceLevel) -> bool {
*self >= document_level
}
}
#[derive(Debug, Clone)]
pub struct SearchPolicy {
pub caller_clearance: ClearanceLevel,
#[cfg(feature = "policy")]
pub policy_context: Option<PolicyContext>,
}
impl SearchPolicy {
pub fn new(caller_clearance: ClearanceLevel) -> Self {
Self {
caller_clearance,
#[cfg(feature = "policy")]
policy_context: None,
}
}
pub fn public() -> Self {
Self::new(ClearanceLevel::Public)
}
pub fn internal() -> Self {
Self::new(ClearanceLevel::Internal)
}
pub fn confidential() -> Self {
Self::new(ClearanceLevel::Confidential)
}
pub fn secret() -> Self {
Self::new(ClearanceLevel::Secret)
}
#[cfg(feature = "policy")]
pub fn with_context(mut self, context: PolicyContext) -> Self {
self.policy_context = Some(context);
self
}
#[inline]
pub fn can_access(&self, document_clearance: ClearanceLevel) -> bool {
self.caller_clearance.can_access(document_clearance)
}
}
impl Default for SearchPolicy {
fn default() -> Self {
Self::public()
}
}
pub fn filter_by_policy<Id, F>(
results: Vec<(Id, DeterministicScore)>,
policy: &SearchPolicy,
get_clearance: F,
) -> Vec<(Id, DeterministicScore)>
where
Id: Clone,
F: Fn(&Id) -> ClearanceLevel,
{
results
.into_iter()
.filter(|(id, _)| {
let doc_clearance = get_clearance(id);
policy.can_access(doc_clearance)
})
.collect()
}
pub fn filter_by_predicate<Id, F>(
results: Vec<(Id, DeterministicScore)>,
is_accessible: F,
) -> Vec<(Id, DeterministicScore)>
where
Id: Clone,
F: Fn(&Id) -> bool,
{
results
.into_iter()
.filter(|(id, _)| is_accessible(id))
.collect()
}
#[cfg(test)]
#[path = "policy/tests.rs"]
mod tests;