use crate::domain::FeatureProfile;
use crate::domain::ir::FeatureSet;
use crate::domain::registry::auth::{AuthContext, ScopeSet};
use crate::domain::registry::primitive::PrimitiveMeta;
#[must_use]
pub const fn is_visible(
session: &AuthContext,
profile: &FeatureProfile,
meta: &PrimitiveMeta,
) -> bool {
let has_features = meta.required_features().is_subset_of(profile.as_set());
has_features && session.holds(meta.required_scopes())
}
#[must_use]
pub const fn missing_scopes(session: &AuthContext, meta: &PrimitiveMeta) -> ScopeSet {
meta.required_scopes().difference(session.scopes())
}
#[must_use]
pub const fn missing_features(profile: &FeatureProfile, meta: &PrimitiveMeta) -> FeatureSet {
meta.required_features().difference(profile.as_set())
}
#[cfg(test)]
mod tests {
use crate::domain::Feature;
use crate::domain::FeatureProfile;
use crate::domain::ir::FeatureSet;
use crate::domain::registry::auth::{AuthContext, Scope, ScopeSet};
use crate::domain::registry::primitive::{PrimitiveKind, PrimitiveMeta};
use crate::domain::registry::visibility::{is_visible, missing_features, missing_scopes};
#[test]
fn a_tool_needing_tasks_is_hidden_without_it() {
let meta = PrimitiveMeta::new(PrimitiveKind::Tool)
.requires(FeatureSet::empty().with(Feature::Tasks));
let session = AuthContext::unrestricted("alice");
assert!(!is_visible(&session, &FeatureProfile::empty(), &meta));
assert!(is_visible(
&session,
&FeatureProfile::empty().with(Feature::Tasks),
&meta
));
}
#[test]
fn the_default_context_and_profile_deny() {
let meta = PrimitiveMeta::new(PrimitiveKind::Tool)
.requires(FeatureSet::empty().with(Feature::Tools))
.scopes(ScopeSet::empty().with(Scope::Write));
assert!(!is_visible(
&AuthContext::default(),
&FeatureProfile::empty(),
&meta
));
}
#[test]
fn a_primitive_requiring_nothing_is_visible() {
let meta = PrimitiveMeta::new(PrimitiveKind::Prompt);
assert!(is_visible(
&AuthContext::default(),
&FeatureProfile::empty(),
&meta
));
}
#[test]
fn the_two_halves_are_independent() {
let meta = PrimitiveMeta::new(PrimitiveKind::Tool)
.requires(FeatureSet::empty().with(Feature::Tasks))
.scopes(ScopeSet::empty().with(Scope::Admin));
let features_only = AuthContext::unrestricted("a");
let scopes_only = AuthContext::new(
"b",
ScopeSet::empty()
.with(Scope::Read)
.with(Scope::Write)
.with(Scope::Admin),
);
assert!(!is_visible(&features_only, &FeatureProfile::empty(), &meta));
assert!(!is_visible(&scopes_only, &FeatureProfile::empty(), &meta));
assert!(is_visible(
&scopes_only,
&FeatureProfile::empty().with(Feature::Tasks),
&meta
));
}
#[test]
fn the_diagnostics_name_what_is_missing() {
let meta = PrimitiveMeta::new(PrimitiveKind::Tool)
.requires(
FeatureSet::empty()
.with(Feature::Tasks)
.with(Feature::Elicitation),
)
.scopes(ScopeSet::empty().with(Scope::Write).with(Scope::Admin));
let session = AuthContext::new("a", ScopeSet::empty().with(Scope::Read));
let scopes = missing_scopes(&session, &meta);
assert!(scopes.contains(Scope::Write));
assert!(scopes.contains(Scope::Admin));
assert!(!scopes.contains(Scope::Read));
let profile = FeatureProfile::empty().with(Feature::Tools);
let features = missing_features(&profile, &meta);
assert!(features.contains(Feature::Tasks));
assert!(features.contains(Feature::Elicitation));
assert!(!features.contains(Feature::Tools));
let full = FeatureProfile::empty()
.with(Feature::Tasks)
.with(Feature::Elicitation);
assert!(missing_features(&full, &meta).is_empty());
assert!(
missing_scopes(&AuthContext::unrestricted("a"), &meta).is_empty(),
"an unrestricted principal is missing nothing"
);
}
}