Simulators
Versioned buckets
A versioned bucket keeps what a key held before, and the simulator lists those rows and handles a delete as S3 does. Load the archive scenario, list the history of a key whose latest version is a delete marker and delete a second key:
s3curl() { curl -s --aws-sigv4 'aws:amz:us-east-1:s3' --user 'AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' "$@"; }
curl -s -X POST "$RYSTIC_URL/_rystic/scenario" -d '{"name": "s3_versioned_archive"}' -w '%{http_code}\n'
# -> 204
s3curl "$RYSTIC_URL/acme-demo-archive?versions&prefix=notes/" | grep -oE '<DeleteMarker>|<Version>|<IsLatest>[a-z]+'
# -> <DeleteMarker>
# -> <IsLatest>true
# -> <Version>
# -> <IsLatest>false
# -> <Version>
# -> <IsLatest>false
s3curl "$RYSTIC_URL/acme-demo-archive/notes/draft.md" | grep -oE '<Code>[^<]*'
# -> <Code>NoSuchKey
s3curl -X DELETE "$RYSTIC_URL/acme-demo-archive/reports/2025-q4.csv" -D - -o /dev/null | grep -i '^x-amz-delete-marker'
# -> x-amz-delete-marker: true
What is versioned
s3_versioned_archive holds acme-demo-archive, versioning enabled, with six version rows across three keys:
reports/2025-q3.csv, overwritten oncereports/2025-q4.csv, with one versionnotes/draft.md, whose latest version is a delete marker over two older ones, so it has no current object
s3_encrypted_vault holds a bucket with versioning and MFA delete enabled. s3_bucket_farm holds buckets in every versioning state.
ListObjectVersions returns IsLatest, the older versions and each DeleteMarker. GetBucketVersioning and PutBucketVersioning read and set the bucket’s status.
Deletes and delete markers
A DeleteObject in a versioned bucket makes a delete marker the current version and returns x-amz-delete-marker: true. The object stays listed as an older version, and a later GetObject returns 404 NoSuchKey, as on S3.
A DeleteObject with ?versionId= removes that version for good and adds no delete marker. The current object stays when the version named is an older one.
Differs from S3: when the version deleted is the current one, the older versions stay listed with IsLatest false and GetObject returns 404. S3 makes the newest remaining version current.
Differs from S3: DeleteObjects (POST /{Bucket}?delete) ignores each VersionId and deletes the key’s current object. It adds no delete marker. The key’s latest row stays IsLatest true, and GetObject returns 404.
Writes and older versions
Only the latest version of a key has a body. A scenario’s older versions are rows in the version listing.
Differs from S3: GetObject, GetObjectAttributes, GetObjectAcl and the object tagging calls ignore ?versionId= and act on the current object, whatever version it names.
Differs from S3: HeadObject with ?versionId= returns 404 for any version but the current one.
Differs from S3: a CopyObject whose x-amz-copy-source names an older version returns 404 NoSuchKey.
Differs from S3: an UploadPartCopy whose x-amz-copy-source names an older version copies the current object.
Differs from S3: a PutObject into a versioned bucket writes a null version, not a new one (Limitations). So test version history against the scenarios’ rows, not against your own overwrites.