DynamoDB: put_item(): Improve type validation (#5654)

This commit is contained in:
Bert Blommers 2022-11-10 21:52:02 -01:00 committed by GitHub
parent 96b2eff1bc
commit 37845792d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 2 deletions

View File

@ -332,3 +332,8 @@ class TransactWriteSingleOpException(MockValidationException):
def __init__(self):
super().__init__(self.there_can_be_only_one)
class SerializationException(DynamodbException):
def __init__(self, msg):
super().__init__(error_type="SerializationException", message=msg)

View File

@ -33,6 +33,7 @@ from moto.dynamodb.exceptions import (
MockValidationException,
InvalidConversion,
TransactWriteSingleOpException,
SerializationException,
)
from moto.dynamodb.models.utilities import bytesize
from moto.dynamodb.models.dynamo_type import DynamoType
@ -658,6 +659,17 @@ class Table(CloudFormationModel):
self._validate_item_types(value)
elif type(value) == int and key == "N":
raise InvalidConversion
if key == "S":
# This scenario is usually caught by boto3, but the user can disable parameter validation
# Which is why we need to catch it 'server-side' as well
if type(value) == int:
raise SerializationException(
"NUMBER_VALUE cannot be converted to String"
)
if type(value) == dict:
raise SerializationException(
"Start of structure or map found where not expected"
)
def put_item(
self,
@ -699,9 +711,8 @@ class Table(CloudFormationModel):
actual_type=range_value.type,
)
self._validate_key_sizes(item_attrs)
self._validate_item_types(item_attrs)
self._validate_key_sizes(item_attrs)
if expected is None:
expected = {}

View File

@ -870,3 +870,29 @@ def test_update_primary_key():
table.get_item(Key={"pk": "testchangepk"})["Item"].should.equal(
{"pk": "testchangepk"}
)
@mock_dynamodb
def test_put_item__string_as_integer_value():
if settings.TEST_SERVER_MODE:
raise SkipTest("Unable to mock a session with Config in ServerMode")
session = botocore.session.Session()
config = botocore.client.Config(parameter_validation=False)
client = session.create_client("dynamodb", region_name="us-east-1", config=config)
client.create_table(
TableName="without_sk",
KeySchema=[{"AttributeName": "pk", "KeyType": "HASH"}],
AttributeDefinitions=[{"AttributeName": "pk", "AttributeType": "S"}],
ProvisionedThroughput={"ReadCapacityUnits": 10, "WriteCapacityUnits": 10},
)
with pytest.raises(ClientError) as exc:
client.put_item(TableName="without_sk", Item={"pk": {"S": 123}})
err = exc.value.response["Error"]
err["Code"].should.equal("SerializationException")
err["Message"].should.equal("NUMBER_VALUE cannot be converted to String")
with pytest.raises(ClientError) as exc:
client.put_item(TableName="without_sk", Item={"pk": {"S": {"S": "asdf"}}})
err = exc.value.response["Error"]
err["Code"].should.equal("SerializationException")
err["Message"].should.equal("Start of structure or map found where not expected")