Overcast is alpha — behaviour and APIs may change between releases. Pin your version and read the changelog before upgrading.

overcast

S3 — Simple Storage Service

Quick start, object, multipart, versioning, lifecycle and notification coverage, the three addressing forms, and the ACLs, website serving and encryption that do nothing.

Objects, multipart uploads, versioning, lifecycle rules and event notifications, addressed path-style or virtual-hosted with no configuration.

Status: ✅ Supported

Quick start

export AWS_ENDPOINT_URL=http://localhost:4566

aws s3api create-bucket --bucket demo
echo hello > hello.txt
aws s3 cp hello.txt s3://demo/hello.txt

aws s3 ls s3://demo/
aws s3api get-object --bucket demo --key hello.txt /dev/stdout

Any credentials work; with none configured, run eval "$(overcast env)" first — see Using AWS SDKs and CLI.

What works

AreaBehaviour
ObjectsPut, get, head, copy and delete, with x-amz-meta-*, Content-Type, Content-Disposition, Cache-Control and friends preserved
Conditional and partial readsRange on GetObject and HeadObject, with 416 InvalidRange for one that names no bytes; If-Match and If-None-Match on GetObject
Conditional writesIf-None-Match: * and If-Match on PutObject and CompleteMultipartUpload, refused with 412 PreconditionFailed, so only one racing writer wins
ListingListObjects and ListObjectsV2 with prefix, delimiter, max-keys (validated, capped at 1000), start-after, continuation tokens, encoding-type=url and fetch-owner; DeleteObjects up to 1000 keys, quiet mode included
MultipartCreate, upload part, complete, abort, list uploads and list parts. CompleteMultipartUpload checks the parts list the way S3 does — a wrong or unknown ETag is InvalidPart, out-of-order parts InvalidPartOrder, a non-final part under 5 MiB EntityTooSmall, an empty list MalformedXML — and a refused completion leaves the upload in place to retry or abort
VersioningEnabled and Suspended with AWS’s semantics — version ids, delete markers, and ListObjectVersions in AWS’s order with resumable pagination
LifecycleExpiration, transitions, noncurrent-version rules, ExpiredObjectDeleteMarker and AbortIncompleteMultipartUpload, applied by an hourly sweeper on the injected clock
NotificationsSQS, SNS, Lambda and EventBridge destinations with prefix/suffix filters; records carry versionId and sequencer
Presigned URLsSigned against IAM access keys and STS session credentials; with OVERCAST_SIGV4_VALIDATE=true an invalid or expired URL is a 403 InvalidSignatureException
Bucket configPolicy, tagging, CORS, encryption, website and notification configuration, each stored and returned; tag sets are held to AWS’s 50-per-bucket, 10-per-object and key/value length limits
ConsoleThe web console browses buckets, previews text and images, shows version history and uploads or downloads objects

Addressing

Both styles work, and Overcast decides between them from the request’s Host header alone — there is no addressing-style environment variable.

FormExample
Path-stylelocalhost:4566/demo/hello.txt
Virtual-hosteddemo.s3.localhost:4566/hello.txt
Bare virtual-hosteddemo.localhost:4566/hello.txt — what an SDK emits against a custom endpoint with path-style disabled

The bucket is everything before the first .s3./.s3- label, or before the base domain in the bare form. For virtual-hosted names that resolve as wildcards, set OVERCAST_HOSTNAME to a wildcard-DNS domain — see Hostnames that resolve for every caller. Full precedence rules, including the reserved service labels that outrank a bucket match: Networking § How Overcast decides who owns a Host.

Differences from AWS

AreaOn AWSOvercast
EncryptionObjects are encrypted at restBucket encryption rules are stored and returned; object-level SSE request headers are ignored and not echoed back
ACLs and bucket policiesBoth are evaluated on every requestThe four ACL operations return 501; a policy is validated as JSON and stored, but S3 evaluates nothing — see IAM
Website endpointServes index and error documents, and redirectsThe website configuration round-trips faithfully, but no request is redirected or served an index document
S3 Select and GlacierSelectObjectContent, RestoreObject, GetObjectAttributes and UploadPartCopyAll return 501
CORS rule idsPreservedRules round-trip, but a rule’s Id is not preserved
Access points, replication, object lock, requester pays, public access block, inventory, Transfer AccelerationFull APINot modelled at all. A listing accepts x-amz-request-payer and returns no x-amz-request-charged, which is what AWS does for a bucket that is not Requester Pays
Directory buckets (S3 Express One Zone)Zonal endpoints with their own listing semanticsNot modelled; Overcast serves general purpose bucket paths only

Versioning states, the lifecycle sweeper’s exact rules and the website document’s validation are in S3 limitations; the EventBridge event shape is in S3 event notifications.

Gotchas

Warning

A bucket whose keys are all delete-marked is not empty. DeleteBucket answers BucketNotEmpty until the markers and the versions under them are removed — the AWS behaviour that makes the SDKs’ ListObjectVersions → DeleteObjects cleanup loop necessary.

A bucket name containing the literal substring .s3. is ambiguous under the virtual-hosted rule and will be mis-split. Real AWS has the same limitation and recommends against dots in bucket names used with virtual-hosted addressing.

Operations

45 of 53 listed operations are implemented. Per-operation status, notes and AWS API links: S3 operations.