Skip to content

fidius-host::host Rust

PluginHost builder and plugin discovery.

Structs

fidius-host::host::PluginHost

pub

Host for loading and managing plugins.

Fields

Name Type Description
search_paths Vec < PathBuf >
load_policy LoadPolicy
require_signature bool
trusted_keys Vec < VerifyingKey >
expected_hash Option < u64 >
expected_strategy Option < BufferStrategyKind >

Methods

builder pub
fn builder () -> PluginHostBuilder

Create a new builder.

Source
    pub fn builder() -> PluginHostBuilder {
        PluginHostBuilder::new()
    }
discover pub
fn discover (& self) -> Result < Vec < PluginInfo > , LoadError >

Discover all valid plugins in the configured search paths.

Scans directories for dylib files, loads each, validates, and returns metadata for all valid plugins found.

Source
    pub fn discover(&self) -> Result<Vec<PluginInfo>, LoadError> {
        #[cfg(feature = "tracing")]
        tracing::info!(search_paths = ?self.search_paths, "discovering plugins");

        let mut plugins = Vec::new();

        for search_path in &self.search_paths {
            if !search_path.is_dir() {
                continue;
            }

            let entries = std::fs::read_dir(search_path)?;
            for entry in entries {
                let entry = entry?;
                let path = entry.path();

                if !is_dylib(&path) {
                    continue;
                }

                // Verify signature before dlopen to prevent code execution from untrusted dylibs
                if self.require_signature
                    && signing::verify_signature(&path, &self.trusted_keys).is_err()
                {
                    continue;
                }

                match loader::load_library(&path) {
                    Ok(loaded) => {
                        for plugin in &loaded.plugins {
                            if let Ok(()) = loader::validate_against_interface(
                                plugin,
                                self.expected_hash,
                                self.expected_strategy,
                            ) {
                                plugins.push(plugin.info.clone());
                            }
                        }
                    }
                    Err(_) => {
                        // Skip invalid dylibs during discovery
                        continue;
                    }
                }
            }
        }

        Ok(plugins)
    }
load pub
fn load (& self , name : & str) -> Result < LoadedPlugin , LoadError >

Load a specific plugin by name.

Searches all configured paths for a dylib containing a plugin with the given name. Returns the loaded plugin ready for calling.

Source
    pub fn load(&self, name: &str) -> Result<LoadedPlugin, LoadError> {
        #[cfg(feature = "tracing")]
        tracing::info!(plugin_name = name, "loading plugin");

        for search_path in &self.search_paths {
            if !search_path.is_dir() {
                continue;
            }

            let entries = std::fs::read_dir(search_path)?;
            for entry in entries {
                let entry = entry?;
                let path = entry.path();

                if !is_dylib(&path) {
                    continue;
                }

                // Verify signature if required — always enforced regardless of LoadPolicy
                if self.require_signature {
                    signing::verify_signature(&path, &self.trusted_keys)?;
                }

                match loader::load_library(&path) {
                    Ok(loaded) => {
                        for plugin in loaded.plugins {
                            if plugin.info.name == name {
                                loader::validate_against_interface(
                                    &plugin,
                                    self.expected_hash,
                                    self.expected_strategy,
                                )?;
                                return Ok(plugin);
                            }
                        }
                    }
                    Err(_) => continue,
                }
            }
        }

        Err(LoadError::PluginNotFound {
            name: name.to_string(),
        })
    }

fidius-host::host::PluginHostBuilder

pub

Builder for configuring a PluginHost.

Fields

Name Type Description
search_paths Vec < PathBuf >
load_policy LoadPolicy
require_signature bool
trusted_keys Vec < VerifyingKey >
expected_hash Option < u64 >
expected_strategy Option < BufferStrategyKind >

Methods

new private
fn new () -> Self
Source
    fn new() -> Self {
        Self {
            search_paths: Vec::new(),
            load_policy: LoadPolicy::Strict,
            require_signature: false,
            trusted_keys: Vec::new(),
            expected_hash: None,
            expected_strategy: None,
        }
    }
search_path pub
fn search_path (mut self , path : impl Into < PathBuf >) -> Self

Add a directory to search for plugin dylibs.

Source
    pub fn search_path(mut self, path: impl Into<PathBuf>) -> Self {
        self.search_paths.push(path.into());
        self
    }
load_policy pub
fn load_policy (mut self , policy : LoadPolicy) -> Self

Set the load policy (Strict or Lenient).

Source
    pub fn load_policy(mut self, policy: LoadPolicy) -> Self {
        self.load_policy = policy;
        self
    }
require_signature pub
fn require_signature (mut self , require : bool) -> Self

Require plugins to have valid signatures.

Source
    pub fn require_signature(mut self, require: bool) -> Self {
        self.require_signature = require;
        self
    }
trusted_keys pub
fn trusted_keys (mut self , keys : & [VerifyingKey]) -> Self

Set trusted Ed25519 public keys for signature verification.

Source
    pub fn trusted_keys(mut self, keys: &[VerifyingKey]) -> Self {
        self.trusted_keys = keys.to_vec();
        self
    }
interface_hash pub
fn interface_hash (mut self , hash : u64) -> Self

Set the expected interface hash for validation.

Source
    pub fn interface_hash(mut self, hash: u64) -> Self {
        self.expected_hash = Some(hash);
        self
    }
buffer_strategy pub
fn buffer_strategy (mut self , strategy : BufferStrategyKind) -> Self

Set the expected buffer strategy for validation.

Source
    pub fn buffer_strategy(mut self, strategy: BufferStrategyKind) -> Self {
        self.expected_strategy = Some(strategy);
        self
    }
build pub
fn build (self) -> Result < PluginHost , LoadError >

Build the PluginHost.

Source
    pub fn build(self) -> Result<PluginHost, LoadError> {
        Ok(PluginHost {
            search_paths: self.search_paths,
            load_policy: self.load_policy,
            require_signature: self.require_signature,
            trusted_keys: self.trusted_keys,
            expected_hash: self.expected_hash,
            expected_strategy: self.expected_strategy,
        })
    }

Functions

fidius-host::host::is_dylib

private

fn is_dylib (path : & Path) -> bool

Check if a path has a platform-appropriate dylib extension.

Source
fn is_dylib(path: &Path) -> bool {
    let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
    if cfg!(target_os = "macos") {
        ext == "dylib"
    } else if cfg!(target_os = "windows") {
        ext == "dll"
    } else {
        ext == "so"
    }
}