diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index ba5bcb0..162a9dd 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -24,7 +24,9 @@ services: S3_ENDPOINT: ${S3_ENDPOINT:-seaweedfs:8333} S3_PUBLIC_ENDPOINT: ${S3_PUBLIC_ENDPOINT:-localhost:8333} S3_BUCKET: ${S3_BUCKET:-officeconvert} + S3_REGION: ${S3_REGION:-} S3_USE_SSL: ${S3_USE_SSL:-false} + S3_PUBLIC_USE_SSL: ${S3_PUBLIC_USE_SSL:-} S3_ACCESS_KEY: ${S3_ACCESS_KEY:-minioadmin} S3_SECRET_KEY: ${S3_SECRET_KEY:-minioadmin} S3_SESSION_TTL_SECONDS: ${S3_SESSION_TTL_SECONDS:-3600} diff --git a/docker-compose.yml b/docker-compose.yml index a9b67f4..5fa108f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,7 +23,9 @@ services: S3_ENDPOINT: ${S3_ENDPOINT:-seaweedfs:8333} S3_PUBLIC_ENDPOINT: ${S3_PUBLIC_ENDPOINT:-localhost:8333} S3_BUCKET: ${S3_BUCKET:-officeconvert} + S3_REGION: ${S3_REGION:-} S3_USE_SSL: ${S3_USE_SSL:-false} + S3_PUBLIC_USE_SSL: ${S3_PUBLIC_USE_SSL:-} S3_ACCESS_KEY: ${S3_ACCESS_KEY:-minioadmin} S3_SECRET_KEY: ${S3_SECRET_KEY:-minioadmin} S3_SESSION_TTL_SECONDS: ${S3_SESSION_TTL_SECONDS:-3600} diff --git a/python/packages/server/src/officeconvert_server/config.py b/python/packages/server/src/officeconvert_server/config.py index f64210f..f7f570c 100644 --- a/python/packages/server/src/officeconvert_server/config.py +++ b/python/packages/server/src/officeconvert_server/config.py @@ -31,10 +31,10 @@ class ServerConfig: def load_server_config() -> ServerConfig: """Load server configuration from environment variables.""" s3_secure = os.getenv("S3_USE_SSL", "false").lower() == "true" - public_ssl_env = os.getenv("S3_PUBLIC_USE_SSL") + public_ssl_env = os.getenv("S3_PUBLIC_USE_SSL", "").strip() s3_public_secure = ( public_ssl_env.lower() == "true" - if public_ssl_env is not None + if public_ssl_env else s3_secure ) region_env = os.getenv("S3_REGION", "").strip() diff --git a/python/packages/server/src/officeconvert_server/storage.py b/python/packages/server/src/officeconvert_server/storage.py index 1b843ea..e18ba84 100644 --- a/python/packages/server/src/officeconvert_server/storage.py +++ b/python/packages/server/src/officeconvert_server/storage.py @@ -86,16 +86,19 @@ class S3Store: def ensure_bucket(self, bucket_name: str) -> None: """Create a bucket if it does not already exist. - Uses CreateBucket only, not HeadBucket. Some S3-compatible stores - (including SeaweedFS) mishandle or over-restrict HeadBucket; the MinIO - client's bucket_exists() maps non-NoSuchBucket errors to failures. - Idempotent create covers the same contract with fewer round trips. + Tries CreateBucket first (idempotent on SeaweedFS and when the caller + owns the bucket). AWS production IAM often grants object access only on + a pre-provisioned bucket; in that case CreateBucket returns + AccessDenied even though HeadBucket succeeds. """ try: self._client.make_bucket(bucket_name) except S3Error as exc: if exc.code in ("BucketAlreadyOwnedByYou", "BucketAlreadyExists"): return + if exc.code in ("AccessDenied", "Forbidden"): + if self._client.bucket_exists(bucket_name): + return raise def presigned_put_url(self, bucket_name: str, object_key: str, *, ttl_seconds: int) -> str: