Compare commits

...

8 Commits

4 changed files with 48 additions and 10 deletions

View File

@@ -10,7 +10,8 @@ use tempfile::TempDir;
use tokio::time::Duration;
use tokio::time::timeout;
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
const INIT_TIMEOUT: Duration = Duration::from_secs(30);
const REQUEST_TIMEOUT: Duration = Duration::from_secs(10);
#[tokio::test]
async fn marketplace_add_local_directory_source() -> Result<()> {
@@ -28,7 +29,7 @@ async fn marketplace_add_local_directory_source() -> Result<()> {
)?;
std::fs::write(source.join("plugins/sample/marker.txt"), "local ref")?;
let mut mcp = McpProcess::new(codex_home.path()).await?;
timeout(DEFAULT_TIMEOUT, mcp.initialize()).await??;
timeout(INIT_TIMEOUT, mcp.initialize()).await??;
let request_id = mcp
.send_marketplace_add_request(MarketplaceAddParams {
@@ -39,7 +40,7 @@ async fn marketplace_add_local_directory_source() -> Result<()> {
.await?;
let response: JSONRPCResponse = timeout(
DEFAULT_TIMEOUT,
REQUEST_TIMEOUT,
mcp.read_stream_until_response_message(RequestId::Integer(request_id)),
)
.await??;

View File

@@ -275,9 +275,15 @@ mod tests {
);
let config = fs::read_to_string(codex_home.path().join(codex_config::CONFIG_TOML_FILE))?;
assert!(config.contains("[marketplaces.debug]"));
assert!(config.contains("source_type = \"local\""));
assert!(config.contains(&format!("source = \"{expected_source}\"")));
let config: toml::Value = toml::from_str(&config)?;
assert_eq!(
config["marketplaces"]["debug"]["source_type"].as_str(),
Some("local")
);
assert_eq!(
config["marketplaces"]["debug"]["source"].as_str(),
Some(expected_source.as_str())
);
Ok(())
}

View File

@@ -296,12 +296,23 @@ mod tests {
r#"{"name":"debug","plugins":[]}"#,
)
.unwrap();
// Let TOML serialization escape platform-specific path separators.
let mut marketplace = toml::map::Map::new();
marketplace.insert(
"source_type".to_string(),
toml::Value::String("local".to_string()),
);
marketplace.insert(
"source".to_string(),
toml::Value::String(source_root.display().to_string()),
);
let mut marketplaces = toml::map::Map::new();
marketplaces.insert("debug".to_string(), toml::Value::Table(marketplace));
let mut config = toml::map::Map::new();
config.insert("marketplaces".to_string(), toml::Value::Table(marketplaces));
fs::write(
codex_home.path().join(CONFIG_TOML_FILE),
format!(
"[marketplaces.debug]\nsource_type = \"local\"\nsource = \"{}\"\n",
source_root.display()
),
toml::to_string(&toml::Value::Table(config)).unwrap(),
)
.unwrap();

View File

@@ -124,12 +124,14 @@ fn normalize_git_url(url: &str) -> String {
}
fn looks_like_local_path(source: &str) -> bool {
let path = Path::new(source);
source.starts_with("./")
|| source.starts_with("../")
|| source.starts_with('/')
|| source.starts_with("~/")
|| source == "."
|| source == ".."
|| path.is_absolute()
}
fn resolve_local_source_path(source: &str) -> Result<PathBuf, MarketplaceAddError> {
@@ -146,6 +148,10 @@ fn resolve_local_source_path(source: &str) -> Result<PathBuf, MarketplaceAddErro
.join(path)
};
if !path.exists() && path.is_absolute() {
return Ok(path);
}
path.canonicalize().map_err(|err| {
MarketplaceAddError::InvalidRequest(format!(
"failed to resolve local marketplace source {}: {err}",
@@ -310,6 +316,20 @@ mod tests {
assert!(path.is_absolute());
}
#[cfg(windows)]
#[test]
fn windows_absolute_path_source_parses() {
let source =
parse_marketplace_source(r"C:\temp\marketplace", /*explicit_ref*/ None).unwrap();
assert_eq!(
source,
MarketplaceSource::Local {
path: PathBuf::from(r"C:\temp\marketplace"),
}
);
}
#[test]
fn local_file_source_is_rejected() {
let tempdir = TempDir::new().unwrap();