Skip to main content

pidgin_lang/
registry.rs

1use std::collections::BTreeMap;
2use std::path::Path;
3
4use serde::Deserialize;
5
6const MAX_CONFIG_SIZE: u64 = 10_485_760; // 10 MiB
7
8#[derive(Debug, Deserialize)]
9pub struct ActionRegistry {
10    pub safe: Vec<String>,
11    pub controlled: Vec<String>,
12    pub human_gated: Vec<String>,
13}
14
15#[derive(Debug, Deserialize)]
16pub struct WorkflowEntry {
17    pub description: String,
18    pub risk_default: String,
19    pub allowed_modes: Vec<String>,
20    pub required_inputs: Vec<String>,
21    pub expected_outputs: Vec<String>,
22    pub recommended_executor: String,
23    pub fallback_executor: String,
24}
25
26#[derive(Debug, Deserialize)]
27pub struct WorkflowRegistry {
28    pub workflows: BTreeMap<String, WorkflowEntry>,
29}
30
31#[derive(Debug, Deserialize)]
32pub struct HumanRequired {
33    pub actions: Vec<String>,
34    pub risk_levels: Vec<String>,
35}
36
37#[derive(Debug, Deserialize)]
38pub struct BlockIf {
39    pub action_in_do_and_deny: bool,
40    pub private_path_referenced: bool,
41    pub unknown_workflow: bool,
42    pub invalid_mode: bool,
43    pub missing_required_field: bool,
44    pub dangerous_action_without_human: bool,
45}
46
47#[derive(Debug, Deserialize)]
48pub struct SafetyRules {
49    pub default_deny: Vec<String>,
50    pub private_paths: Vec<String>,
51    pub human_required: HumanRequired,
52    pub block_if: BlockIf,
53}
54
55#[derive(Debug, thiserror::Error)]
56pub enum ConfigError {
57    #[error("failed to read config file: {0}")]
58    Io(#[from] std::io::Error),
59
60    #[error("failed to parse YAML: {0}")]
61    Yaml(#[from] serde_yaml::Error),
62}
63
64fn read_yaml_to_string(path: &Path) -> Result<String, ConfigError> {
65    let metadata = std::fs::metadata(path)?;
66    if metadata.len() > MAX_CONFIG_SIZE {
67        return Err(ConfigError::Io(std::io::Error::new(
68            std::io::ErrorKind::InvalidData,
69            format!(
70                "config file {} exceeds maximum size ({} > {})",
71                path.display(),
72                metadata.len(),
73                MAX_CONFIG_SIZE
74            ),
75        )));
76    }
77    Ok(std::fs::read_to_string(path)?)
78}
79
80pub fn load_action_registry(path: &Path) -> Result<ActionRegistry, ConfigError> {
81    let content = read_yaml_to_string(path)?;
82    let registry: ActionRegistry = serde_yaml::from_str(&content)?;
83    Ok(registry)
84}
85
86pub fn load_workflow_registry(path: &Path) -> Result<WorkflowRegistry, ConfigError> {
87    let content = read_yaml_to_string(path)?;
88    let registry: WorkflowRegistry = serde_yaml::from_str(&content)?;
89    Ok(registry)
90}
91
92pub fn load_safety_rules(path: &Path) -> Result<SafetyRules, ConfigError> {
93    let content = read_yaml_to_string(path)?;
94    let rules: SafetyRules = serde_yaml::from_str(&content)?;
95    Ok(rules)
96}