S3: Allow in place copies when bucket versioning is enabled (#7303)

This commit is contained in:
Arpad Müller 2024-02-04 22:56:27 +01:00 committed by GitHub
parent 7eb3c572d9
commit a4b71877e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 55 additions and 2 deletions

View File

@ -108,7 +108,7 @@ class FakeKey(BaseModel, ManagedState):
storage: Optional[str] = "STANDARD",
etag: Optional[str] = None,
is_versioned: bool = False,
version_id: str = "null",
version_id: Optional[str] = None,
max_buffer_size: Optional[int] = None,
multipart: Optional["FakeMultipart"] = None,
bucket_name: Optional[str] = None,
@ -170,7 +170,7 @@ class FakeKey(BaseModel, ManagedState):
@property
def version_id(self) -> str:
return self._version_id
return self._version_id or "null"
@property
def value(self) -> bytes:
@ -2674,6 +2674,7 @@ class S3Backend(BaseBackend, CloudWatchMetricProvider):
mdirective == "REPLACE",
website_redirect_location,
bucket.encryption, # S3 will allow copy in place if the bucket has encryption configured
src_key._version_id and bucket.is_versioned,
)
):
raise CopyObjectMustChangeSomething

View File

@ -783,6 +783,58 @@ def test_copy_object_in_place_with_bucket_encryption():
assert response["ServerSideEncryption"] == "AES256"
@mock_aws
def test_copy_object_in_place_with_versioning():
# If a bucket has versioning enabled, it will allow copy in place
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "testbucket"
client.create_bucket(Bucket=bucket_name)
key = "source-key"
response = client.put_object(
Body=b"",
Bucket=bucket_name,
Key=key,
)
response = client.put_bucket_versioning(
Bucket=bucket_name,
VersioningConfiguration={
"MFADelete": "Disabled",
"Status": "Enabled",
},
)
assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
response = client.put_object(
Body=b"",
Bucket=bucket_name,
Key=key,
)
version_id = response["ResponseMetadata"]["HTTPHeaders"]["x-amz-version-id"]
assert version_id and version_id != "null"
response = client.copy_object(
Bucket=bucket_name,
CopySource={"Bucket": bucket_name, "Key": key, "VersionId": version_id},
Key=key,
)
assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
response = client.copy_object(
Bucket=bucket_name,
CopySource={"Bucket": bucket_name, "Key": key, "VersionId": "null"},
Key=key,
)
assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
response = client.list_object_versions(
Bucket=bucket_name,
Prefix=key,
)
assert len(response["Versions"]) == 4
@mock_aws
@pytest.mark.parametrize(
"algorithm",