use std::collections::HashSet;
use std::sync::Mutex;
use std::sync::atomic::{AtomicU64, Ordering};
use super::{AccessAction, AccessResource, DeliberateDecision, GrantReceipt};
use crate::config::types::Decisions;
pub const ADVISED_GRANT: &str = "advised";
const WARNED_BOUND: usize = 256;
static ADVISED_TOTAL: AtomicU64 = AtomicU64::new(0);
#[must_use]
pub fn advised_total() -> u64 {
ADVISED_TOTAL.load(Ordering::Relaxed)
}
#[derive(Debug, Default)]
pub struct Warned {
keys: Mutex<HashSet<(String, String, String)>>,
}
impl Warned {
fn first(&self, kind: &str, id: &str, action: &str) -> bool {
let Ok(mut keys) = self.keys.lock() else {
return false;
};
if keys.len() >= WARNED_BOUND {
return false;
}
keys.insert((kind.to_owned(), id.to_owned(), action.to_owned()))
}
}
#[derive(Debug, Clone, Copy)]
pub struct Act<'a> {
pub holder: &'a str,
pub kind: &'a str,
pub id: &'a str,
pub action: &'a str,
pub lacking: &'a str,
}
#[must_use]
pub fn advised(decisions: Decisions, warned: &Warned, act: Act<'_>) -> Option<GrantReceipt> {
if decisions != Decisions::Advise {
return None;
}
ADVISED_TOTAL.fetch_add(1, Ordering::Relaxed);
crate::metrics::advised();
if warned.first(act.kind, act.id, act.action) {
let Act {
holder,
kind,
id,
action,
lacking,
} = act;
tracing::warn!(
holder,
kind,
id,
action,
lacking,
"advised: {holder} {action} on {kind}:{id}, grant lacking: {lacking}"
);
}
Some(GrantReceipt {
grant: ADVISED_GRANT.to_owned(),
})
}
#[must_use]
pub fn advised_access(
decisions: Decisions,
warned: &Warned,
holder: &str,
resource: &AccessResource,
action: AccessAction,
lacking: &str,
) -> Option<GrantReceipt> {
advised(
decisions,
warned,
Act {
holder,
kind: resource.kind.qualified(),
id: &resource.id,
action: action.name(),
lacking,
},
)
}
#[must_use]
pub fn advised_deliberate(
decisions: Decisions,
warned: &Warned,
holder: &str,
resource: &AccessResource,
action: AccessAction,
lacking: &str,
) -> Option<DeliberateDecision> {
advised_access(decisions, warned, holder, resource, action, lacking)
.map(DeliberateDecision::Outright)
}