Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5e9190c

Browse files
mattsb42-awspraus
authored andcommittedMay 2, 2018
* helper clients need to set item attributes in encryption context used for processing item
* move sorted_key_map to serialize.attribute (only consumer) to avoid circular dependencies * add acceptance tests for helper clients to verify that item values are being added to encryption context (used by AWS CMP)
1 parent 43f4b45 commit 5e9190c

File tree

9 files changed

+521
-30
lines changed

9 files changed

+521
-30
lines changed
 

‎src/dynamodb_encryption_sdk/encrypted/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,14 @@ def copy(self):
104104
encryption_context=copy.copy(self.encryption_context),
105105
attribute_actions=self.attribute_actions
106106
)
107+
108+
def with_item(self, item):
109+
"""Return a copy of this instance with an encryption context that includes the provided item attributes.
110+
111+
:param dict item: DynamoDB item in DynamnoDB JSON format
112+
:returns: New :class:`CryptoConfig` identical to this one
113+
:rtype: CryptoConfig
114+
"""
115+
new_config = self.copy()
116+
new_config.encryption_context.attributes = item
117+
return new_config

‎src/dynamodb_encryption_sdk/encrypted/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ class EncryptedClient(object):
136136
137137
We do not currently support the ``update_item`` method.
138138
139-
:param table: Pre-configured boto3 DynamoDB client object
140-
:type table: boto3.resources.base.BaseClient
139+
:param client: Pre-configured boto3 DynamoDB client object
140+
:type client: boto3.resources.base.BaseClient
141141
:param CryptographicMaterialsProvider materials_provider: Cryptographic materials provider
142142
to use
143143
:param AttributeActions attribute_actions: Table-level configuration of how to encrypt/sign

‎src/dynamodb_encryption_sdk/internal/formatting/serialize/attribute.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,28 @@
3333
from dynamodb_encryption_sdk.internal.formatting.serialize import encode_length, encode_value
3434
from dynamodb_encryption_sdk.internal.identifiers import Tag, TagValues
3535
from dynamodb_encryption_sdk.internal.str_ops import to_bytes
36-
from dynamodb_encryption_sdk.internal.utils import sorted_key_map
3736

3837
__all__ = ('serialize_attribute',)
3938
_LOGGER = logging.getLogger(LOGGER_NAME)
4039
_RESERVED = b'\x00'
4140

4241

42+
def _sorted_key_map(item, transform=to_bytes):
43+
"""Creates a list of the item's key/value pairs as tuples, sorted by the keys transformed by transform.
44+
45+
:param dict item: Source dictionary
46+
:param function transform: Transform function
47+
:returns: List of tuples containing transformed key, original value, and original key for each entry
48+
:rtype: list(tuple)
49+
"""
50+
sorted_items = []
51+
for key, value in item.items():
52+
_key = transform(key)
53+
sorted_items.append((_key, value, key))
54+
sorted_items = sorted(sorted_items, key=lambda x: x[0])
55+
return sorted_items
56+
57+
4358
def serialize_attribute(attribute): # noqa: C901 pylint: disable=too-many-locals
4459
# type: (dynamodb_types.RAW_ATTRIBUTE) -> bytes
4560
"""Serializes a raw attribute to a byte string as defined for the DynamoDB Client-Side Encryption Standard.
@@ -213,7 +228,7 @@ def _serialize_map(_attribute):
213228
serialized_attribute.write(Tag.MAP.tag)
214229
serialized_attribute.write(encode_length(_attribute))
215230

216-
sorted_items = sorted_key_map(
231+
sorted_items = _sorted_key_map(
217232
item=_attribute,
218233
transform=_transform_string_value
219234
)

‎src/dynamodb_encryption_sdk/internal/utils.py

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@
2020
import botocore.client
2121

2222
from dynamodb_encryption_sdk.encrypted import CryptoConfig
23+
from dynamodb_encryption_sdk.encrypted.item import decrypt_python_item, encrypt_python_item
2324
from dynamodb_encryption_sdk.exceptions import InvalidArgumentError
24-
from dynamodb_encryption_sdk.internal.str_ops import to_bytes
2525
from dynamodb_encryption_sdk.structures import EncryptionContext, TableInfo
26+
from dynamodb_encryption_sdk.transform import dict_to_ddb
2627

2728
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
2829
from typing import Any, Callable, Dict, Text # noqa pylint: disable=unused-import
@@ -31,30 +32,14 @@
3132
pass
3233

3334
__all__ = (
34-
'sorted_key_map', 'TableInfoCache',
35+
'TableInfoCache',
3536
'crypto_config_from_kwargs', 'crypto_config_from_table_info', 'crypto_config_from_cache',
3637
'decrypt_get_item', 'decrypt_multi_get', 'decrypt_batch_get_item',
3738
'encrypt_put_item', 'encrypt_batch_write_item',
3839
'validate_get_arguments'
3940
)
4041

4142

42-
def sorted_key_map(item, transform=to_bytes):
43-
"""Creates a list of the item's key/value pairs as tuples, sorted by the keys transformed by transform.
44-
45-
:param dict item: Source dictionary
46-
:param function transform: Transform function
47-
:returns: List of tuples containing transformed key, original value, and original key for each entry
48-
:rtype: list(tuple)
49-
"""
50-
sorted_items = []
51-
for key, value in item.items():
52-
_key = transform(key)
53-
sorted_items.append((_key, value, key))
54-
sorted_items = sorted(sorted_items, key=lambda x: x[0])
55-
return sorted_items
56-
57-
5843
@attr.s(init=False)
5944
class TableInfoCache(object):
6045
# pylint: disable=too-few-public-methods
@@ -142,9 +127,16 @@ def crypto_config_from_table_info(materials_provider, attribute_actions, table_i
142127
:returns: crypto config and updated kwargs
143128
:rtype: tuple(CryptoConfig, dict)
144129
"""
130+
ec_kwargs = table_info.encryption_context_values
131+
if table_info.primary_index is not None:
132+
ec_kwargs.update({
133+
'partition_key_name': table_info.primary_index.partition,
134+
'sort_key_name': table_info.primary_index.sort
135+
})
136+
145137
return CryptoConfig(
146138
materials_provider=materials_provider,
147-
encryption_context=EncryptionContext(**table_info.encryption_context_values),
139+
encryption_context=EncryptionContext(**ec_kwargs),
148140
attribute_actions=attribute_actions
149141
)
150142

@@ -163,10 +155,23 @@ def crypto_config_from_cache(materials_provider, attribute_actions, table_info_c
163155
return crypto_config_from_table_info(materials_provider, attribute_actions, table_info)
164156

165157

158+
def _item_transformer(crypto_transformer):
159+
"""Supply an item transformer to go from an item that the provided ``crypto_transformer``
160+
can understand to a DynamoDB JSON object.
161+
162+
:param crypto_transformer: An item encryptor or decryptor function
163+
:returns: Item transformer function
164+
"""
165+
if crypto_transformer in (decrypt_python_item, encrypt_python_item):
166+
return dict_to_ddb
167+
168+
return lambda x: x
169+
170+
166171
def decrypt_multi_get(decrypt_method, crypto_config_method, read_method, **kwargs):
167172
# type: (Callable, Callable, Callable, **Any) -> Dict
168173
# TODO: narrow this down
169-
"""Transparently decrypt multiple items after getting them from the table.
174+
"""Transparently decrypt multiple items after getting them from the table with a scan or query method.
170175
171176
:param callable decrypt_method: Method to use to decrypt items
172177
:param callable crypto_config_method: Method that accepts ``kwargs`` and provides a :class:`CryptoConfig`
@@ -181,7 +186,7 @@ def decrypt_multi_get(decrypt_method, crypto_config_method, read_method, **kwarg
181186
for pos in range(len(response['Items'])):
182187
response['Items'][pos] = decrypt_method(
183188
item=response['Items'][pos],
184-
crypto_config=crypto_config
189+
crypto_config=crypto_config.with_item(_item_transformer(decrypt_method)(response['Items'][pos]))
185190
)
186191
return response
187192

@@ -204,7 +209,7 @@ def decrypt_get_item(decrypt_method, crypto_config_method, read_method, **kwargs
204209
if 'Item' in response:
205210
response['Item'] = decrypt_method(
206211
item=response['Item'],
207-
crypto_config=crypto_config
212+
crypto_config=crypto_config.with_item(_item_transformer(decrypt_method)(response['Item']))
208213
)
209214
return response
210215

@@ -236,7 +241,7 @@ def decrypt_batch_get_item(decrypt_method, crypto_config_method, read_method, **
236241
for pos, value in enumerate(items):
237242
items[pos] = decrypt_method(
238243
item=value,
239-
crypto_config=crypto_config
244+
crypto_config=crypto_config.with_item(_item_transformer(decrypt_method)(items[pos]))
240245
)
241246
return response
242247

@@ -256,7 +261,7 @@ def encrypt_put_item(encrypt_method, crypto_config_method, write_method, **kwarg
256261
crypto_config, ddb_kwargs = crypto_config_method(**kwargs)
257262
ddb_kwargs['Item'] = encrypt_method(
258263
item=ddb_kwargs['Item'],
259-
crypto_config=crypto_config
264+
crypto_config=crypto_config.with_item(_item_transformer(encrypt_method)(ddb_kwargs['Item']))
260265
)
261266
return write_method(**ddb_kwargs)
262267

@@ -287,6 +292,6 @@ def encrypt_batch_write_item(encrypt_method, crypto_config_method, write_method,
287292
if request_type == 'PutRequest':
288293
items[pos][request_type]['Item'] = encrypt_method(
289294
item=item['Item'],
290-
crypto_config=crypto_config
295+
crypto_config=crypto_config.with_item(_item_transformer(encrypt_method)(item['Item']))
291296
)
292297
return write_method(**kwargs)

‎test/README.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
********************************************
2+
dynamodb-encryption-client Integration Tests
3+
********************************************
4+
5+
In order to run these integration tests successfully, these things which must be configured.
6+
7+
#. These tests assume that AWS credentials are available in one of the
8+
`automatically discoverable credential locations`_.
9+
#. The ``AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID`` environment variable
10+
must be set to a valid `AWS KMS CMK ARN`_ that can be used by the available credentials.
11+
#. The ``DDB_ENCRYPTION_CLIENT_TEST_TABLE_NAME`` environment variable must be set to a valid
12+
DynamoDB table name, in the default region, to which the discoverable credentials have
13+
read, write, and describe permissions.
14+
15+
.. _automatically discoverable credential locations: http://boto3.readthedocs.io/en/latest/guide/configuration.html
16+
.. _AWS KMS CMK ARN: http://docs.aws.amazon.com/kms/latest/APIReference/API_Encrypt.html

‎test/acceptance/acceptance_test_utils.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import sys
2020

2121
import boto3
22-
from moto import mock_dynamodb2
2322
import pytest
2423
from six.moves.urllib.parse import urlparse # moves confuse pylint: disable=wrong-import-order
2524

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You
4+
# may not use this file except in compliance with the License. A copy of
5+
# the License is located at
6+
#
7+
# http://aws.amazon.com/apache2.0/
8+
#
9+
# or in the "license" file accompanying this file. This file is
10+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11+
# ANY KIND, either express or implied. See the License for the specific
12+
# language governing permissions and limitations under the License.
13+
"""Acceptance tests for ``dynamodb_encryption_sdk.encrypted.client``."""
14+
import botocore
15+
from mock import MagicMock
16+
from moto import mock_dynamodb2
17+
import pytest
18+
19+
from dynamodb_encryption_sdk.encrypted.client import EncryptedClient
20+
from dynamodb_encryption_sdk.structures import TableIndex, TableInfo
21+
from dynamodb_encryption_sdk.transform import dict_to_ddb
22+
from ..acceptance_test_utils import load_scenarios
23+
24+
pytestmark = [pytest.mark.accept]
25+
26+
27+
def fake_client(table_name, item):
28+
client = MagicMock(__class__=botocore.client.BaseClient)
29+
client.get_item.return_value = {'Item': item.copy()}
30+
client.batch_get_item.return_value = {'Responses': {table_name: [item.copy()]}}
31+
return client
32+
33+
34+
def _compare_item(plaintext_item, decrypted_item):
35+
assert set(decrypted_item.keys()) == set(plaintext_item.keys())
36+
for key in decrypted_item:
37+
if key == 'version':
38+
continue
39+
assert decrypted_item[key] == plaintext_item[key]
40+
41+
42+
def _client_setup(
43+
materials_provider,
44+
table_name,
45+
table_index,
46+
ciphertext_item,
47+
attribute_actions,
48+
prep
49+
):
50+
prep() # Test scenario setup that needs to happen inside the test
51+
cmp = materials_provider() # Some of the materials providers need to be constructed inside the test
52+
client = fake_client(table_name, ciphertext_item)
53+
table_info = TableInfo(
54+
name=table_name,
55+
primary_index=TableIndex(
56+
partition=table_index['partition'],
57+
sort=table_index.get('sort', None)
58+
)
59+
)
60+
item_key = {table_info.primary_index.partition: ciphertext_item[table_info.primary_index.partition]}
61+
if table_info.primary_index.sort is not None:
62+
item_key[table_info.primary_index.sort] = ciphertext_item[table_info.primary_index.sort]
63+
64+
e_client = EncryptedClient(
65+
client=client,
66+
materials_provider=cmp,
67+
attribute_actions=attribute_actions,
68+
auto_refresh_table_indexes=False
69+
)
70+
e_client._table_info_cache._all_tables_info[table_name] = table_info
71+
return e_client, dict_to_ddb(item_key)
72+
73+
74+
def _item_check(
75+
materials_provider,
76+
table_name,
77+
table_index,
78+
ciphertext_item,
79+
plaintext_item,
80+
attribute_actions,
81+
prep
82+
):
83+
e_client, item_key = _client_setup(
84+
materials_provider,
85+
table_name,
86+
table_index,
87+
ciphertext_item,
88+
attribute_actions,
89+
prep
90+
)
91+
decrypted_item = e_client.get_item(TableName=table_name, Key=item_key)['Item']
92+
_compare_item(plaintext_item, decrypted_item)
93+
94+
95+
def _batch_items_check(
96+
materials_provider,
97+
table_name,
98+
table_index,
99+
ciphertext_item,
100+
plaintext_item,
101+
attribute_actions,
102+
prep
103+
):
104+
e_client, item_key = _client_setup(
105+
materials_provider,
106+
table_name,
107+
table_index,
108+
ciphertext_item,
109+
attribute_actions,
110+
prep
111+
)
112+
response = e_client.batch_get_item(RequestItems={table_name: {'Keys': [item_key]}})
113+
decrypted_item = response['Responses'][table_name][0]
114+
_compare_item(plaintext_item, decrypted_item)
115+
116+
117+
def pytest_generate_tests(metafunc):
118+
if 'item_checker' in metafunc.fixturenames:
119+
metafunc.parametrize('item_checker', (
120+
pytest.param(_item_check, id='single-item'),
121+
pytest.param(_batch_items_check, id='batch-items')
122+
))
123+
124+
125+
@mock_dynamodb2
126+
@pytest.mark.local
127+
@pytest.mark.parametrize(
128+
'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
129+
load_scenarios(online=False)
130+
)
131+
def test_client_get_offline(
132+
materials_provider,
133+
table_name,
134+
table_index,
135+
ciphertext_item,
136+
plaintext_item,
137+
attribute_actions,
138+
prep,
139+
item_checker
140+
):
141+
return item_checker(
142+
materials_provider,
143+
table_name,
144+
table_index,
145+
ciphertext_item,
146+
plaintext_item,
147+
attribute_actions,
148+
prep
149+
)
150+
151+
152+
@pytest.mark.integ
153+
@pytest.mark.parametrize(
154+
'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
155+
load_scenarios(online=True)
156+
)
157+
def test_client_get_online(
158+
materials_provider,
159+
table_name,
160+
table_index,
161+
ciphertext_item,
162+
plaintext_item,
163+
attribute_actions,
164+
prep,
165+
item_checker
166+
):
167+
return item_checker(
168+
materials_provider,
169+
table_name,
170+
table_index,
171+
ciphertext_item,
172+
plaintext_item,
173+
attribute_actions,
174+
prep
175+
)
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You
4+
# may not use this file except in compliance with the License. A copy of
5+
# the License is located at
6+
#
7+
# http://aws.amazon.com/apache2.0/
8+
#
9+
# or in the "license" file accompanying this file. This file is
10+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11+
# ANY KIND, either express or implied. See the License for the specific
12+
# language governing permissions and limitations under the License.
13+
"""Acceptance tests for ``dynamodb_encryption_sdk.encrypted.resource``."""
14+
from boto3.resources.base import ServiceResource
15+
from boto3.resources.collection import CollectionManager
16+
import botocore
17+
from mock import MagicMock
18+
from moto import mock_dynamodb2
19+
import pytest
20+
21+
from dynamodb_encryption_sdk.encrypted.resource import EncryptedResource
22+
from dynamodb_encryption_sdk.structures import TableIndex, TableInfo
23+
from dynamodb_encryption_sdk.transform import ddb_to_dict
24+
from ..acceptance_test_utils import load_scenarios
25+
26+
pytestmark = [pytest.mark.accept]
27+
28+
29+
def fake_resource(table_name, item):
30+
resource = MagicMock(__class__=ServiceResource)
31+
resource.batch_get_item.return_value = {'Responses': {table_name: [item.copy()]}}
32+
resource.meta.client = MagicMock(__class__=botocore.client.BaseClient)
33+
resource.tables = MagicMock(__class__=CollectionManager)
34+
return resource
35+
36+
37+
def _compare_item(plaintext_item, decrypted_item):
38+
assert set(decrypted_item.keys()) == set(plaintext_item.keys())
39+
for key in decrypted_item:
40+
if key == 'version':
41+
continue
42+
assert decrypted_item[key] == plaintext_item[key]
43+
44+
45+
def _resource_setup(
46+
materials_provider,
47+
table_name,
48+
table_index,
49+
ciphertext_item,
50+
attribute_actions,
51+
prep
52+
):
53+
prep() # Test scenario setup that needs to happen inside the test
54+
cmp = materials_provider() # Some of the materials providers need to be constructed inside the test
55+
resource = fake_resource(table_name, ciphertext_item)
56+
table_info = TableInfo(
57+
name=table_name,
58+
primary_index=TableIndex(
59+
partition=table_index['partition'],
60+
sort=table_index.get('sort', None)
61+
)
62+
)
63+
item_key = {table_info.primary_index.partition: ciphertext_item[table_info.primary_index.partition]}
64+
if table_info.primary_index.sort is not None:
65+
item_key[table_info.primary_index.sort] = ciphertext_item[table_info.primary_index.sort]
66+
67+
e_resource = EncryptedResource(
68+
resource=resource,
69+
materials_provider=cmp,
70+
attribute_actions=attribute_actions,
71+
auto_refresh_table_indexes=False
72+
)
73+
e_resource._table_info_cache._all_tables_info[table_name] = table_info
74+
return e_resource, item_key
75+
76+
77+
def _batch_items_check(
78+
materials_provider,
79+
table_name,
80+
table_index,
81+
ciphertext_item,
82+
plaintext_item,
83+
attribute_actions,
84+
prep
85+
):
86+
plaintext_item = ddb_to_dict(plaintext_item)
87+
ciphertext_item = ddb_to_dict(ciphertext_item)
88+
e_resource, item_key = _resource_setup(
89+
materials_provider,
90+
table_name,
91+
table_index,
92+
ciphertext_item,
93+
attribute_actions,
94+
prep
95+
)
96+
response = e_resource.batch_get_item(RequestItems={table_name: {'Keys': [item_key]}})
97+
decrypted_item = response['Responses'][table_name][0]
98+
_compare_item(plaintext_item, decrypted_item)
99+
100+
101+
@mock_dynamodb2
102+
@pytest.mark.local
103+
@pytest.mark.parametrize(
104+
'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
105+
load_scenarios(online=False)
106+
)
107+
def test_client_get_offline(
108+
materials_provider,
109+
table_name,
110+
table_index,
111+
ciphertext_item,
112+
plaintext_item,
113+
attribute_actions,
114+
prep
115+
):
116+
return _batch_items_check(
117+
materials_provider,
118+
table_name,
119+
table_index,
120+
ciphertext_item,
121+
plaintext_item,
122+
attribute_actions,
123+
prep
124+
)
125+
126+
127+
@pytest.mark.integ
128+
@pytest.mark.parametrize(
129+
'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
130+
load_scenarios(online=True)
131+
)
132+
def test_client_get_online(
133+
materials_provider,
134+
table_name,
135+
table_index,
136+
ciphertext_item,
137+
plaintext_item,
138+
attribute_actions,
139+
prep
140+
):
141+
return _batch_items_check(
142+
materials_provider,
143+
table_name,
144+
table_index,
145+
ciphertext_item,
146+
plaintext_item,
147+
attribute_actions,
148+
prep
149+
)
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You
4+
# may not use this file except in compliance with the License. A copy of
5+
# the License is located at
6+
#
7+
# http://aws.amazon.com/apache2.0/
8+
#
9+
# or in the "license" file accompanying this file. This file is
10+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11+
# ANY KIND, either express or implied. See the License for the specific
12+
# language governing permissions and limitations under the License.
13+
"""Acceptance tests for ``dynamodb_encryption_sdk.encrypted.table``."""
14+
from boto3.resources.base import ServiceResource
15+
from mock import MagicMock
16+
from moto import mock_dynamodb2
17+
import pytest
18+
19+
from dynamodb_encryption_sdk.encrypted.table import EncryptedTable
20+
from dynamodb_encryption_sdk.structures import TableIndex, TableInfo
21+
from dynamodb_encryption_sdk.transform import ddb_to_dict
22+
from ..acceptance_test_utils import load_scenarios
23+
24+
pytestmark = [pytest.mark.accept]
25+
26+
27+
def fake_table(item):
28+
table = MagicMock(__class__=ServiceResource)
29+
table.get_item.return_value = {'Item': item}
30+
return table
31+
32+
33+
def _item_check(
34+
materials_provider,
35+
table_name,
36+
table_index,
37+
ciphertext_item,
38+
plaintext_item,
39+
attribute_actions,
40+
prep
41+
):
42+
ciphertext_item = ddb_to_dict(ciphertext_item)
43+
plaintext_item = ddb_to_dict(plaintext_item)
44+
prep() # Test scenario setup that needs to happen inside the test
45+
cmp = materials_provider() # Some of the materials providers need to be constructed inside the test
46+
table = fake_table(ciphertext_item)
47+
table_info = TableInfo(
48+
name=table_name,
49+
primary_index=TableIndex(
50+
partition=table_index['partition'],
51+
sort=table_index.get('sort', None)
52+
)
53+
)
54+
item_key = {table_info.primary_index.partition: ciphertext_item[table_info.primary_index.partition]}
55+
if table_info.primary_index.sort is not None:
56+
item_key[table_info.primary_index.sort] = ciphertext_item[table_info.primary_index.sort]
57+
58+
e_table = EncryptedTable(
59+
table=table,
60+
materials_provider=cmp,
61+
table_info=table_info,
62+
attribute_actions=attribute_actions,
63+
auto_refresh_table_indexes=False
64+
)
65+
decrypted_item = e_table.get_item(Key=item_key)['Item']
66+
assert set(decrypted_item.keys()) == set(plaintext_item.keys())
67+
for key in decrypted_item:
68+
if key == 'version':
69+
continue
70+
assert decrypted_item[key] == plaintext_item[key]
71+
72+
73+
@mock_dynamodb2
74+
@pytest.mark.local
75+
@pytest.mark.parametrize(
76+
'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
77+
load_scenarios(online=False)
78+
)
79+
def test_table_get_offline(
80+
materials_provider,
81+
table_name,
82+
table_index,
83+
ciphertext_item,
84+
plaintext_item,
85+
attribute_actions,
86+
prep
87+
):
88+
return _item_check(
89+
materials_provider,
90+
table_name,
91+
table_index,
92+
ciphertext_item,
93+
plaintext_item,
94+
attribute_actions,
95+
prep
96+
)
97+
98+
99+
@pytest.mark.integ
100+
@pytest.mark.parametrize(
101+
'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
102+
load_scenarios(online=True)
103+
)
104+
def test_table_get_online(
105+
materials_provider,
106+
table_name,
107+
table_index,
108+
ciphertext_item,
109+
plaintext_item,
110+
attribute_actions,
111+
prep
112+
):
113+
return _item_check(
114+
materials_provider,
115+
table_name,
116+
table_index,
117+
ciphertext_item,
118+
plaintext_item,
119+
attribute_actions,
120+
prep
121+
)

0 commit comments

Comments
 (0)
Please sign in to comment.