Improve DDB transaction validation (#5521)

This commit is contained in:
rafcio19 2022-10-04 14:18:14 +01:00 committed by GitHub
parent 8486646f2d
commit 696b809b5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 0 deletions

View File

@ -323,3 +323,12 @@ class InvalidConversion(JsonRESTError):
def __init__(self): def __init__(self):
er = "SerializationException" er = "SerializationException"
super().__init__(er, "NUMBER_VALUE cannot be converted to String") super().__init__(er, "NUMBER_VALUE cannot be converted to String")
class TransactWriteSingleOpException(MockValidationException):
there_can_be_only_one = (
"TransactItems can only contain one of Check, Put, Update or Delete"
)
def __init__(self):
super().__init__(self.there_can_be_only_one)

View File

@ -32,6 +32,7 @@ from moto.dynamodb.exceptions import (
StreamAlreadyEnabledException, StreamAlreadyEnabledException,
MockValidationException, MockValidationException,
InvalidConversion, InvalidConversion,
TransactWriteSingleOpException,
) )
from moto.dynamodb.models.utilities import bytesize from moto.dynamodb.models.utilities import bytesize
from moto.dynamodb.models.dynamo_type import DynamoType from moto.dynamodb.models.dynamo_type import DynamoType
@ -1656,6 +1657,11 @@ class DynamoDBBackend(BaseBackend):
errors = [] # [(Code, Message, Item), ..] errors = [] # [(Code, Message, Item), ..]
for item in transact_items: for item in transact_items:
# check transact writes are not performing multiple operations
# in the same item
if len(list(item.keys())) > 1:
raise TransactWriteSingleOpException
try: try:
if "ConditionCheck" in item: if "ConditionCheck" in item:
item = item["ConditionCheck"] item = item["ConditionCheck"]
@ -1682,6 +1688,7 @@ class DynamoDBBackend(BaseBackend):
item = item["Put"] item = item["Put"]
attrs = item["Item"] attrs = item["Item"]
table_name = item["TableName"] table_name = item["TableName"]
check_unicity(table_name, item)
condition_expression = item.get("ConditionExpression", None) condition_expression = item.get("ConditionExpression", None)
expression_attribute_names = item.get( expression_attribute_names = item.get(
"ExpressionAttributeNames", None "ExpressionAttributeNames", None

View File

@ -761,3 +761,42 @@ def test_query_begins_with_without_brackets():
'Invalid KeyConditionExpression: Syntax error; token: "sk"' 'Invalid KeyConditionExpression: Syntax error; token: "sk"'
) )
err["Code"].should.equal("ValidationException") err["Code"].should.equal("ValidationException")
@mock_dynamodb
def test_transact_write_items_multiple_operations_fail():
# Setup
table_schema = {
"KeySchema": [{"AttributeName": "id", "KeyType": "HASH"}],
"AttributeDefinitions": [{"AttributeName": "id", "AttributeType": "S"}],
}
dynamodb = boto3.client("dynamodb", region_name="us-east-1")
table_name = "test-table"
dynamodb.create_table(
TableName=table_name, BillingMode="PAY_PER_REQUEST", **table_schema
)
# Execute
with pytest.raises(ClientError) as exc:
dynamodb.transact_write_items(
TransactItems=[
{
"Put": {
"Item": {"id": {"S": "test"}},
"TableName": table_name,
},
"Delete": {
"Key": {"id": {"S": "test"}},
"TableName": table_name,
},
}
]
)
# Verify
err = exc.value.response["Error"]
assert err["Code"] == "ValidationException"
assert (
err["Message"]
== "TransactItems can only contain one of Check, Put, Update or Delete"
)