vika_cli/config/
validator.rs1use crate::config::model::Config;
2use crate::error::{ConfigError, Result};
3use std::path::{Path, PathBuf};
4
5pub fn validate_config(config: &Config) -> Result<()> {
6 let root_dir = PathBuf::from(&config.root_dir);
8 if root_dir.is_absolute() && !root_dir.exists() {
9 return Err(ConfigError::Invalid {
10 message: format!("Root directory does not exist: {}", config.root_dir),
11 }
12 .into());
13 }
14
15 let schemas_output = PathBuf::from(&config.schemas.output);
17 if schemas_output.is_absolute() {
18 validate_safe_path(&schemas_output)?;
19 }
20
21 let apis_output = PathBuf::from(&config.apis.output);
23 if apis_output.is_absolute() {
24 validate_safe_path(&apis_output)?;
25 }
26
27 if config.apis.style != "fetch" {
29 return Err(ConfigError::Invalid {
30 message: format!(
31 "Unsupported API style: {}. Only 'fetch' is supported.",
32 config.apis.style
33 ),
34 }
35 .into());
36 }
37
38 Ok(())
39}
40
41fn validate_safe_path(path: &Path) -> Result<()> {
42 let path_str = path.to_string_lossy();
44
45 if path_str.contains("/etc/")
46 || path_str.contains("/usr/")
47 || path_str.contains("/bin/")
48 || path_str.contains("/sbin/")
49 || path_str.contains("/var/")
50 || path_str.contains("/opt/")
51 || path_str == "/"
52 || path_str == "/root"
53 {
54 return Err(ConfigError::InvalidOutputDirectory {
55 path: path_str.to_string(),
56 }
57 .into());
58 }
59
60 Ok(())
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use crate::config::model::Config;
67
68 #[test]
69 fn test_validate_config_valid() {
70 let config = Config::default();
71 assert!(validate_config(&config).is_ok());
72 }
73
74 #[test]
75 fn test_validate_config_invalid_style() {
76 let mut config = Config::default();
77 config.apis.style = "invalid".to_string();
78
79 let result = validate_config(&config);
80 assert!(result.is_err());
81 let error = result.unwrap_err();
82 assert!(error.to_string().contains("Unsupported API style"));
83 }
84
85 #[test]
86 fn test_validate_safe_path_etc() {
87 let path = PathBuf::from("/etc/test");
88 let result = validate_safe_path(&path);
89 assert!(result.is_err());
90 }
91
92 #[test]
93 fn test_validate_safe_path_usr() {
94 let path = PathBuf::from("/usr/test");
95 let result = validate_safe_path(&path);
96 assert!(result.is_err());
97 }
98
99 #[test]
100 fn test_validate_safe_path_bin() {
101 let path = PathBuf::from("/bin/test");
102 let result = validate_safe_path(&path);
103 assert!(result.is_err());
104 }
105
106 #[test]
107 fn test_validate_safe_path_root() {
108 let path = PathBuf::from("/");
109 let result = validate_safe_path(&path);
110 assert!(result.is_err());
111 }
112
113 #[test]
114 fn test_validate_safe_path_valid() {
115 let path = PathBuf::from("/home/user/project");
116 let result = validate_safe_path(&path);
117 assert!(result.is_ok());
118 }
119
120 #[test]
121 fn test_validate_config_absolute_paths() {
122 let mut config = Config::default();
123 config.schemas.output = "/home/user/schemas".to_string();
124 config.apis.output = "/home/user/apis".to_string();
125
126 let result = validate_config(&config);
127 assert!(result.is_ok());
128 }
129
130 #[test]
131 fn test_validate_config_unsafe_schemas_path() {
132 let mut config = Config::default();
133 config.schemas.output = "/etc/schemas".to_string();
134
135 let result = validate_config(&config);
136 assert!(result.is_err());
137 }
138
139 #[test]
140 fn test_validate_config_unsafe_apis_path() {
141 let mut config = Config::default();
142 config.apis.output = "/usr/apis".to_string();
143
144 let result = validate_config(&config);
145 assert!(result.is_err());
146 }
147}