pinakes-core: add plugin pipeline; impl signature verification & dependency resolution
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Ida98135cf868db0f5a46a64b8ac562366a6a6964
This commit is contained in:
parent
8347a714d2
commit
4edda201e6
12 changed files with 2679 additions and 36 deletions
|
|
@ -235,6 +235,54 @@ impl CapabilityEnforcer {
|
|||
.unwrap_or(self.max_cpu_time_limit)
|
||||
.min(self.max_cpu_time_limit)
|
||||
}
|
||||
|
||||
/// Validate that a function call is allowed for a plugin's declared kinds.
|
||||
///
|
||||
/// Defense-in-depth: even though the pipeline filters by kind, this prevents
|
||||
/// bugs from calling wrong functions on plugins. Returns `true` if allowed.
|
||||
#[must_use]
|
||||
pub fn validate_function_call(
|
||||
&self,
|
||||
plugin_kinds: &[String],
|
||||
function_name: &str,
|
||||
) -> bool {
|
||||
match function_name {
|
||||
// Lifecycle functions are always allowed
|
||||
"initialize" | "shutdown" | "health_check" => true,
|
||||
// MediaTypeProvider
|
||||
"supported_media_types" | "can_handle" => {
|
||||
plugin_kinds.iter().any(|k| k == "media_type")
|
||||
},
|
||||
// supported_types is shared by metadata_extractor and thumbnail_generator
|
||||
"supported_types" => {
|
||||
plugin_kinds
|
||||
.iter()
|
||||
.any(|k| k == "metadata_extractor" || k == "thumbnail_generator")
|
||||
},
|
||||
// MetadataExtractor
|
||||
"extract_metadata" => {
|
||||
plugin_kinds.iter().any(|k| k == "metadata_extractor")
|
||||
},
|
||||
// ThumbnailGenerator
|
||||
"generate_thumbnail" => {
|
||||
plugin_kinds.iter().any(|k| k == "thumbnail_generator")
|
||||
},
|
||||
// SearchBackend
|
||||
"search" | "index_item" | "remove_item" | "get_stats" => {
|
||||
plugin_kinds.iter().any(|k| k == "search_backend")
|
||||
},
|
||||
// EventHandler
|
||||
"interested_events" | "handle_event" => {
|
||||
plugin_kinds.iter().any(|k| k == "event_handler")
|
||||
},
|
||||
// ThemeProvider
|
||||
"get_themes" | "load_theme" => {
|
||||
plugin_kinds.iter().any(|k| k == "theme_provider")
|
||||
},
|
||||
// Unknown function names are not allowed
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CapabilityEnforcer {
|
||||
|
|
@ -356,20 +404,70 @@ mod tests {
|
|||
|
||||
let mut caps = Capabilities::default();
|
||||
|
||||
// No limits specified - use defaults
|
||||
// No limits specified, use the defaults
|
||||
assert_eq!(enforcer.get_memory_limit(&caps), 100 * 1024 * 1024);
|
||||
assert_eq!(enforcer.get_cpu_time_limit(&caps), 30_000);
|
||||
|
||||
// Plugin requests lower limits - use plugin's
|
||||
// Plugin requests lower limits, use plugin's
|
||||
caps.max_memory_bytes = Some(50 * 1024 * 1024);
|
||||
caps.max_cpu_time_ms = Some(10_000);
|
||||
assert_eq!(enforcer.get_memory_limit(&caps), 50 * 1024 * 1024);
|
||||
assert_eq!(enforcer.get_cpu_time_limit(&caps), 10_000);
|
||||
|
||||
// Plugin requests higher limits - cap at system max
|
||||
// Plugin requests higher limits, cap at system max
|
||||
caps.max_memory_bytes = Some(200 * 1024 * 1024);
|
||||
caps.max_cpu_time_ms = Some(60_000);
|
||||
assert_eq!(enforcer.get_memory_limit(&caps), 100 * 1024 * 1024);
|
||||
assert_eq!(enforcer.get_cpu_time_limit(&caps), 30_000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_function_call_lifecycle_always_allowed() {
|
||||
let enforcer = CapabilityEnforcer::new();
|
||||
let kinds = vec!["metadata_extractor".to_string()];
|
||||
assert!(enforcer.validate_function_call(&kinds, "initialize"));
|
||||
assert!(enforcer.validate_function_call(&kinds, "shutdown"));
|
||||
assert!(enforcer.validate_function_call(&kinds, "health_check"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_function_call_metadata_extractor() {
|
||||
let enforcer = CapabilityEnforcer::new();
|
||||
let kinds = vec!["metadata_extractor".to_string()];
|
||||
assert!(enforcer.validate_function_call(&kinds, "extract_metadata"));
|
||||
assert!(enforcer.validate_function_call(&kinds, "supported_types"));
|
||||
assert!(!enforcer.validate_function_call(&kinds, "search"));
|
||||
assert!(!enforcer.validate_function_call(&kinds, "generate_thumbnail"));
|
||||
assert!(!enforcer.validate_function_call(&kinds, "can_handle"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_function_call_multi_kind() {
|
||||
let enforcer = CapabilityEnforcer::new();
|
||||
let kinds =
|
||||
vec!["media_type".to_string(), "metadata_extractor".to_string()];
|
||||
assert!(enforcer.validate_function_call(&kinds, "can_handle"));
|
||||
assert!(enforcer.validate_function_call(&kinds, "supported_media_types"));
|
||||
assert!(enforcer.validate_function_call(&kinds, "extract_metadata"));
|
||||
assert!(!enforcer.validate_function_call(&kinds, "search"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_function_call_unknown_function() {
|
||||
let enforcer = CapabilityEnforcer::new();
|
||||
let kinds = vec!["metadata_extractor".to_string()];
|
||||
assert!(!enforcer.validate_function_call(&kinds, "unknown_func"));
|
||||
assert!(!enforcer.validate_function_call(&kinds, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_function_call_shared_supported_types() {
|
||||
let enforcer = CapabilityEnforcer::new();
|
||||
let extractor = vec!["metadata_extractor".to_string()];
|
||||
let generator = vec!["thumbnail_generator".to_string()];
|
||||
let search = vec!["search_backend".to_string()];
|
||||
assert!(enforcer.validate_function_call(&extractor, "supported_types"));
|
||||
assert!(enforcer.validate_function_call(&generator, "supported_types"));
|
||||
assert!(!enforcer.validate_function_call(&search, "supported_types"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue