use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
#[cfg(any(test, feature = "test-support"))]
use std::sync::{OnceLock, RwLock};
use regex::Regex;
use super::ResolvedPolicy;
#[cfg(test)]
use super::{parse_file, resolve};
use crate::core::input_filters::{FilterAction, FilterConfig};
mod refresh;
pub const REQUIRED_POLICY_ROOT_ENV: &str = "LEAN_CTX_REQUIRED_POLICY_ROOT";
pub const REQUIRED_POLICY_DIGEST_ENV: &str = "LEAN_CTX_REQUIRED_POLICY_DIGEST";
pub use refresh::{protected_authority_paths, protected_policy_digest};
#[cfg(any(test, feature = "test-support"))]
pub mod held_horizon_support;
#[cfg(test)]
pub(crate) mod held_horizon_tests;
#[cfg(test)]
mod refresh_tests;
tokio::task_local! {
pub static REQUEST_PROJECT: std::cell::RefCell<Option<PathBuf>>;
pub(crate) static SOURCE_VIEW: std::cell::RefCell<Option<SourceView>>;
}
#[derive(Clone)]
pub struct SourceView {
project: PathBuf,
policy: Option<Arc<ActivePolicy>>,
fingerprint: blake3::Hash,
role: crate::core::roles::Role,
role_fingerprint: blake3::Hash,
lifetime: Option<super::org::Lifetime>,
observation: Option<super::org::Observation>,
valid: Arc<AtomicBool>,
live: Arc<AtomicBool>,
}
impl SourceView {
fn within_horizon(&self) -> bool {
let holds = self
.lifetime
.is_none_or(|lifetime| lifetime.check_horizon().is_ok());
if !holds {
self.valid.store(false, Ordering::Release);
}
holds
}
fn invalidate_if_live(&self) {
if self.live.load(Ordering::Acquire) {
self.valid.store(false, Ordering::Release);
}
}
}
struct SourceViewLifetime(Arc<AtomicBool>);
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct StoredPublicationAuthority {
project: PathBuf,
fingerprint: [u8; 32],
role_fingerprint: [u8; 32],
lifetime: Option<StoredLifetime>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct StoredLifetime {
horizon: Option<chrono::DateTime<chrono::Utc>>,
}
#[derive(Debug)]
pub struct PublicationAuthority {
project: PathBuf,
fingerprint: blake3::Hash,
role_fingerprint: blake3::Hash,
lifetime: Option<super::org::Lifetime>,
valid: Arc<AtomicBool>,
}
impl PublicationAuthority {
pub fn capture() -> Result<Self, String> {
let view = current_source_view().ok_or("source authority unavailable")?;
if !view.within_horizon() {
return Err("source authority unavailable".into());
}
Ok(Self {
project: view.project,
fingerprint: view.fingerprint,
role_fingerprint: view.role_fingerprint,
lifetime: view.lifetime,
valid: view.valid,
})
}
pub fn stored(&self) -> Option<StoredPublicationAuthority> {
self.valid
.load(Ordering::Acquire)
.then(|| StoredPublicationAuthority {
project: self.project.clone(),
fingerprint: *self.fingerprint.as_bytes(),
role_fingerprint: *self.role_fingerprint.as_bytes(),
lifetime: self.lifetime.map(|lifetime| StoredLifetime {
horizon: lifetime.horizon(),
}),
})
}
#[must_use]
pub fn restore(stored: StoredPublicationAuthority) -> Self {
Self {
project: stored.project,
fingerprint: blake3::Hash::from_bytes(stored.fingerprint),
role_fingerprint: blake3::Hash::from_bytes(stored.role_fingerprint),
lifetime: stored
.lifetime
.map(|lifetime| super::org::Lifetime::restored(lifetime.horizon)),
valid: Arc::new(AtomicBool::new(true)),
}
}
pub fn verify(&self) -> Result<(), String> {
if !self.valid.load(Ordering::Acquire)
|| REQUEST_PROJECT
.try_with(|slot| {
slot.borrow()
.as_ref()
.is_some_and(|root| root != &self.project)
})
.unwrap_or(false)
{
return Err("source authority changed before publication".into());
}
REQUEST_PROJECT.sync_scope(std::cell::RefCell::new(Some(self.project.clone())), || {
SOURCE_VIEW.sync_scope(std::cell::RefCell::new(None), || {
let latest = refresh::current_verified(self.project.clone())?;
let role = role_fingerprint(&crate::core::roles::active_role())?;
if latest.fingerprint != self.fingerprint || role != self.role_fingerprint {
return Err("source authority changed before publication".into());
}
if let Some(lifetime) = &self.lifetime {
lifetime.check_horizon()?;
}
Ok(())
})
})
}
pub fn fingerprint_bytes(&self) -> [u8; 32] {
*self.fingerprint.as_bytes()
}
#[cfg(any(test, feature = "http-server"))]
pub fn role_fingerprint_bytes(&self) -> [u8; 32] {
*self.role_fingerprint.as_bytes()
}
}
impl Drop for SourceViewLifetime {
fn drop(&mut self) {
self.0.store(false, Ordering::Release);
}
}
fn current_source_view() -> Option<SourceView> {
SOURCE_VIEW
.try_with(|slot| slot.borrow().clone())
.ok()
.flatten()
}
pub fn inherited_source_view() -> Option<SourceView> {
current_source_view()
}
pub fn detached_project_root(fallback: &Path) -> Result<PathBuf, String> {
let request_project = REQUEST_PROJECT
.try_with(|slot| slot.borrow().clone())
.ok()
.flatten();
if let Some(view) = current_source_view() {
if !view.live.load(Ordering::Acquire)
|| !view.valid.load(Ordering::Acquire)
|| request_project.as_ref() != Some(&view.project)
{
view.invalidate_if_live();
return Err("source policy view is no longer active".into());
}
return Ok(view.project);
}
Ok(request_project.unwrap_or_else(|| fallback.to_path_buf()))
}
pub(crate) fn with_inherited_source_view<T>(
view: Option<SourceView>,
operation: impl FnOnce() -> T,
) -> T {
match view {
Some(view) => SOURCE_VIEW.sync_scope(std::cell::RefCell::new(Some(view)), operation),
None => operation(),
}
}
pub(crate) fn pinned_role() -> Option<crate::core::roles::Role> {
current_source_view().map(|view| {
let project = REQUEST_PROJECT
.try_with(|slot| slot.borrow().clone())
.ok()
.flatten();
if !view.live.load(Ordering::Acquire)
|| !view.valid.load(Ordering::Acquire)
|| project.as_ref() != Some(&view.project)
{
view.invalidate_if_live();
crate::core::roles::closed_source_view_role()
} else {
view.role
}
})
}
pub fn in_project<T>(project: impl Into<PathBuf>, operation: impl FnOnce() -> T) -> T {
REQUEST_PROJECT.sync_scope(std::cell::RefCell::new(Some(project.into())), operation)
}
pub fn spawn_for_project<T: Send + 'static>(
project: impl Into<PathBuf>,
operation: impl FnOnce() -> T + Send + 'static,
) -> std::thread::JoinHandle<T> {
let project = project.into();
std::thread::spawn(move || in_project(project, operation))
}
pub fn bind_request_project(project: Option<&str>) {
if current_source_view().is_some() {
return;
}
let _ = REQUEST_PROJECT.try_with(|slot| {
*slot.borrow_mut() = project.map(PathBuf::from);
});
}
fn canonical_project_root(project: &Path) -> Result<PathBuf, String> {
let project = crate::core::pathutil::canonicalize_secure(project)
.map_err(|_| "policy project root unavailable")?;
if !project.is_dir() {
return Err("policy project root unavailable".into());
}
Ok(project)
}
pub(crate) fn request_project_is(root: &Path) -> bool {
match REQUEST_PROJECT.try_with(|slot| slot.borrow().clone()) {
Ok(Some(bound)) => canonical_project_root(&bound).is_ok_and(|bound| bound == root),
_ => true,
}
}
pub fn with_project_source_view<T>(
project_root: &str,
operation: impl FnOnce() -> T,
) -> Result<T, String> {
let project = REQUEST_PROJECT
.try_with(|slot| slot.borrow().clone())
.ok()
.flatten()
.or_else(|| current_source_view().map(|view| view.project))
.unwrap_or_else(|| PathBuf::from(project_root));
let project = canonical_project_root(&project)?;
REQUEST_PROJECT.sync_scope(std::cell::RefCell::new(Some(project)), || {
with_source_view(operation)
})
}
pub fn with_explicit_project_source_view<T>(
project_root: &Path,
operation: impl FnOnce(&PublicationAuthority) -> T,
) -> Result<T, String> {
let project = canonical_project_root(project_root)?;
let bound = REQUEST_PROJECT
.try_with(|slot| slot.borrow().clone())
.ok()
.flatten();
if let Some(bound) = bound {
let bound = crate::core::pathutil::canonicalize_secure(&bound)
.map_err(|_| "request project authority unavailable")?;
if bound != project {
return Err("request project authority does not match egress root".into());
}
}
if let Some(view) = current_source_view()
&& (!view.live.load(Ordering::Acquire)
|| !view.valid.load(Ordering::Acquire)
|| view.project != project)
{
view.invalidate_if_live();
return Err("source policy view does not match egress root".into());
}
REQUEST_PROJECT.sync_scope(std::cell::RefCell::new(Some(project)), || {
with_source_view(|| {
let authority = PublicationAuthority::capture()?;
let result = operation(&authority);
authority.verify()?;
Ok(result)
})?
})
}
pub fn with_source_view<T>(operation: impl FnOnce() -> T) -> Result<T, String> {
with_source_view_when(|_, _| true, operation)?
.ok_or_else(|| "source policy view is no longer active".into())
}
#[cfg(feature = "http-server")]
pub fn with_governed_source_view<T>(operation: impl FnOnce() -> T) -> Result<Option<T>, String> {
with_source_view_when(|policy, observed| policy || observed, operation)
}
fn with_source_view_when<T>(
enter: impl FnOnce(bool, bool) -> bool,
operation: impl FnOnce() -> T,
) -> Result<Option<T>, String> {
if let Some(view) = current_source_view() {
let project = REQUEST_PROJECT
.try_with(|slot| slot.borrow().clone())
.ok()
.flatten()
.ok_or("source policy view is no longer active")?;
let project = canonical_project_root(&project)
.map_err(|_| "source policy view is no longer active")?;
if !view.live.load(Ordering::Acquire)
|| !view.valid.load(Ordering::Acquire)
|| project != view.project
|| !view.within_horizon()
{
view.invalidate_if_live();
return Err("source policy view is no longer active".into());
}
if !enter(view.policy.is_some(), view.observation.is_some()) {
return Ok(None);
}
return REQUEST_PROJECT
.sync_scope(std::cell::RefCell::new(Some(view.project.clone())), || {
Ok(Some(operation()))
});
}
let project = match REQUEST_PROJECT.try_with(|slot| slot.borrow().clone()) {
Ok(project) => project.ok_or("project_unresolved")?,
Err(_) => std::env::current_dir().map_err(|_| "policy project root unavailable")?,
};
let project = canonical_project_root(&project)?;
REQUEST_PROJECT.sync_scope(std::cell::RefCell::new(Some(project.clone())), || {
let verified = refresh::current_verified_settled(&project)?;
let lifetime = verified.lifetime;
let observation = verified.observation;
let role = crate::core::roles::active_role();
let pinned_role_fingerprint = role_fingerprint(&role)?;
let view = SourceView {
project: project.clone(),
policy: source_view_policy(verified.policy),
fingerprint: verified.fingerprint,
role,
role_fingerprint: pinned_role_fingerprint,
lifetime,
observation,
valid: Arc::new(AtomicBool::new(true)),
live: Arc::new(AtomicBool::new(true)),
};
if !view.within_horizon() {
return Err("source policy view is no longer active".into());
}
if !enter(view.policy.is_some(), view.observation.is_some()) {
return Ok(None);
}
let view_lifetime = SourceViewLifetime(view.live.clone());
let value = SOURCE_VIEW.sync_scope(std::cell::RefCell::new(Some(view.clone())), operation);
drop(view_lifetime);
let project_unchanged = REQUEST_PROJECT
.try_with(|slot| slot.borrow().as_ref() == Some(&view.project))
.unwrap_or(false);
let latest_role = crate::core::roles::active_role();
let latest_role_fingerprint = role_fingerprint(&latest_role)?;
let latest = refresh::current_verified_settled(&project)?;
if !project_unchanged
|| latest.fingerprint != view.fingerprint
|| latest_role_fingerprint != view.role_fingerprint
|| !view.valid.load(Ordering::Acquire)
{
return Err("source policy view changed during operation".into());
}
if !view.within_horizon() {
return Err("source policy view changed during operation".into());
}
Ok(Some(value))
})
}
pub(crate) fn role_fingerprint(role: &crate::core::roles::Role) -> Result<blake3::Hash, String> {
serde_json::to_vec(role)
.map(|bytes| blake3::hash(&bytes))
.map_err(|_| "source role view unavailable".into())
}
#[cfg(any(test, feature = "test-support"))]
fn source_view_policy(fresh: Option<Arc<ActivePolicy>>) -> Option<Arc<ActivePolicy>> {
let state = test_override()
.read()
.unwrap_or_else(std::sync::PoisonError::into_inner);
match &*state {
OverrideState::Live => fresh,
OverrideState::Fixed(policy) => policy.clone(),
}
}
#[cfg(not(any(test, feature = "test-support")))]
fn source_view_policy(fresh: Option<Arc<ActivePolicy>>) -> Option<Arc<ActivePolicy>> {
fresh
}
const PROJECT_PACK_PATH: &str = ".lean-ctx/policy.toml";
pub struct ActivePolicy {
pub resolved: ResolvedPolicy,
pub redaction: Vec<(String, Regex)>,
pub(crate) blocked_patterns: Vec<(String, Regex)>,
pub(crate) hive_rules: usize,
pub content_valid: bool,
pub filters: FilterConfig,
pub egress: crate::core::egress::EgressConfig,
horizon: Option<chrono::DateTime<chrono::Utc>>,
expired: AtomicBool,
}
impl ActivePolicy {
#[must_use]
pub fn within_horizon(&self) -> bool {
if self.expired.load(Ordering::Acquire) {
return false;
}
let holds = self
.horizon
.is_none_or(|horizon| chrono::Utc::now() < horizon);
if !holds {
self.expired.store(true, Ordering::Release);
}
holds
}
fn until(mut self, horizon: Option<chrono::DateTime<chrono::Utc>>) -> Self {
self.horizon = horizon;
self
}
pub fn from_resolved(resolved: ResolvedPolicy) -> Self {
Self::from_resolved_with_hive(
resolved,
&crate::core::policy::hive_filters::FilterRules::default(),
)
}
pub(crate) fn from_resolved_with_hive(
mut resolved: ResolvedPolicy,
hive: &crate::core::policy::hive_filters::FilterRules,
) -> Self {
use super::content::{MAX_REDACTION_RULES, MAX_RULE_LABEL_BYTES, MAX_RULE_PATTERN_BYTES};
let hive_rules = hive.redaction.len() + hive.blocked.len();
let hive_bounded = hive_rules <= crate::core::policy::hive_filters::HIVE_MAX_RULES
&& hive
.redaction
.iter()
.chain(&hive.blocked)
.all(|(label, pattern)| {
label.starts_with(super::HIVE_LABEL_PREFIX)
&& label.len() <= MAX_RULE_LABEL_BYTES
&& !label.chars().any(char::is_control)
&& pattern.len() <= MAX_RULE_PATTERN_BYTES
});
let bounded = hive_bounded
&& resolved.redaction.len() + resolved.filters.blocked_patterns.len()
<= MAX_REDACTION_RULES
&& resolved.egress.forbidden_patterns.len() <= MAX_REDACTION_RULES
&& resolved
.egress
.forbidden_patterns
.iter()
.all(|pattern| pattern.len() <= MAX_RULE_PATTERN_BYTES)
&& resolved
.redaction
.iter()
.chain(&resolved.filters.blocked_patterns)
.all(|(label, pattern)| {
!label.is_empty()
&& label.len() <= MAX_RULE_LABEL_BYTES
&& !label.chars().any(char::is_control)
&& pattern.len() <= MAX_RULE_PATTERN_BYTES
});
resolved.redaction.extend(hive.redaction.iter().cloned());
resolved
.filters
.blocked_patterns
.extend(hive.blocked.iter().cloned());
let compiled = bounded.then(|| {
resolved
.redaction
.iter()
.map(|(label, pattern)| {
regex::RegexBuilder::new(pattern)
.size_limit(1024 * 1024)
.dfa_size_limit(1024 * 1024)
.build()
.map(|re| (label.clone(), re))
})
.collect::<Result<Vec<_>, _>>()
});
let content_valid = matches!(&compiled, Some(Ok(_)));
let redaction = compiled.and_then(Result::ok).unwrap_or_default();
let compiled_blocks = bounded.then(|| {
resolved
.filters
.blocked_patterns
.iter()
.map(|(label, pattern)| {
regex::RegexBuilder::new(pattern)
.size_limit(1024 * 1024)
.dfa_size_limit(1024 * 1024)
.build()
.map(|re| (label.clone(), re))
})
.collect::<Result<Vec<_>, _>>()
});
let content_valid = content_valid && matches!(&compiled_blocks, Some(Ok(_)));
let blocked_patterns = compiled_blocks.and_then(Result::ok).unwrap_or_default();
let filters = FilterConfig::new(
filter_action(resolved.filters.pii.as_ref()),
filter_action(resolved.filters.classification.as_ref()),
filter_action(resolved.filters.injection.as_ref()),
&resolved.filters.blocked_labels,
);
let egress = crate::core::egress::EgressConfig::new(
&resolved.egress.forbidden_patterns,
resolved.egress.block_secrets.unwrap_or(false),
resolved.egress.max_writes_per_min,
);
Self {
resolved,
redaction,
blocked_patterns,
hive_rules,
content_valid,
filters,
egress,
horizon: None,
expired: AtomicBool::new(false),
}
}
pub(crate) fn deny_all() -> Self {
let mut active = Self::from_resolved(ResolvedPolicy {
name: "invalid-local-policy".into(),
version: "0.0.0".into(),
description: "deny all because the local policy pack is invalid".into(),
chain: Vec::new(),
default_read_mode: None,
allow_tools: Some(Vec::new()),
deny_tools: Vec::new(),
max_context_tokens: None,
audit_retention_days: None,
redaction: std::collections::BTreeMap::new(),
filters: crate::core::policy::FilterRules::default(),
egress: crate::core::policy::EgressRules::default(),
routing: crate::core::policy::RoutingPolicyRules::default(),
budgets: crate::core::policy::BudgetRules::default(),
});
active.content_valid = false;
active
}
#[must_use]
pub fn tool_allowed(&self, tool: &str) -> bool {
if !self.content_valid || !self.within_horizon() {
return false;
}
if self.resolved.deny_tools.iter().any(|t| t == tool) {
return false;
}
match &self.resolved.allow_tools {
Some(allow) => allow.iter().any(|t| t == tool),
None => true,
}
}
}
fn filter_action(opt: Option<&String>) -> FilterAction {
opt.map(String::as_str)
.and_then(FilterAction::parse)
.unwrap_or(FilterAction::Off)
}
#[cfg(test)]
fn load_from_disk() -> Option<Arc<ActivePolicy>> {
let local = match load_local_pack() {
Ok(local) => local,
Err(msg) => {
tracing::error!(
"policy: failed to load invalid {PROJECT_PACK_PATH} ({msg}); enforcing deny-all"
);
return Some(Arc::new(ActivePolicy::deny_all()));
}
};
apply_org_floor(
local,
crate::core::policy::org::active_resolved_checked(),
None,
&crate::core::policy::hive_filters::FilterRules::default(),
None,
)
}
fn apply_org_floor(
local: Option<ResolvedPolicy>,
org: Result<Option<ResolvedPolicy>, String>,
horizon: Option<chrono::DateTime<chrono::Utc>>,
hive: &crate::core::policy::hive_filters::FilterRules,
hive_floor: Option<&ResolvedPolicy>,
) -> Option<Arc<ActivePolicy>> {
let effective = match org {
Ok(Some(org)) => Some(crate::core::policy::floor::merge_floor(
&org,
local.as_ref(),
)),
Ok(None) => local,
Err(error) => {
tracing::error!("org policy rejected; enforcing deny-all: {error}");
return Some(Arc::new(ActivePolicy::deny_all()));
}
};
let effective = match hive_floor {
Some(floor) => Some(crate::core::policy::hive_floor::apply(
floor,
effective.as_ref(),
)),
None => effective,
};
let effective = match effective {
Some(effective) => effective,
None if hive.redaction.is_empty() && hive.blocked.is_empty() => return None,
None => hive_filters_only(),
};
Some(Arc::new(
ActivePolicy::from_resolved_with_hive(effective, hive).until(horizon),
))
}
fn hive_filters_only() -> ResolvedPolicy {
ResolvedPolicy {
name: "hive-filters".into(),
version: "1.0.0".into(),
description: "content rules of the installed Hive filter packs".into(),
chain: Vec::new(),
default_read_mode: None,
allow_tools: None,
deny_tools: Vec::new(),
max_context_tokens: None,
audit_retention_days: None,
redaction: std::collections::BTreeMap::new(),
filters: crate::core::policy::FilterRules::default(),
egress: crate::core::policy::EgressRules::default(),
routing: crate::core::policy::RoutingPolicyRules::default(),
budgets: crate::core::policy::BudgetRules::default(),
}
}
#[cfg(test)]
fn load_local_pack() -> Result<Option<ResolvedPolicy>, String> {
let path = PathBuf::from(PROJECT_PACK_PATH);
load_local_pack_at(&path)
}
#[cfg(test)]
fn load_local_pack_at(path: &Path) -> Result<Option<ResolvedPolicy>, String> {
match std::fs::symlink_metadata(path) {
Ok(_) => {}
Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(None),
Err(error) => return Err(format!("{}: {error}", path.display())),
}
match parse_file(path).and_then(|p| resolve(&p)) {
Ok(resolved) => Ok(Some(resolved)),
Err(e) => Err(format!("{}: {e}", path.display())),
}
}
pub fn for_project(project_root: &Path) -> Result<Option<Arc<ActivePolicy>>, String> {
refresh::current(project_root.to_path_buf())
}
#[must_use]
pub fn active() -> Option<Arc<ActivePolicy>> {
active_observed().0
}
#[must_use]
pub(crate) fn active_observed() -> (Option<Arc<ActivePolicy>>, Option<super::org::Observation>) {
let deny_all = || (Some(Arc::new(ActivePolicy::deny_all())), None);
if let Some(view) = current_source_view() {
if !view.live.load(Ordering::Acquire) || !view.valid.load(Ordering::Acquire) {
return deny_all();
}
let project = REQUEST_PROJECT
.try_with(|slot| slot.borrow().clone())
.ok()
.flatten();
if project.as_ref() != Some(&view.project) || !view.within_horizon() {
view.invalidate_if_live();
return deny_all();
}
return (view.policy, view.observation);
}
#[cfg(any(test, feature = "test-support"))]
{
let state = test_override()
.read()
.unwrap_or_else(std::sync::PoisonError::into_inner);
if let OverrideState::Fixed(policy) = &*state {
return (policy.clone(), None);
}
}
let scoped = REQUEST_PROJECT
.try_with(|slot| slot.borrow().clone())
.ok()
.flatten();
match scoped
.map_or_else(std::env::current_dir, Ok)
.map_err(|_| "policy project root unavailable".into())
.and_then(refresh::current_verified)
{
Ok(verified) => (verified.policy, verified.observation),
Err(_) => deny_all(),
}
}
#[cfg(any(test, feature = "test-support"))]
pub fn with_observed_view_for_test<T>(
project: &Path,
observation: Option<super::org::Observation>,
operation: impl FnOnce() -> T,
) -> T {
let project = canonical_project_root(project).expect("test project root");
let role = crate::core::roles::active_role();
let verified = refresh::current_verified(project.clone()).expect("test authority");
let view = SourceView {
project: project.clone(),
policy: verified.policy,
fingerprint: verified.fingerprint,
role_fingerprint: role_fingerprint(&role).expect("test role"),
role,
lifetime: None,
observation,
valid: Arc::new(AtomicBool::new(true)),
live: Arc::new(AtomicBool::new(true)),
};
REQUEST_PROJECT.sync_scope(std::cell::RefCell::new(Some(project)), || {
SOURCE_VIEW.sync_scope(std::cell::RefCell::new(Some(view)), operation)
})
}
pub(crate) enum HeldObservation {
NotHeld,
Held(Option<super::org::Observation>),
}
pub(crate) fn held_observation() -> HeldObservation {
let Some(view) = current_source_view() else {
return HeldObservation::NotHeld;
};
let project = REQUEST_PROJECT
.try_with(|slot| slot.borrow().clone())
.ok()
.flatten();
if !view.live.load(Ordering::Acquire)
|| !view.valid.load(Ordering::Acquire)
|| project.as_ref() != Some(&view.project)
|| !view.within_horizon()
{
return HeldObservation::NotHeld;
}
HeldObservation::Held(view.observation)
}
#[must_use]
pub fn is_active() -> bool {
active().is_some()
}
pub fn reload() {
let _ = active();
}
#[cfg(any(test, feature = "test-support"))]
enum OverrideState {
Live,
Fixed(Option<Arc<ActivePolicy>>),
}
#[cfg(any(test, feature = "test-support"))]
fn test_override() -> &'static RwLock<OverrideState> {
static OVERRIDE: OnceLock<RwLock<OverrideState>> = OnceLock::new();
OVERRIDE.get_or_init(|| RwLock::new(OverrideState::Live))
}
#[cfg(any(test, feature = "test-support"))]
fn test_override_lock() -> &'static std::sync::Mutex<()> {
static LOCK: OnceLock<std::sync::Mutex<()>> = OnceLock::new();
LOCK.get_or_init(|| std::sync::Mutex::new(()))
}
#[cfg(any(test, feature = "test-support"))]
pub struct TestOverrideGuard {
_policy: std::sync::MutexGuard<'static, ()>,
_environment: crate::core::data_dir::TestEnvGuard,
}
#[cfg(any(test, feature = "test-support"))]
pub fn lock_test_override() -> TestOverrideGuard {
let environment = crate::core::data_dir::test_env_lock();
let policy = test_override_lock()
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
TestOverrideGuard {
_policy: policy,
_environment: environment,
}
}
#[cfg(any(test, feature = "test-support"))]
pub struct TestPolicyOverride {
previous: OverrideState,
_lock: TestOverrideGuard,
}
#[cfg(any(test, feature = "test-support"))]
impl TestPolicyOverride {
pub fn set(resolved: Option<ResolvedPolicy>) -> Self {
let lock = lock_test_override();
let previous = std::mem::replace(
&mut *test_override()
.write()
.unwrap_or_else(std::sync::PoisonError::into_inner),
OverrideState::Fixed(
resolved.map(|policy| Arc::new(ActivePolicy::from_resolved(policy))),
),
);
Self {
previous,
_lock: lock,
}
}
}
#[cfg(any(test, feature = "test-support"))]
impl Drop for TestPolicyOverride {
fn drop(&mut self) {
*test_override()
.write()
.unwrap_or_else(std::sync::PoisonError::into_inner) =
std::mem::replace(&mut self.previous, OverrideState::Live);
}
}
#[cfg(test)]
#[path = "runtime/tests.rs"]
mod tests;