1use std::collections::BTreeMap;
2use std::path::Path;
3
4use serde::Deserialize;
5
6const MAX_CONFIG_SIZE: u64 = 10_485_760; #[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 SafetyRules {
39 pub private_paths: Vec<String>,
40 pub human_required: HumanRequired,
41}
42
43#[derive(Debug, thiserror::Error)]
44pub enum ConfigError {
45 #[error("failed to read config file: {0}")]
46 Io(#[from] std::io::Error),
47
48 #[error("failed to parse YAML: {0}")]
49 Yaml(#[from] serde_yaml::Error),
50}
51
52fn read_yaml_to_string(path: &Path) -> Result<String, ConfigError> {
53 let metadata = std::fs::metadata(path)?;
54 if metadata.len() > MAX_CONFIG_SIZE {
55 return Err(ConfigError::Io(std::io::Error::new(
56 std::io::ErrorKind::InvalidData,
57 format!(
58 "config file {} exceeds maximum size ({} > {})",
59 path.display(),
60 metadata.len(),
61 MAX_CONFIG_SIZE
62 ),
63 )));
64 }
65 Ok(std::fs::read_to_string(path)?)
66}
67
68pub fn load_action_registry(path: &Path) -> Result<ActionRegistry, ConfigError> {
69 let content = read_yaml_to_string(path)?;
70 let registry: ActionRegistry = serde_yaml::from_str(&content)?;
71 Ok(registry)
72}
73
74pub fn load_workflow_registry(path: &Path) -> Result<WorkflowRegistry, ConfigError> {
75 let content = read_yaml_to_string(path)?;
76 let registry: WorkflowRegistry = serde_yaml::from_str(&content)?;
77 Ok(registry)
78}
79
80pub fn load_safety_rules(path: &Path) -> Result<SafetyRules, ConfigError> {
81 let content = read_yaml_to_string(path)?;
82 let rules: SafetyRules = serde_yaml::from_str(&content)?;
83 Ok(rules)
84}