Reject unknown MCP keys in partial layers

This commit is contained in:
Felix Xia
2026-06-25 20:48:29 +01:00
parent 393c97d898
commit 0b065b0e31
2 changed files with 52 additions and 0 deletions
@@ -493,6 +493,49 @@ enabled = false
Ok(())
}
#[tokio::test]
async fn write_value_rejects_unknown_mcp_field_hidden_by_cloud_config() -> Result<()> {
let tmp = tempdir().expect("tempdir");
let config_path = tmp.path().join(CONFIG_TOML_FILE);
std::fs::write(&config_path, "")?;
let service = ConfigManager::new_for_tests(
tmp.path().to_path_buf(),
vec![],
LoaderOverrides::without_managed_config_for_tests(),
CloudConfigBundleFixture::loader_with_enterprise_config(
r#"[mcp_servers.docs]
command = "cloud-docs-server"
enabled = false
"#,
),
);
let error = service
.write_value(ConfigValueWriteParams {
file_path: Some(config_path.display().to_string()),
key_path: "mcp_servers.docs.typo".to_string(),
value: serde_json::json!(true),
merge_strategy: MergeStrategy::Replace,
expected_version: None,
})
.await
.expect_err("the cloud transport must not hide an unknown user-layer field");
assert_eq!(
error.write_error_code(),
Some(ConfigWriteErrorCode::ConfigValidationError)
);
assert!(
error
.to_string()
.contains("unknown configuration field `mcp_servers.docs.typo`"),
"{error}"
);
assert_eq!(std::fs::read_to_string(config_path)?, "");
Ok(())
}
#[tokio::test]
async fn read_includes_origins_and_layers() {
let tmp = tempdir().expect("tempdir");
+9
View File
@@ -1,7 +1,9 @@
use crate::config_toml::ConfigToml;
use crate::mcp_types::RawMcpServerConfig;
use crate::strict_config::ignored_toml_value_field;
use codex_utils_absolute_path::AbsolutePathBufGuard;
use serde::Deserialize;
use serde::de::Error as _;
use std::collections::HashMap;
use std::path::Path;
use toml::Value as TomlValue;
@@ -17,6 +19,13 @@ impl ParsedConfigTomlLayer {
pub fn parse(raw: TomlValue, base_dir: &Path) -> Result<Self, toml::de::Error> {
let parts = split_config_toml_layer(raw.clone());
let _guard = AbsolutePathBufGuard::new(base_dir);
if let Some(ignored_field) =
ignored_toml_value_field::<ConfigTomlComposableSections>(parts.composable.clone())
{
return Err(toml::de::Error::custom(format!(
"unknown configuration field `{ignored_field}`"
)));
}
let _: ConfigTomlComposableSections = parts.composable.try_into()?;
let self_contained_config = parts.self_contained.try_into()?;