diff --git a/src/config/schema.rs b/src/config/schema.rs index 40b4bcb..c096bf0 100644 --- a/src/config/schema.rs +++ b/src/config/schema.rs @@ -3193,170 +3193,4 @@ default_model = "legacy-model" assert_eq!(parsed.allowed_users, vec!["*"]); } - // ══════════════════════════════════════════════════════════ - // AGENT DELEGATION CONFIG TESTS - // ══════════════════════════════════════════════════════════ - - #[test] - fn agents_config_default_empty() { - let c = Config::default(); - assert!(c.agents.is_empty()); - } - - #[test] - fn agents_config_backward_compat_missing_section() { - let minimal = r#" -workspace_dir = "/tmp/ws" -config_path = "/tmp/config.toml" -default_temperature = 0.7 -"#; - let parsed: Config = toml::from_str(minimal).unwrap(); - assert!(parsed.agents.is_empty()); - } - - #[test] - fn agents_config_toml_roundtrip() { - let toml_str = r#" -default_temperature = 0.7 - -[agents.researcher] -provider = "gemini" -model = "gemini-2.0-flash" -system_prompt = "You are a research assistant." -max_depth = 2 - -[agents.coder] -provider = "openrouter" -model = "anthropic/claude-sonnet-4-20250514" -"#; - let parsed: Config = toml::from_str(toml_str).unwrap(); - assert_eq!(parsed.agents.len(), 2); - - let researcher = &parsed.agents["researcher"]; - assert_eq!(researcher.provider, "gemini"); - assert_eq!(researcher.model, "gemini-2.0-flash"); - assert_eq!( - researcher.system_prompt.as_deref(), - Some("You are a research assistant.") - ); - assert_eq!(researcher.max_depth, 2); - assert!(researcher.api_key.is_none()); - assert!(researcher.temperature.is_none()); - - let coder = &parsed.agents["coder"]; - assert_eq!(coder.provider, "openrouter"); - assert_eq!(coder.model, "anthropic/claude-sonnet-4-20250514"); - assert!(coder.system_prompt.is_none()); - assert_eq!(coder.max_depth, 3); // default - } - - #[test] - fn agents_config_with_api_key_and_temperature() { - let toml_str = r#" -[agents.fast] -provider = "groq" -model = "llama-3.3-70b-versatile" -api_key = "gsk-test-key" -temperature = 0.3 -"#; - let parsed: HashMap = toml::from_str::(toml_str) - .unwrap()["agents"] - .clone() - .try_into() - .unwrap(); - let fast = &parsed["fast"]; - assert_eq!(fast.api_key.as_deref(), Some("gsk-test-key")); - assert!((fast.temperature.unwrap() - 0.3).abs() < f64::EPSILON); - } - - #[test] - fn agent_api_key_encrypted_on_save_and_decrypted_on_load() { - let tmp = TempDir::new().unwrap(); - let zeroclaw_dir = tmp.path(); - let config_path = zeroclaw_dir.join("config.toml"); - - // Create a config with a plaintext agent API key - let mut agents = HashMap::new(); - agents.insert( - "test_agent".to_string(), - DelegateAgentConfig { - provider: "openrouter".to_string(), - model: "test-model".to_string(), - system_prompt: None, - api_key: Some("sk-super-secret".to_string()), - temperature: None, - max_depth: 3, - }, - ); - let config = Config { - config_path: config_path.clone(), - workspace_dir: zeroclaw_dir.join("workspace"), - secrets: SecretsConfig { encrypt: true }, - agents, - ..Config::default() - }; - std::fs::create_dir_all(&config.workspace_dir).unwrap(); - config.save().unwrap(); - - // Read the raw TOML and verify the key is encrypted (not plaintext) - let raw = std::fs::read_to_string(&config_path).unwrap(); - assert!( - !raw.contains("sk-super-secret"), - "Plaintext API key should not appear in saved config" - ); - assert!( - raw.contains("enc2:"), - "Encrypted key should use enc2: prefix" - ); - - // Parse and decrypt — simulate load_or_init by reading + decrypting - let store = crate::security::SecretStore::new(zeroclaw_dir, true); - let mut loaded: Config = toml::from_str(&raw).unwrap(); - for agent in loaded.agents.values_mut() { - if let Some(ref encrypted_key) = agent.api_key { - agent.api_key = Some(store.decrypt(encrypted_key).unwrap()); - } - } - assert_eq!( - loaded.agents["test_agent"].api_key.as_deref(), - Some("sk-super-secret"), - "Decrypted key should match original" - ); - } - - #[test] - fn agent_api_key_not_encrypted_when_disabled() { - let tmp = TempDir::new().unwrap(); - let zeroclaw_dir = tmp.path(); - let config_path = zeroclaw_dir.join("config.toml"); - - let mut agents = HashMap::new(); - agents.insert( - "test_agent".to_string(), - DelegateAgentConfig { - provider: "openrouter".to_string(), - model: "test-model".to_string(), - system_prompt: None, - api_key: Some("sk-plaintext-ok".to_string()), - temperature: None, - max_depth: 3, - }, - ); - let config = Config { - config_path: config_path.clone(), - workspace_dir: zeroclaw_dir.join("workspace"), - secrets: SecretsConfig { encrypt: false }, - agents, - ..Config::default() - }; - std::fs::create_dir_all(&config.workspace_dir).unwrap(); - config.save().unwrap(); - - let raw = std::fs::read_to_string(&config_path).unwrap(); - assert!( - raw.contains("sk-plaintext-ok"), - "With encryption disabled, key should remain plaintext" - ); - assert!(!raw.contains("enc2:"), "No encryption prefix when disabled"); - } }