pinakes-core: update remaining modules and tests

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I9e0ff5ea33a5cf697473423e88f167ce6a6a6964
This commit is contained in:
raf 2026-03-08 00:42:29 +03:00
commit 3d9f8933d2
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
44 changed files with 1207 additions and 578 deletions

View file

@ -25,7 +25,8 @@ pub struct CapabilityEnforcer {
impl CapabilityEnforcer {
/// Create a new capability enforcer with default limits
pub fn new() -> Self {
#[must_use]
pub const fn new() -> Self {
Self {
max_memory_limit: 512 * 1024 * 1024, // 512 MB
max_cpu_time_limit: 60 * 1000, // 60 seconds
@ -36,36 +37,47 @@ impl CapabilityEnforcer {
}
/// Set maximum memory limit
pub fn with_max_memory(mut self, bytes: usize) -> Self {
#[must_use]
pub const fn with_max_memory(mut self, bytes: usize) -> Self {
self.max_memory_limit = bytes;
self
}
/// Set maximum CPU time limit
pub fn with_max_cpu_time(mut self, milliseconds: u64) -> Self {
#[must_use]
pub const fn with_max_cpu_time(mut self, milliseconds: u64) -> Self {
self.max_cpu_time_limit = milliseconds;
self
}
/// Add allowed read path
#[must_use]
pub fn allow_read_path(mut self, path: PathBuf) -> Self {
self.allowed_read_paths.push(path);
self
}
/// Add allowed write path
#[must_use]
pub fn allow_write_path(mut self, path: PathBuf) -> Self {
self.allowed_write_paths.push(path);
self
}
/// Set default network access policy
pub fn with_network_default(mut self, allow: bool) -> Self {
#[must_use]
pub const fn with_network_default(mut self, allow: bool) -> Self {
self.allow_network_default = allow;
self
}
/// Validate capabilities requested by a plugin
///
/// # Errors
///
/// Returns an error if the plugin requests capabilities that exceed the
/// configured system limits, such as memory, CPU time, filesystem paths, or
/// network access.
pub fn validate_capabilities(
&self,
capabilities: &Capabilities,
@ -115,8 +127,8 @@ impl CapabilityEnforcer {
for path in &capabilities.filesystem.read {
if !self.is_read_allowed(path) {
return Err(anyhow!(
"Plugin requests read access to {:?} which is not in allowed paths",
path
"Plugin requests read access to {} which is not in allowed paths",
path.display()
));
}
}
@ -125,8 +137,8 @@ impl CapabilityEnforcer {
for path in &capabilities.filesystem.write {
if !self.is_write_allowed(path) {
return Err(anyhow!(
"Plugin requests write access to {:?} which is not in allowed paths",
path
"Plugin requests write access to {} which is not in allowed paths",
path.display()
));
}
}
@ -135,6 +147,7 @@ impl CapabilityEnforcer {
}
/// Check if a path is allowed for reading
#[must_use]
pub fn is_read_allowed(&self, path: &Path) -> bool {
if self.allowed_read_paths.is_empty() {
return false; // deny-all when unconfigured
@ -150,6 +163,7 @@ impl CapabilityEnforcer {
}
/// Check if a path is allowed for writing
#[must_use]
pub fn is_write_allowed(&self, path: &Path) -> bool {
if self.allowed_write_paths.is_empty() {
return false; // deny-all when unconfigured
@ -173,11 +187,13 @@ impl CapabilityEnforcer {
}
/// Check if network access is allowed for a plugin
pub fn is_network_allowed(&self, capabilities: &Capabilities) -> bool {
#[must_use]
pub const fn is_network_allowed(&self, capabilities: &Capabilities) -> bool {
capabilities.network.enabled && self.allow_network_default
}
/// Check if a specific domain is allowed
#[must_use]
pub fn is_domain_allowed(
&self,
capabilities: &Capabilities,
@ -197,11 +213,13 @@ impl CapabilityEnforcer {
.network
.allowed_domains
.as_ref()
.map(|domains| domains.iter().any(|d| d.eq_ignore_ascii_case(domain)))
.unwrap_or(false)
.is_some_and(|domains| {
domains.iter().any(|d| d.eq_ignore_ascii_case(domain))
})
}
/// Get effective memory limit for a plugin
#[must_use]
pub fn get_memory_limit(&self, capabilities: &Capabilities) -> usize {
capabilities
.max_memory_bytes
@ -210,6 +228,7 @@ impl CapabilityEnforcer {
}
/// Get effective CPU time limit for a plugin
#[must_use]
pub fn get_cpu_time_limit(&self, capabilities: &Capabilities) -> u64 {
capabilities
.max_cpu_time_ms
@ -264,8 +283,7 @@ mod tests {
let test_file = allowed_dir.join("test.txt");
std::fs::write(&test_file, "test").unwrap();
let enforcer =
CapabilityEnforcer::new().allow_read_path(allowed_dir.clone());
let enforcer = CapabilityEnforcer::new().allow_read_path(allowed_dir);
assert!(enforcer.is_read_allowed(&test_file));
assert!(!enforcer.is_read_allowed(Path::new("/etc/passwd")));