Split from #475. The record-and-echo half is #492 and is milestoned; this carries items
2–5 of #475's own priority order, which interact with each other and are worth designing
together rather than piecemeal.
Depends on #492 — every item here is a resolution rule over the fields #492 stores.
1. CopyObject does not inherit the source's encryption
The sharpest case, and the one #475's reporter found two live bugs behind. S3 encrypts the
destination according to the request; a copy naming nothing gets the bucket default,
not the source's encryption. So an in-place CopyObject for a metadata change, or an
automatic storage-tier transition, silently moves an SSE-KMS object off the customer
managed key.
Same asymmetry family as the MetadataDirective behaviour already documented in
s3_copy_metadata.go:73 — worth following that precedent, since a reader who understands
one will expect the other.
2. Multipart records it on the create only
CreateMultipartUpload carries the encryption for the upload as a whole; UploadPart
restating it is rejected; CompleteMultipartUpload surfaces it on the assembled
object.
S3SystemMetadata is embedded in both S3Object and S3MultipartUpload precisely so the
two write paths cannot disagree (#406), so this may fall out naturally. But #475 flags a
real design question: the resolution rules differ enough that SSE may want its own struct
rather than joining that family — the way Content-Type and the storage class deliberately
stayed out. Decide that explicitly.
3. Bucket default encryption
PutBucketEncryption / GetBucketEncryption / DeleteBucketEncryption, so a request
naming nothing resolves to the bucket's setting rather than to absent.
This is what makes "off" testable as distinct from "unencrypted": S3 has applied SSE-S3
to all new objects unconditionally since January 2023, so a real bucket never stores an
object with no encryption at all. Note the interaction with #492's criterion that an object
written with no headers echoes none — that criterion exists to keep "no header sent"
observable, and this item changes it, so the change has to be deliberate and documented
rather than a side effect.
4. The invalid combinations
Each is a combination a caller can produce and currently gets silent success for — the
tracker's recurring shape, where the consumer's error branch is unreachable:
x-amz-server-side-encryption-aws-kms-key-id sent with AES256 → InvalidArgument
x-amz-server-side-encryption-bucket-key-enabled without aws:kms → InvalidArgument
- an unrecognized algorithm token →
InvalidArgument
UploadPart carrying encryption headers → 400
Per #487, each message needs its own corroborating source — a capture or a parity-tested
reimplementation — or it ships as substrate's own text and says so in the comment.
Acceptance criteria
Not milestoned: this wants a design pass on the resolution rules before it is scheduled.
SSE-C remains out of scope.
Split from #475. The record-and-echo half is #492 and is milestoned; this carries items
2–5 of #475's own priority order, which interact with each other and are worth designing
together rather than piecemeal.
Depends on #492 — every item here is a resolution rule over the fields #492 stores.
1.
CopyObjectdoes not inherit the source's encryptionThe sharpest case, and the one #475's reporter found two live bugs behind. S3 encrypts the
destination according to the request; a copy naming nothing gets the bucket default,
not the source's encryption. So an in-place
CopyObjectfor a metadata change, or anautomatic storage-tier transition, silently moves an SSE-KMS object off the customer
managed key.
Same asymmetry family as the
MetadataDirectivebehaviour already documented ins3_copy_metadata.go:73— worth following that precedent, since a reader who understandsone will expect the other.
2. Multipart records it on the create only
CreateMultipartUploadcarries the encryption for the upload as a whole;UploadPartrestating it is rejected;
CompleteMultipartUploadsurfaces it on the assembledobject.
S3SystemMetadatais embedded in bothS3ObjectandS3MultipartUploadprecisely so thetwo write paths cannot disagree (#406), so this may fall out naturally. But #475 flags a
real design question: the resolution rules differ enough that SSE may want its own struct
rather than joining that family — the way
Content-Typeand the storage class deliberatelystayed out. Decide that explicitly.
3. Bucket default encryption
PutBucketEncryption/GetBucketEncryption/DeleteBucketEncryption, so a requestnaming nothing resolves to the bucket's setting rather than to absent.
This is what makes "off" testable as distinct from "unencrypted": S3 has applied SSE-S3
to all new objects unconditionally since January 2023, so a real bucket never stores an
object with no encryption at all. Note the interaction with #492's criterion that an object
written with no headers echoes none — that criterion exists to keep "no header sent"
observable, and this item changes it, so the change has to be deliberate and documented
rather than a side effect.
4. The invalid combinations
Each is a combination a caller can produce and currently gets silent success for — the
tracker's recurring shape, where the consumer's error branch is unreachable:
x-amz-server-side-encryption-aws-kms-key-idsent withAES256→InvalidArgumentx-amz-server-side-encryption-bucket-key-enabledwithoutaws:kms→InvalidArgumentInvalidArgumentUploadPartcarrying encryption headers → 400Per #487, each message needs its own corroborating source — a capture or a parity-tested
reimplementation — or it ships as substrate's own text and says so in the comment.
Acceptance criteria
CopyObjectnaming no encryption does not inherit the source's; it takes thebucket default, and there is a test for the in-place metadata-change case
specifically.
CreateMultipartUploadrecords it,UploadPartrestating it is refused,CompleteMultipartUploadsurfaces it on the assembled object.PutObjectnaming nothingresolves to the bucket's default.
docs/services.mdcovers the resolution order — request, then bucket default — andthe
CopyObjectasymmetry alongside the existingMetadataDirectivenote.Not milestoned: this wants a design pass on the resolution rules before it is scheduled.
SSE-C remains out of scope.