diff --git a/codex-rs/Cargo.toml b/codex-rs/Cargo.toml index c425468870..412f7f0620 100644 --- a/codex-rs/Cargo.toml +++ b/codex-rs/Cargo.toml @@ -151,9 +151,6 @@ assert_matches = "1.5.0" async-channel = "2.3.1" async-stream = "0.3.6" async-trait = "0.1.89" -aws-config = "1" -aws-sdk-s3 = "1" -aws-smithy-types = "1" axum = { version = "0.8", default-features = false } azure_core = "0.21" azure_identity = "0.21" diff --git a/codex-rs/core/src/session_share.rs b/codex-rs/core/src/session_share.rs index 29ff795f4d..b8b0f83035 100644 --- a/codex-rs/core/src/session_share.rs +++ b/codex-rs/core/src/session_share.rs @@ -3,12 +3,6 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::Context; -use aws_config::BehaviorVersion; -use aws_config::meta::region::RegionProviderChain; -use aws_sdk_s3::Client as S3Client; -use aws_sdk_s3::error::SdkError; -use aws_sdk_s3::primitives::ByteStream; -use aws_smithy_types::error::metadata::ProvideErrorMetadata; use azure_core::auth::TokenCredential; use azure_identity::AzureCliCredential; use codex_protocol::ThreadId; @@ -34,7 +28,6 @@ pub struct SessionShareResult { #[derive(Debug, Clone)] enum SessionObjectStore { Http(HttpObjectStore), - S3(S3ObjectStore), Azure(AzureObjectStore), } @@ -44,13 +37,6 @@ struct HttpObjectStore { client: reqwest::Client, } -#[derive(Debug, Clone)] -struct S3ObjectStore { - client: S3Client, - bucket: String, - prefix: String, -} - #[derive(Debug, Clone)] struct AzureObjectStore { endpoint: Url, @@ -73,7 +59,6 @@ impl SessionObjectStore { let mut url = Url::parse(base_url) .with_context(|| format!("invalid session_object_storage_url: {base_url}"))?; match url.scheme() { - "s3" => Ok(SessionObjectStore::S3(S3ObjectStore::new(&url).await?)), "az" => Ok(SessionObjectStore::Azure(AzureObjectStore::new_from_az( &url, )?)), @@ -97,7 +82,6 @@ impl SessionObjectStore { fn object_url(&self, key: &str) -> anyhow::Result { match self { SessionObjectStore::Http(store) => store.object_url(key), - SessionObjectStore::S3(store) => store.object_url(key), SessionObjectStore::Azure(store) => store.object_url(key), } } @@ -105,7 +89,6 @@ impl SessionObjectStore { async fn object_exists(&self, key: &str) -> anyhow::Result { match self { SessionObjectStore::Http(store) => store.object_exists(key).await, - SessionObjectStore::S3(store) => store.object_exists(key).await, SessionObjectStore::Azure(store) => store.object_exists(key).await, } } @@ -113,7 +96,6 @@ impl SessionObjectStore { async fn put_object(&self, key: &str, data: Vec, content_type: &str) -> anyhow::Result<()> { match self { SessionObjectStore::Http(store) => store.put_object(key, data, content_type).await, - SessionObjectStore::S3(store) => store.put_object(key, data, content_type).await, SessionObjectStore::Azure(store) => store.put_object(key, data, content_type).await, } } @@ -121,7 +103,6 @@ impl SessionObjectStore { async fn get_object_bytes(&self, key: &str) -> anyhow::Result>> { match self { SessionObjectStore::Http(store) => store.get_object_bytes(key).await, - SessionObjectStore::S3(store) => store.get_object_bytes(key).await, SessionObjectStore::Azure(store) => store.get_object_bytes(key).await, } } @@ -338,113 +319,6 @@ impl HttpObjectStore { } } -impl S3ObjectStore { - async fn new(url: &Url) -> anyhow::Result { - let bucket = url - .host_str() - .ok_or_else(|| anyhow::anyhow!("s3 url missing bucket"))? - .to_string(); - let prefix = url - .path() - .trim_start_matches('/') - .trim_end_matches('/') - .to_string(); - let region_provider = RegionProviderChain::default_provider(); - let shared_config = aws_config::defaults(BehaviorVersion::latest()) - .region(region_provider) - .load() - .await; - if shared_config.region().is_none() { - return Err(anyhow::anyhow!( - "AWS region not set. Set AWS_REGION or configure a default region." - )); - } - let client = S3Client::new(&shared_config); - Ok(Self { - client, - bucket, - prefix, - }) - } - - fn object_url(&self, key: &str) -> anyhow::Result { - let full_key = join_prefix(&self.prefix, key); - Url::parse(&format!("s3://{}/{}", self.bucket, full_key)) - .with_context(|| format!("failed to build s3 url for key {full_key}")) - } - - async fn object_exists(&self, key: &str) -> anyhow::Result { - let full_key = join_prefix(&self.prefix, key); - let response = self - .client - .head_object() - .bucket(&self.bucket) - .key(&full_key) - .send() - .await; - match response { - Ok(_) => Ok(true), - Err(err) => match err { - SdkError::ServiceError(service) => { - let code = service.err().code(); - if matches!(code, Some("NotFound") | Some("NoSuchKey")) { - Ok(false) - } else { - Err(anyhow::anyhow!( - "object store HEAD failed with status {code:?}" - )) - } - } - other => Err(anyhow::anyhow!("object store HEAD failed: {other}")), - }, - } - } - - async fn put_object(&self, key: &str, data: Vec, content_type: &str) -> anyhow::Result<()> { - let full_key = join_prefix(&self.prefix, key); - self.client - .put_object() - .bucket(&self.bucket) - .key(&full_key) - .content_type(content_type) - .body(ByteStream::from(data)) - .send() - .await - .with_context(|| format!("failed to upload s3://{}/{}", self.bucket, full_key))?; - Ok(()) - } - - async fn get_object_bytes(&self, key: &str) -> anyhow::Result>> { - let full_key = join_prefix(&self.prefix, key); - let response = self - .client - .get_object() - .bucket(&self.bucket) - .key(&full_key) - .send() - .await; - match response { - Ok(output) => { - let bytes = output.body.collect().await?; - Ok(Some(bytes.into_bytes().to_vec())) - } - Err(err) => match err { - SdkError::ServiceError(service) => { - let code = service.err().code(); - if matches!(code, Some("NotFound") | Some("NoSuchKey")) { - Ok(None) - } else { - Err(anyhow::anyhow!( - "object store GET failed with status {code:?}" - )) - } - } - other => Err(anyhow::anyhow!("object store GET failed: {other}")), - }, - } - } -} - impl AzureObjectStore { fn new(url: &Url) -> anyhow::Result { let endpoint = azure_endpoint(url)?; diff --git a/docs/config.md b/docs/config.md index 0fe11f47ce..ec0c29d0fd 100644 --- a/docs/config.md +++ b/docs/config.md @@ -32,14 +32,6 @@ To enable `/share` for enterprise or self-hosted storage, configure: session_object_storage_url = "https://your-object-store.example.com/codex-sessions/" ``` -You can also use AWS S3 with authenticated requests: - -``` -session_object_storage_url = "s3://your-bucket/codex-sessions" -``` - -For S3, Codex uses the default AWS credential chain (env vars, shared config, instance roles, etc.) and requires a region (e.g., `AWS_REGION` or a profile default). - You can also use Azure Blob Storage with a SAS URL, either as a standard HTTPS URL or the shorthand `az://` form: ```