Skip to main content

specfold_core/
plugins.rs

1//! Plugins: external programs that add rules, importers, exporters, audits and event handlers
2//! over a JSON protocol. Only programs named in spec.toml ever run.
3
4pub mod payload;
5pub mod process;
6pub mod protocol;
7pub mod registry;
8pub mod rules;
9
10pub use protocol::{Description, PROTOCOL};
11pub use registry::{Loaded, load};
12
13#[cfg(all(test, unix))]
14mod tests {
15    use super::*;
16    use crate::config::{Config, PluginDef, RawConfig};
17
18    #[test]
19    fn describes_and_times_out() {
20        let tmp = tempfile::tempdir().unwrap();
21        let r = tmp.path();
22        let script = r.join("plugin.sh");
23        std::fs::write(&script, "#!/bin/sh\nread req\ncase \"$req\" in\n*describe*) echo '{\"protocol\":\"specfold.plugin.v1\",\"name\":\"demo\",\"provides\":{\"rules\":[{\"id\":\"r1\",\"title\":\"t\"}]}}';;\n*) sleep 5;;\nesac\n").unwrap();
24        let raw = RawConfig {
25            plugins: vec![PluginDef {
26                name: "demo".into(),
27                cmd: vec!["sh".into(), script.to_string_lossy().into_owned()],
28                timeout_ms: 300,
29            }],
30            ..Default::default()
31        };
32        let cfg = Config::from_raw(r.to_path_buf(), raw, false);
33        let loaded = load(&cfg);
34        let d = loaded[0].description.as_ref().unwrap();
35        assert_eq!(d.provides.rules[0].id, "r1");
36        let slow: anyhow::Result<serde_json::Value> =
37            process::call(&cfg, &cfg.raw.plugins[0], "rule.run", serde_json::Value::Null);
38        assert!(slow.unwrap_err().to_string().contains("did not answer"));
39    }
40}