boto3-assist 0.10.0__tar.gz → 0.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/.vscode/settings.json +3 -3
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/PKG-INFO +9 -2
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/README.md +4 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/pyproject.toml +9 -2
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/requirements-dev.txt +2 -1
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/boto3session.py +23 -13
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/cloudwatch/cloudwatch_connection_tracker.py +1 -1
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/cognito/cognito_utility.py +13 -13
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/connection.py +3 -1
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb.py +2 -4
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_connection.py +2 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_model_base.py +1 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/s3/s3_event_data.py +7 -7
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/s3/s3_object.py +2 -2
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/securityhub/securityhub.py +2 -2
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/utilities/serialization_utility.py +9 -4
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/utilities/string_utility.py +1 -0
- boto3_assist-0.12.0/src/boto3_assist/version.py +1 -0
- boto3_assist-0.12.0/tests/integration/cross_account_connection_test.py +78 -0
- boto3_assist-0.12.0/tests/integration/tenant.py +185 -0
- boto3_assist-0.12.0/tests/integration/tenant_services.py +48 -0
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dbmodels/cms/content_block.py +1 -1
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dbmodels/cms/page.py +1 -1
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dbmodels/cms/template.py +1 -1
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dynamodb_model_base_test.py +1 -1
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dynamodb_model_projections_test.py +2 -2
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dynamodb_model_serializtion_test.py +2 -2
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dynamodb_moto_sorting_test.py +2 -4
- boto3_assist-0.12.0/tests/unit/models_tests/models/person.py +26 -0
- boto3_assist-0.12.0/tests/unit/models_tests/models/user.py +66 -0
- boto3_assist-0.10.0/tests/models/serializable_model_test.py → boto3_assist-0.12.0/tests/unit/models_tests/serializable_model_person_test.py +11 -28
- boto3_assist-0.12.0/tests/unit/models_tests/serializable_model_user_test.py +54 -0
- boto3_assist-0.10.0/src/boto3_assist/version.py +0 -1
- boto3_assist-0.10.0/tests/__top/__init__.py +0 -25
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/.env.docker +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/.env.docker.001 +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/.env.docker.nosql.workbench +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/.env.unittest +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/.gitignore +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/.vscode/launch.json +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/.vscode/tasks.json +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/LICENSE-EXPLAINED.txt +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/LICENSE.txt +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/aws_regions_with_status.csv +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/aws_regions_with_status.json +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/devops/build.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/devops/readme.md +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/__init__.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/cloudwatch/log_report.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/models/order_item_model.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/models/order_model.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/models/product_model.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/models/user_model.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/models/user_post_model.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/order_example/main.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/order_example/products.json +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/services/order_item_service.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/services/order_service.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/services/product_service.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/services/table_service.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/services/user_post_service.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/services/user_service.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/services/user_service_client_example.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/services/user_service_resource_example.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/dynamodb/user_post_example/main.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/examples/ec2/regions_report.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/module-headers.txt +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/mypy.ini +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/requirements.txt +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/run-checks.sh +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/run_unit_tests.sh +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/__init__.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/aws_lambda/event_info.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/aws_lambda/mock_context.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/cloudwatch/cloudwatch_connection.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/cloudwatch/cloudwatch_log_connection.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/cloudwatch/cloudwatch_logs.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/cloudwatch/cloudwatch_query.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/cognito/cognito_authorizer.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/cognito/cognito_connection.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/cognito/jwks_cache.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/cognito/user.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/connection_tracker.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_helpers.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_importer.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_index.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_iservice.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_key.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_model_base_interfaces.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_reindexer.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.txt +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/readme.md +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/troubleshooting.md +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/ec2/ec2_connection.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/environment_services/__init__.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/environment_services/environment_loader.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/environment_services/environment_variables.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/errors/custom_exceptions.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/http_status_codes.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/models/serializable_model.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/s3/s3.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/s3/s3_bucket.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/s3/s3_connection.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/securityhub/securityhub_connection.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/ssm/connection.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/ssm/parameter_store/parameter_store.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/utilities/datetime_utility.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/utilities/dictionary_utility.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/utilities/file_operations.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/utilities/http_utility.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/utilities/logging_utility.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/utilities/numbers_utility.py +0 -0
- {boto3_assist-0.10.0 → boto3_assist-0.12.0}/tests/__init__.py +0 -0
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/__init__.py +0 -0
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dbmodels/cms/base.py +0 -0
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dbmodels/simple_model.py +0 -0
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dbmodels/user_model.py +0 -0
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dbmodels/user_required_fields_model.py +0 -0
- {boto3_assist-0.10.0/tests/dynamodb → boto3_assist-0.12.0/tests/unit/dynamodb_tests}/dynamodb_reindex_test.py +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/examples_test/__init__.py +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/examples_test/user_service_test.py +0 -0
- {boto3_assist-0.10.0/tests/lambda → boto3_assist-0.12.0/tests/unit/lambda_tests}/__init__.py +0 -0
- {boto3_assist-0.10.0/tests/lambda → boto3_assist-0.12.0/tests/unit/lambda_tests}/event_info_test.py +0 -0
- {boto3_assist-0.10.0/tests/models → boto3_assist-0.12.0/tests/unit/models_tests}/__init__.py +0 -0
- {boto3_assist-0.10.0/tests/models → boto3_assist-0.12.0/tests/unit/models_tests}/serializable_model_wide_test.py +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/parameter_store/__init__.py +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/parameter_store/parameter_store_test.py +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/s3/__init__.py +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/s3/files/test.txt +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/s3/s3_event_data_test.py +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/s3/s3_file_delete_test.py +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/s3/s3_file_upload_test.py +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/utilities/__init__.py +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/utilities/serialization_utility_test.py +0 -0
- {boto3_assist-0.10.0/tests → boto3_assist-0.12.0/tests/unit}/utilities/string_utility_test.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"python.testing.pytestEnabled":
|
|
3
|
-
"python.testing.unittestEnabled":
|
|
2
|
+
"python.testing.pytestEnabled": true,
|
|
3
|
+
"python.testing.unittestEnabled": false,
|
|
4
4
|
"python.testing.unittestArgs": [
|
|
5
5
|
"-v",
|
|
6
6
|
"-s",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"[python]": {
|
|
25
25
|
|
|
26
26
|
"editor.formatOnSave": true,
|
|
27
|
-
"editor.defaultFormatter": "
|
|
27
|
+
"editor.defaultFormatter": "ms-python.black-formatter",
|
|
28
28
|
},
|
|
29
29
|
|
|
30
30
|
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: boto3_assist
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Additional boto3 wrappers to make your life a little easier
|
|
5
5
|
Author-email: Eric Wilson <boto3-assist@geekcafe.com>
|
|
6
6
|
License-File: LICENSE-EXPLAINED.txt
|
|
7
7
|
License-File: LICENSE.txt
|
|
8
|
-
Classifier:
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
10
|
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python
|
|
10
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Software Development
|
|
11
14
|
Requires-Python: >=3.10
|
|
12
15
|
Requires-Dist: aws-lambda-powertools
|
|
13
16
|
Requires-Dist: aws-xray-sdk
|
|
@@ -23,6 +26,10 @@ Description-Content-Type: text/markdown
|
|
|
23
26
|
|
|
24
27
|
# boto3 assist
|
|
25
28
|
|
|
29
|
+
[](https://pypi.org/project/boto3-assist/)
|
|
30
|
+
[](https://opensource.org/licenses/MIT)
|
|
31
|
+
[](https://pepy.tech/project/boto3-assist)
|
|
32
|
+
|
|
26
33
|
This is in beta and subject to changes before it's initial 1.0.0 release
|
|
27
34
|
|
|
28
35
|
This libary was created to make life a little easier when using boto3.
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# boto3 assist
|
|
2
2
|
|
|
3
|
+
[](https://pypi.org/project/boto3-assist/)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://pepy.tech/project/boto3-assist)
|
|
6
|
+
|
|
3
7
|
This is in beta and subject to changes before it's initial 1.0.0 release
|
|
4
8
|
|
|
5
9
|
This libary was created to make life a little easier when using boto3.
|
|
@@ -8,10 +8,14 @@ packages = ["src/boto3_assist"]
|
|
|
8
8
|
[tool.pytest.ini_options]
|
|
9
9
|
pythonpath = ["src"]
|
|
10
10
|
testpaths = ["tests"]
|
|
11
|
+
markers = [
|
|
12
|
+
"integration: marks tests as integration (deselect with '-m \"not integration\"')"
|
|
13
|
+
]
|
|
14
|
+
addopts = "-m 'not integration'"
|
|
11
15
|
|
|
12
16
|
[project]
|
|
13
17
|
name = "boto3_assist"
|
|
14
|
-
version = "0.
|
|
18
|
+
version = "0.12.0"
|
|
15
19
|
|
|
16
20
|
authors = [
|
|
17
21
|
{ name="Eric Wilson", email="boto3-assist@geekcafe.com" }
|
|
@@ -21,8 +25,11 @@ readme = "README.md"
|
|
|
21
25
|
requires-python = ">=3.10"
|
|
22
26
|
classifiers = [
|
|
23
27
|
"Programming Language :: Python :: 3",
|
|
24
|
-
"License ::
|
|
28
|
+
"License :: OSI Approved :: MIT License",
|
|
29
|
+
"Development Status :: 4 - Beta",
|
|
25
30
|
"Operating System :: OS Independent",
|
|
31
|
+
"Programming Language :: Python",
|
|
32
|
+
"Topic :: Software Development"
|
|
26
33
|
]
|
|
27
34
|
|
|
28
35
|
dependencies = [
|
|
@@ -19,4 +19,5 @@ pkginfo # occasionally we need to upgrade this or we can get upload errors when
|
|
|
19
19
|
# the error may look like the following
|
|
20
20
|
# ERROR InvalidDistribution: Metadata is missing required fields: Name, Version.
|
|
21
21
|
# Make sure the distribution includes the files where those fields are specified, and is using a supported
|
|
22
|
-
# Metadata-Version: 1.0, 1.1, 1.2, 2.0, 2.1, 2.2, 2.3.
|
|
22
|
+
# Metadata-Version: 1.0, 1.1, 1.2, 2.0, 2.1, 2.2, 2.3.
|
|
23
|
+
pytest
|
|
@@ -27,7 +27,7 @@ class Boto3SessionManager:
|
|
|
27
27
|
aws_region: Optional[str] = None,
|
|
28
28
|
assume_role_arn: Optional[str] = None,
|
|
29
29
|
assume_role_session_name: Optional[str] = None,
|
|
30
|
-
cross_account_role_arn: Optional[str] = None,
|
|
30
|
+
# cross_account_role_arn: Optional[str] = None,
|
|
31
31
|
config: Optional[Config] = None,
|
|
32
32
|
aws_endpoint_url: Optional[str] = None,
|
|
33
33
|
aws_access_key_id: Optional[str] = None,
|
|
@@ -40,7 +40,7 @@ class Boto3SessionManager:
|
|
|
40
40
|
self.assume_role_arn = assume_role_arn
|
|
41
41
|
self.assume_role_session_name = assume_role_session_name
|
|
42
42
|
self.config = config
|
|
43
|
-
self.cross_account_role_arn = cross_account_role_arn
|
|
43
|
+
# # self.cross_account_role_arn = cross_account_role_arn
|
|
44
44
|
self.endpoint_url = aws_endpoint_url
|
|
45
45
|
self.aws_access_key_id = aws_access_key_id
|
|
46
46
|
self.aws_secret_access_key = aws_secret_access_key
|
|
@@ -57,36 +57,46 @@ class Boto3SessionManager:
|
|
|
57
57
|
|
|
58
58
|
profile = self.aws_profile or EnvironmentVariables.AWS.profile()
|
|
59
59
|
region = self.aws_region or EnvironmentVariables.AWS.region()
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
logger.debug("Connecting without assuming a role.")
|
|
64
|
-
self.__session = self.__get_aws_session(profile, region)
|
|
60
|
+
|
|
61
|
+
logger.debug("Connecting without assuming a role.")
|
|
62
|
+
self.__session = self.__get_aws_session(profile, region)
|
|
65
63
|
|
|
66
64
|
if profile:
|
|
67
65
|
print(f"Connecting with a profile: {profile}")
|
|
68
66
|
|
|
67
|
+
if self.assume_role_arn:
|
|
68
|
+
self.__assume_role()
|
|
69
|
+
|
|
69
70
|
def __assume_role(self):
|
|
70
71
|
"""Assume an AWS IAM role."""
|
|
71
72
|
try:
|
|
73
|
+
if not self.__session:
|
|
74
|
+
raise RuntimeError(
|
|
75
|
+
"Session must be established before assuming a role."
|
|
76
|
+
)
|
|
77
|
+
|
|
72
78
|
logger.debug(f"Assuming role {self.assume_role_arn}")
|
|
73
|
-
|
|
79
|
+
|
|
80
|
+
sts_client = self.__session.client("sts")
|
|
74
81
|
session_name = (
|
|
75
82
|
self.assume_role_session_name
|
|
76
83
|
or f"AssumeRoleSessionFor{self.service_name}"
|
|
77
84
|
)
|
|
78
|
-
|
|
79
|
-
raise ValueError("assume_role_arn is required")
|
|
85
|
+
|
|
80
86
|
assumed_role_response = sts_client.assume_role(
|
|
81
87
|
RoleArn=self.assume_role_arn,
|
|
82
88
|
RoleSessionName=session_name,
|
|
83
89
|
)
|
|
84
90
|
credentials = assumed_role_response["Credentials"]
|
|
91
|
+
|
|
92
|
+
# Now override the session with assumed credentials
|
|
85
93
|
self.__session = boto3.Session(
|
|
86
94
|
aws_access_key_id=credentials["AccessKeyId"],
|
|
87
95
|
aws_secret_access_key=credentials["SecretAccessKey"],
|
|
88
96
|
aws_session_token=credentials["SessionToken"],
|
|
97
|
+
region_name=self.aws_region,
|
|
89
98
|
)
|
|
99
|
+
logger.debug("Successfully assumed role and created new session.")
|
|
90
100
|
|
|
91
101
|
except Exception as e:
|
|
92
102
|
logger.error(f"Error assuming role: {e}")
|
|
@@ -117,9 +127,9 @@ class Boto3SessionManager:
|
|
|
117
127
|
"region": self.aws_region,
|
|
118
128
|
"aws_access_key_id": tmp_access_key_id,
|
|
119
129
|
"aws_secret_access_key": tmp_secret_access_key,
|
|
120
|
-
"aws_session_token":
|
|
121
|
-
|
|
122
|
-
|
|
130
|
+
"aws_session_token": (
|
|
131
|
+
"*******" if self.aws_session_token is not None else ""
|
|
132
|
+
),
|
|
123
133
|
}
|
|
124
134
|
)
|
|
125
135
|
logger.debug("Creating boto3 session")
|
|
@@ -5,7 +5,7 @@ MIT License. See Project Root for the license information.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import time
|
|
8
|
-
from typing import List, Dict, Any, Optional
|
|
8
|
+
from typing import List, Dict, Any, Optional, Literal
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
from aws_lambda_powertools import Logger
|
|
@@ -130,7 +130,7 @@ class CognitoUtility(CognitoConnection):
|
|
|
130
130
|
is_permanent=True,
|
|
131
131
|
)
|
|
132
132
|
|
|
133
|
-
return response
|
|
133
|
+
return dict(response)
|
|
134
134
|
|
|
135
135
|
except self.client.exceptions.UsernameExistsException as e:
|
|
136
136
|
logger.error(f"Error: {e.response['Error']['Message']}")
|
|
@@ -185,7 +185,7 @@ class CognitoUtility(CognitoConnection):
|
|
|
185
185
|
UserPoolId=user_pool_id, Username=user_name
|
|
186
186
|
)
|
|
187
187
|
|
|
188
|
-
return response
|
|
188
|
+
return dict(response)
|
|
189
189
|
|
|
190
190
|
def admin_enable_user(
|
|
191
191
|
self, user_name: str, user_pool_id: str, reset_password: bool = True
|
|
@@ -271,7 +271,7 @@ class CognitoUtility(CognitoConnection):
|
|
|
271
271
|
logger.debug(
|
|
272
272
|
f"User {email} created successfully. Confirmation code sent to {email}."
|
|
273
273
|
)
|
|
274
|
-
return response
|
|
274
|
+
return dict(response)
|
|
275
275
|
|
|
276
276
|
except self.client.exceptions.UsernameExistsException as e:
|
|
277
277
|
logger.error(f"Error: {e.response['Error']['Message']}")
|
|
@@ -324,11 +324,11 @@ class CognitoUtility(CognitoConnection):
|
|
|
324
324
|
user_pool_id,
|
|
325
325
|
client_name,
|
|
326
326
|
id_token_time_out=60,
|
|
327
|
-
id_token_units="minutes",
|
|
327
|
+
id_token_units: Literal["days", "hours", "minutes", "seconds"] = "minutes",
|
|
328
328
|
access_token_time_out=60,
|
|
329
|
-
access_token_units="minutes",
|
|
329
|
+
access_token_units: Literal["days", "hours", "minutes", "seconds"] = "minutes",
|
|
330
330
|
refresh_token_time_out=60,
|
|
331
|
-
refresh_token_units="minutes",
|
|
331
|
+
refresh_token_units: Literal["days", "hours", "minutes", "seconds"] = "minutes",
|
|
332
332
|
) -> dict:
|
|
333
333
|
# valid units: 'seconds'|'minutes'|'hours'|'days'
|
|
334
334
|
|
|
@@ -340,9 +340,9 @@ class CognitoUtility(CognitoConnection):
|
|
|
340
340
|
AccessTokenValidity=access_token_time_out,
|
|
341
341
|
IdTokenValidity=id_token_time_out,
|
|
342
342
|
TokenValidityUnits={
|
|
343
|
-
"AccessToken":
|
|
344
|
-
"IdToken":
|
|
345
|
-
"RefreshToken":
|
|
343
|
+
"AccessToken": access_token_units,
|
|
344
|
+
"IdToken": id_token_units,
|
|
345
|
+
"RefreshToken": refresh_token_units,
|
|
346
346
|
},
|
|
347
347
|
# ReadAttributes=[
|
|
348
348
|
# 'string',
|
|
@@ -381,18 +381,18 @@ class CognitoUtility(CognitoConnection):
|
|
|
381
381
|
# AuthSessionValidity=123
|
|
382
382
|
)
|
|
383
383
|
|
|
384
|
-
return response
|
|
384
|
+
return dict(response)
|
|
385
385
|
|
|
386
386
|
def search_cognito(self, email: str, user_pool_id: str) -> dict:
|
|
387
387
|
"""Search cognito for an existing user"""
|
|
388
388
|
|
|
389
|
-
email = self.__format_email(email=email)
|
|
389
|
+
email = self.__format_email(email=email) or ""
|
|
390
390
|
filter_string = f'email = "{email}"'
|
|
391
391
|
|
|
392
392
|
# Call the admin_list_users method with the filter
|
|
393
393
|
response = self.client.list_users(UserPoolId=user_pool_id, Filter=filter_string)
|
|
394
394
|
|
|
395
|
-
return response
|
|
395
|
+
return dict(response)
|
|
396
396
|
|
|
397
397
|
def __set_user_attributes(self, *, user: CognitoUser) -> List[dict]:
|
|
398
398
|
"""
|
|
@@ -30,6 +30,7 @@ class Connection:
|
|
|
30
30
|
aws_access_key_id: Optional[str] = None,
|
|
31
31
|
aws_secret_access_key: Optional[str] = None,
|
|
32
32
|
aws_end_point_url: Optional[str] = None,
|
|
33
|
+
assume_role_arn: Optional[str] = None,
|
|
33
34
|
) -> None:
|
|
34
35
|
self.__aws_profile = aws_profile
|
|
35
36
|
self.__aws_region = aws_region
|
|
@@ -37,7 +38,7 @@ class Connection:
|
|
|
37
38
|
self.__aws_secret_access_key = aws_secret_access_key
|
|
38
39
|
self.end_point_url = aws_end_point_url
|
|
39
40
|
self.__session: Boto3SessionManager | None = None
|
|
40
|
-
|
|
41
|
+
self.__assume_role_arn: Optional[str] = assume_role_arn
|
|
41
42
|
self.__service_name: str | None = service_name
|
|
42
43
|
|
|
43
44
|
if self.__service_name is None:
|
|
@@ -73,6 +74,7 @@ class Connection:
|
|
|
73
74
|
aws_access_key_id=self.aws_access_key_id,
|
|
74
75
|
aws_secret_access_key=self.aws_secret_access_key,
|
|
75
76
|
aws_endpoint_url=self.end_point_url,
|
|
77
|
+
assume_role_arn=self.__assume_role_arn,
|
|
76
78
|
)
|
|
77
79
|
|
|
78
80
|
tracker.add(service_name=self.service_name)
|
|
@@ -24,7 +24,6 @@ from boto3_assist.utilities.string_utility import StringUtility
|
|
|
24
24
|
logger = Logger()
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
|
|
28
27
|
class DynamoDB(DynamoDBConnection):
|
|
29
28
|
"""
|
|
30
29
|
DynamoDB. Wrapper for basic DynamoDB Connection and Actions
|
|
@@ -41,6 +40,7 @@ class DynamoDB(DynamoDBConnection):
|
|
|
41
40
|
aws_end_point_url: Optional[str] = None,
|
|
42
41
|
aws_access_key_id: Optional[str] = None,
|
|
43
42
|
aws_secret_access_key: Optional[str] = None,
|
|
43
|
+
assume_role_arn: Optional[str] = None,
|
|
44
44
|
) -> None:
|
|
45
45
|
super().__init__(
|
|
46
46
|
aws_profile=aws_profile,
|
|
@@ -48,6 +48,7 @@ class DynamoDB(DynamoDBConnection):
|
|
|
48
48
|
aws_end_point_url=aws_end_point_url,
|
|
49
49
|
aws_access_key_id=aws_access_key_id,
|
|
50
50
|
aws_secret_access_key=aws_secret_access_key,
|
|
51
|
+
assume_role_arn=assume_role_arn,
|
|
51
52
|
)
|
|
52
53
|
self.helpers: DynamoDBHelpers = DynamoDBHelpers()
|
|
53
54
|
self.log_dynamodb_item_size = (
|
|
@@ -55,7 +56,6 @@ class DynamoDB(DynamoDBConnection):
|
|
|
55
56
|
)
|
|
56
57
|
logger.setLevel(os.getenv("LOG_LEVEL", "INFO"))
|
|
57
58
|
|
|
58
|
-
|
|
59
59
|
def save(
|
|
60
60
|
self,
|
|
61
61
|
item: dict | DynamoDBModelBase,
|
|
@@ -169,7 +169,6 @@ class DynamoDB(DynamoDBConnection):
|
|
|
169
169
|
call_type: str = "resource",
|
|
170
170
|
) -> Dict[str, Any]: ...
|
|
171
171
|
|
|
172
|
-
|
|
173
172
|
def get(
|
|
174
173
|
self,
|
|
175
174
|
key: Optional[dict] = None,
|
|
@@ -344,7 +343,6 @@ class DynamoDB(DynamoDBConnection):
|
|
|
344
343
|
) -> dict:
|
|
345
344
|
pass
|
|
346
345
|
|
|
347
|
-
|
|
348
346
|
def delete(
|
|
349
347
|
self,
|
|
350
348
|
*,
|
{boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/dynamodb/dynamodb_connection.py
RENAMED
|
@@ -32,6 +32,7 @@ class DynamoDBConnection(Connection):
|
|
|
32
32
|
aws_end_point_url: Optional[str] = None,
|
|
33
33
|
aws_access_key_id: Optional[str] = None,
|
|
34
34
|
aws_secret_access_key: Optional[str] = None,
|
|
35
|
+
assume_role_arn: Optional[str] = None,
|
|
35
36
|
) -> None:
|
|
36
37
|
super().__init__(
|
|
37
38
|
service_name="dynamodb",
|
|
@@ -40,6 +41,7 @@ class DynamoDBConnection(Connection):
|
|
|
40
41
|
aws_access_key_id=aws_access_key_id,
|
|
41
42
|
aws_secret_access_key=aws_secret_access_key,
|
|
42
43
|
aws_end_point_url=aws_end_point_url,
|
|
44
|
+
assume_role_arn=assume_role_arn,
|
|
43
45
|
)
|
|
44
46
|
|
|
45
47
|
self.__dynamodb_client: DynamoDBClient | None = None
|
|
@@ -15,37 +15,37 @@ class EventData:
|
|
|
15
15
|
self.__event = event
|
|
16
16
|
|
|
17
17
|
@property
|
|
18
|
-
def version(self) -> str:
|
|
18
|
+
def version(self) -> str | None:
|
|
19
19
|
"""Event Version"""
|
|
20
20
|
return self.__event.get("version")
|
|
21
21
|
|
|
22
22
|
@property
|
|
23
|
-
def id(self) -> str:
|
|
23
|
+
def id(self) -> str | None:
|
|
24
24
|
"""Event Id"""
|
|
25
25
|
return self.__event.get("id")
|
|
26
26
|
|
|
27
27
|
@property
|
|
28
|
-
def detail_type(self) -> str:
|
|
28
|
+
def detail_type(self) -> str | None:
|
|
29
29
|
"""Event Detail Type"""
|
|
30
30
|
return self.__event.get("detail-type")
|
|
31
31
|
|
|
32
32
|
@property
|
|
33
|
-
def source(self) -> str:
|
|
33
|
+
def source(self) -> str | None:
|
|
34
34
|
"""Event Source"""
|
|
35
35
|
return self.__event.get("source")
|
|
36
36
|
|
|
37
37
|
@property
|
|
38
|
-
def account(self) -> str:
|
|
38
|
+
def account(self) -> str | None:
|
|
39
39
|
"""Event Account"""
|
|
40
40
|
return self.__event.get("account")
|
|
41
41
|
|
|
42
42
|
@property
|
|
43
|
-
def time(self) -> str:
|
|
43
|
+
def time(self) -> str | None:
|
|
44
44
|
"""Event Time"""
|
|
45
45
|
return self.__event.get("time")
|
|
46
46
|
|
|
47
47
|
@property
|
|
48
|
-
def region(self) -> str:
|
|
48
|
+
def region(self) -> str | None:
|
|
49
49
|
"""Event Region"""
|
|
50
50
|
return self.__event.get("region")
|
|
51
51
|
|
|
@@ -217,7 +217,7 @@ class S3Object:
|
|
|
217
217
|
)
|
|
218
218
|
try:
|
|
219
219
|
# convert if necessary
|
|
220
|
-
file_obj
|
|
220
|
+
file_obj = (
|
|
221
221
|
file_obj.encode("utf-8") if isinstance(file_obj, str) else file_obj
|
|
222
222
|
)
|
|
223
223
|
self.connection.client.upload_fileobj(
|
|
@@ -658,7 +658,7 @@ class S3Object:
|
|
|
658
658
|
Key=destination_key,
|
|
659
659
|
)
|
|
660
660
|
|
|
661
|
-
return response
|
|
661
|
+
return dict(response)
|
|
662
662
|
|
|
663
663
|
def move(
|
|
664
664
|
self,
|
|
@@ -5,7 +5,7 @@ MIT License. See Project Root for the license information.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import os
|
|
8
|
-
from typing import Optional
|
|
8
|
+
from typing import Optional, Literal
|
|
9
9
|
|
|
10
10
|
from aws_lambda_powertools import Logger
|
|
11
11
|
|
|
@@ -20,7 +20,7 @@ class SecurityHub(SecurityHubConnection):
|
|
|
20
20
|
def update_findings_status(
|
|
21
21
|
self,
|
|
22
22
|
region_name: str,
|
|
23
|
-
workflow_status:
|
|
23
|
+
workflow_status: Literal["NEW", "NOTIFIED", "RESOLVED", "SUPPRESSED"],
|
|
24
24
|
note_text: Optional[str] = None,
|
|
25
25
|
updated_by: Optional[str] = None,
|
|
26
26
|
):
|
{boto3_assist-0.10.0 → boto3_assist-0.12.0}/src/boto3_assist/utilities/serialization_utility.py
RENAMED
|
@@ -148,9 +148,11 @@ class JsonConversions:
|
|
|
148
148
|
elif isinstance(data, list):
|
|
149
149
|
# For lists, if deep conversion is enabled, process each element.
|
|
150
150
|
return [
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
(
|
|
152
|
+
JsonConversions._convert_keys(item, convert_func, deep)
|
|
153
|
+
if deep
|
|
154
|
+
else item
|
|
155
|
+
)
|
|
154
156
|
for item in data
|
|
155
157
|
]
|
|
156
158
|
else:
|
|
@@ -377,7 +379,10 @@ class Serialization:
|
|
|
377
379
|
setattr(target, "__actively_serializing_data__", True)
|
|
378
380
|
|
|
379
381
|
for key, value in source.items():
|
|
380
|
-
if
|
|
382
|
+
if isinstance(target, dict):
|
|
383
|
+
# our target is a dictionary, so we need to handle this differently
|
|
384
|
+
target[key] = value
|
|
385
|
+
elif Serialization.has_attribute(target, key):
|
|
381
386
|
attr = getattr(target, key)
|
|
382
387
|
expected_type = type(attr)
|
|
383
388
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.12.0'
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import os
|
|
3
|
+
from typing import List
|
|
4
|
+
from boto3_assist.dynamodb.dynamodb import DynamoDB
|
|
5
|
+
from tests.integration.tenant_services import TenantServices
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.mark.integration
|
|
9
|
+
def test_cross_account_role_assumption_with_profile():
|
|
10
|
+
responses = []
|
|
11
|
+
|
|
12
|
+
profile_name = os.getenv("AWS_PROFILE")
|
|
13
|
+
|
|
14
|
+
connections: List[dict] = [
|
|
15
|
+
{
|
|
16
|
+
"profile_name": profile_name,
|
|
17
|
+
"aws_account": "959096737760",
|
|
18
|
+
"aws_region": "us-east-1",
|
|
19
|
+
"role_name": "CrossAccountAccessRole",
|
|
20
|
+
"table_name": "db-us-east-1",
|
|
21
|
+
"enabled": False,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"profile_name": profile_name,
|
|
25
|
+
"aws_account": "959096737760",
|
|
26
|
+
"aws_region": "eu-west-2",
|
|
27
|
+
"role_name": "CrossAccountAccessRole",
|
|
28
|
+
"table_name": "db-eu-west-2",
|
|
29
|
+
"enabled": False,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"profile_name": profile_name,
|
|
33
|
+
"aws_account": "257932641017",
|
|
34
|
+
"aws_region": "us-east-1",
|
|
35
|
+
"role_name": "CrossAccountAccessRole",
|
|
36
|
+
"table_name": "aplos-nca-saas-production-demo-001-database",
|
|
37
|
+
"enabled": True,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"profile_name": profile_name,
|
|
41
|
+
"aws_region": "us-east-1",
|
|
42
|
+
"aws_account": "211125601483",
|
|
43
|
+
"role_name": "CrossAccountAccessRole",
|
|
44
|
+
"table_name": "aplos-nca-saas-production-app-database",
|
|
45
|
+
"enabled": True,
|
|
46
|
+
},
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
for connection in connections:
|
|
50
|
+
role_arn = (
|
|
51
|
+
f"arn:aws:iam::{connection['aws_account']}:role/{connection['role_name']}"
|
|
52
|
+
)
|
|
53
|
+
if connection["enabled"]:
|
|
54
|
+
db = DynamoDB(
|
|
55
|
+
aws_profile=connection["profile_name"],
|
|
56
|
+
aws_region=connection["aws_region"],
|
|
57
|
+
assume_role_arn=role_arn,
|
|
58
|
+
)
|
|
59
|
+
ts: TenantServices = TenantServices(
|
|
60
|
+
db=db, table_name=connection["table_name"]
|
|
61
|
+
)
|
|
62
|
+
response = ts.list()
|
|
63
|
+
responses.append(response)
|
|
64
|
+
# print(response)
|
|
65
|
+
else:
|
|
66
|
+
responses.append(None)
|
|
67
|
+
|
|
68
|
+
print(len(responses))
|
|
69
|
+
assert len(responses) == 3
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def main():
|
|
73
|
+
test_cross_account_role_assumption_with_profile()
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
main()
|