localstack-core 4.3.1.dev6__py3-none-any.whl → 4.3.1.dev28__py3-none-any.whl
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.
- localstack/aws/api/ec2/__init__.py +597 -0
- localstack/aws/api/events/__init__.py +18 -12
- localstack/aws/api/route53/__init__.py +2 -0
- localstack/aws/api/s3control/__init__.py +89 -0
- localstack/aws/api/transcribe/__init__.py +1 -0
- localstack/services/cloudformation/engine/entities.py +18 -1
- localstack/services/cloudformation/engine/template_deployer.py +0 -9
- localstack/services/cloudformation/engine/v2/change_set_model.py +164 -35
- localstack/services/cloudformation/engine/v2/change_set_model_describer.py +143 -69
- localstack/services/cloudformation/engine/v2/change_set_model_executor.py +170 -0
- localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +8 -0
- localstack/services/cloudformation/v2/provider.py +72 -6
- localstack/services/ec2/patches.py +31 -3
- localstack/services/events/provider.py +6 -1
- localstack/services/kms/models.py +1 -1
- localstack/services/lambda_/event_source_mapping/pollers/dynamodb_poller.py +2 -0
- localstack/services/lambda_/event_source_mapping/pollers/kinesis_poller.py +2 -0
- localstack/services/lambda_/event_source_mapping/pollers/stream_poller.py +4 -2
- localstack/services/lambda_/invocation/assignment.py +4 -2
- localstack/services/lambda_/invocation/execution_environment.py +16 -4
- localstack/services/lambda_/invocation/logs.py +28 -4
- localstack/services/lambda_/provider.py +18 -3
- localstack/services/lambda_/runtimes.py +15 -2
- localstack/services/s3/presigned_url.py +15 -11
- localstack/services/secretsmanager/provider.py +13 -4
- localstack/services/sqs/models.py +22 -3
- localstack/services/sqs/utils.py +16 -7
- localstack/services/ssm/resource_providers/aws_ssm_parameter.py +1 -5
- localstack/services/stepfunctions/asl/utils/json_path.py +9 -0
- localstack/testing/snapshots/transformer_utility.py +13 -0
- localstack/utils/aws/client_types.py +8 -0
- localstack/utils/docker_utils.py +2 -2
- localstack/version.py +2 -2
- {localstack_core-4.3.1.dev6.dist-info → localstack_core-4.3.1.dev28.dist-info}/METADATA +5 -5
- {localstack_core-4.3.1.dev6.dist-info → localstack_core-4.3.1.dev28.dist-info}/RECORD +43 -42
- localstack_core-4.3.1.dev28.dist-info/plux.json +1 -0
- localstack_core-4.3.1.dev6.dist-info/plux.json +0 -1
- {localstack_core-4.3.1.dev6.data → localstack_core-4.3.1.dev28.data}/scripts/localstack +0 -0
- {localstack_core-4.3.1.dev6.data → localstack_core-4.3.1.dev28.data}/scripts/localstack-supervisor +0 -0
- {localstack_core-4.3.1.dev6.data → localstack_core-4.3.1.dev28.data}/scripts/localstack.bat +0 -0
- {localstack_core-4.3.1.dev6.dist-info → localstack_core-4.3.1.dev28.dist-info}/WHEEL +0 -0
- {localstack_core-4.3.1.dev6.dist-info → localstack_core-4.3.1.dev28.dist-info}/entry_points.txt +0 -0
- {localstack_core-4.3.1.dev6.dist-info → localstack_core-4.3.1.dev28.dist-info}/licenses/LICENSE.txt +0 -0
- {localstack_core-4.3.1.dev6.dist-info → localstack_core-4.3.1.dev28.dist-info}/top_level.txt +0 -0
@@ -59,6 +59,7 @@ IMAGE_MAPPING: dict[Runtime, str] = {
|
|
59
59
|
Runtime.dotnet6: "dotnet:6",
|
60
60
|
Runtime.dotnetcore3_1: "dotnet:core3.1", # deprecated Apr 3, 2023 => Apr 3, 2023 => May 3, 2023
|
61
61
|
Runtime.go1_x: "go:1", # deprecated Jan 8, 2024 => Feb 8, 2024 => Mar 12, 2024
|
62
|
+
Runtime.ruby3_4: "ruby:3.4",
|
62
63
|
Runtime.ruby3_3: "ruby:3.3",
|
63
64
|
Runtime.ruby3_2: "ruby:3.2",
|
64
65
|
Runtime.ruby2_7: "ruby:2.7", # deprecated Dec 7, 2023 => Jan 9, 2024 => Feb 8, 2024
|
@@ -133,6 +134,7 @@ RUNTIMES_AGGREGATED = {
|
|
133
134
|
"ruby": [
|
134
135
|
Runtime.ruby3_2,
|
135
136
|
Runtime.ruby3_3,
|
137
|
+
Runtime.ruby3_4,
|
136
138
|
],
|
137
139
|
"dotnet": [
|
138
140
|
Runtime.dotnet6,
|
@@ -149,7 +151,18 @@ TESTED_RUNTIMES: list[Runtime] = [
|
|
149
151
|
runtime for runtime_group in RUNTIMES_AGGREGATED.values() for runtime in runtime_group
|
150
152
|
]
|
151
153
|
|
154
|
+
# An unordered list of snapstart-enabled runtimes. Related to snapshots in test_snapstart_exceptions
|
155
|
+
# https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html
|
156
|
+
SNAP_START_SUPPORTED_RUNTIMES = [
|
157
|
+
Runtime.java11,
|
158
|
+
Runtime.java17,
|
159
|
+
Runtime.java21,
|
160
|
+
Runtime.python3_12,
|
161
|
+
Runtime.python3_13,
|
162
|
+
Runtime.dotnet8,
|
163
|
+
]
|
164
|
+
|
152
165
|
# An ordered list of all Lambda runtimes considered valid by AWS. Matching snapshots in test_create_lambda_exceptions
|
153
|
-
VALID_RUNTIMES: str = "[nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9]"
|
166
|
+
VALID_RUNTIMES: str = "[nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9]"
|
154
167
|
# An ordered list of all Lambda runtimes for layers considered valid by AWS. Matching snapshots in test_layer_exceptions
|
155
|
-
VALID_LAYER_RUNTIMES: str = "[ruby2.6, dotnetcore1.0, python3.7, nodejs8.10, nasa, ruby2.7, python2.7-greengrass, dotnetcore2.0, python3.8, java21, dotnet6, dotnetcore2.1, python3.9, java11, nodejs6.10, provided, dotnetcore3.1, dotnet8, java17, nodejs, nodejs4.3, java8.al2, go1.x, nodejs20.x, go1.9, byol, nodejs10.x, provided.al2023, nodejs22.x, python3.10, java8, nodejs12.x, python3.11, nodejs8.x, python3.12, nodejs14.x, nodejs8.9, python3.13, nodejs16.x, provided.al2, nodejs4.3-edge, nodejs18.x, ruby3.2, python3.4, ruby3.3, ruby2.5, python3.6, python2.7]"
|
168
|
+
VALID_LAYER_RUNTIMES: str = "[ruby2.6, dotnetcore1.0, python3.7, nodejs8.10, nasa, ruby2.7, python2.7-greengrass, dotnetcore2.0, python3.8, java21, dotnet6, dotnetcore2.1, python3.9, java11, nodejs6.10, provided, dotnetcore3.1, dotnet8, java25, java17, nodejs, nodejs4.3, java8.al2, go1.x, dotnet10, nodejs20.x, go1.9, byol, nodejs10.x, provided.al2023, nodejs22.x, python3.10, java8, nodejs12.x, python3.11, nodejs24.x, nodejs8.x, python3.12, nodejs14.x, nodejs8.9, python3.13, python3.14, nodejs16.x, provided.al2, nodejs4.3-edge, nodejs18.x, ruby3.2, python3.4, ruby3.3, ruby3.4, ruby2.5, python3.6, python2.7]"
|
@@ -60,7 +60,7 @@ LOG = logging.getLogger(__name__)
|
|
60
60
|
|
61
61
|
SIGNATURE_V2_POST_FIELDS = [
|
62
62
|
"signature",
|
63
|
-
"
|
63
|
+
"awsaccesskeyid",
|
64
64
|
]
|
65
65
|
|
66
66
|
SIGNATURE_V4_POST_FIELDS = [
|
@@ -768,13 +768,17 @@ def validate_post_policy(
|
|
768
768
|
)
|
769
769
|
raise ex
|
770
770
|
|
771
|
-
|
771
|
+
form_dict = {k.lower(): v for k, v in request_form.items()}
|
772
|
+
|
773
|
+
policy = form_dict.get("policy")
|
774
|
+
if not policy:
|
772
775
|
# A POST request needs a policy except if the bucket is publicly writable
|
773
776
|
return
|
774
777
|
|
775
778
|
# TODO: this does validation of fields only for now
|
776
|
-
is_v4 = _is_match_with_signature_fields(
|
777
|
-
is_v2 = _is_match_with_signature_fields(
|
779
|
+
is_v4 = _is_match_with_signature_fields(form_dict, SIGNATURE_V4_POST_FIELDS)
|
780
|
+
is_v2 = _is_match_with_signature_fields(form_dict, SIGNATURE_V2_POST_FIELDS)
|
781
|
+
|
778
782
|
if not is_v2 and not is_v4:
|
779
783
|
ex: AccessDenied = AccessDenied("Access Denied")
|
780
784
|
ex.HostId = FAKE_HOST_ID
|
@@ -784,7 +788,7 @@ def validate_post_policy(
|
|
784
788
|
policy_decoded = json.loads(base64.b64decode(policy).decode("utf-8"))
|
785
789
|
except ValueError:
|
786
790
|
# this means the policy has been tampered with
|
787
|
-
signature =
|
791
|
+
signature = form_dict.get("signature") if is_v2 else form_dict.get("x-amz-signature")
|
788
792
|
credentials = get_credentials_from_parameters(request_form, "us-east-1")
|
789
793
|
ex: SignatureDoesNotMatch = create_signature_does_not_match_sig_v2(
|
790
794
|
request_signature=signature,
|
@@ -813,7 +817,6 @@ def validate_post_policy(
|
|
813
817
|
return
|
814
818
|
|
815
819
|
conditions = policy_decoded.get("conditions", [])
|
816
|
-
form_dict = {k.lower(): v for k, v in request_form.items()}
|
817
820
|
for condition in conditions:
|
818
821
|
if not _verify_condition(condition, form_dict, additional_policy_metadata):
|
819
822
|
str_condition = str(condition).replace("'", '"')
|
@@ -896,7 +899,7 @@ def _parse_policy_expiration_date(expiration_string: str) -> datetime.datetime:
|
|
896
899
|
|
897
900
|
|
898
901
|
def _is_match_with_signature_fields(
|
899
|
-
request_form:
|
902
|
+
request_form: dict[str, str], signature_fields: list[str]
|
900
903
|
) -> bool:
|
901
904
|
"""
|
902
905
|
Checks if the form contains at least one of the required fields passed in `signature_fields`
|
@@ -910,12 +913,13 @@ def _is_match_with_signature_fields(
|
|
910
913
|
for p in signature_fields:
|
911
914
|
if p not in request_form:
|
912
915
|
LOG.info("POST pre-sign missing fields")
|
913
|
-
# .capitalize() does not work here, because of AWSAccessKeyId casing
|
914
916
|
argument_name = (
|
915
|
-
capitalize_header_name_from_snake_case(p)
|
916
|
-
if "-" in p
|
917
|
-
else f"{p[0].upper()}{p[1:]}"
|
917
|
+
capitalize_header_name_from_snake_case(p) if "-" in p else p.capitalize()
|
918
918
|
)
|
919
|
+
# AWSAccessKeyId is a special case
|
920
|
+
if argument_name == "Awsaccesskeyid":
|
921
|
+
argument_name = "AWSAccessKeyId"
|
922
|
+
|
919
923
|
ex: InvalidArgument = _create_invalid_argument_exc(
|
920
924
|
message=f"Bucket POST must contain a field named '{argument_name}'. If it is specified, please check the order of the fields.",
|
921
925
|
name=argument_name,
|
@@ -729,17 +729,28 @@ def backend_rotate_secret(
|
|
729
729
|
if not self._is_valid_identifier(secret_id):
|
730
730
|
raise SecretNotFoundException()
|
731
731
|
|
732
|
-
|
732
|
+
secret = self.secrets[secret_id]
|
733
|
+
if secret.is_deleted():
|
733
734
|
raise InvalidRequestException(
|
734
735
|
"An error occurred (InvalidRequestException) when calling the RotateSecret operation: You tried to \
|
735
736
|
perform the operation on a secret that's currently marked deleted."
|
736
737
|
)
|
738
|
+
# Resolve rotation_lambda_arn and fallback to previous value if its missing
|
739
|
+
# from the current request
|
740
|
+
rotation_lambda_arn = rotation_lambda_arn or secret.rotation_lambda_arn
|
741
|
+
if not rotation_lambda_arn:
|
742
|
+
raise InvalidRequestException(
|
743
|
+
"No Lambda rotation function ARN is associated with this secret."
|
744
|
+
)
|
737
745
|
|
738
746
|
if rotation_lambda_arn:
|
739
747
|
if len(rotation_lambda_arn) > 2048:
|
740
748
|
msg = "RotationLambdaARN must <= 2048 characters long."
|
741
749
|
raise InvalidParameterException(msg)
|
742
750
|
|
751
|
+
# In case rotation_period is not provided, resolve auto_rotate_after_days
|
752
|
+
# and fallback to previous value if its missing from the current request.
|
753
|
+
rotation_period = secret.auto_rotate_after_days or 0
|
743
754
|
if rotation_rules:
|
744
755
|
if rotation_days in rotation_rules:
|
745
756
|
rotation_period = rotation_rules[rotation_days]
|
@@ -753,8 +764,6 @@ def backend_rotate_secret(
|
|
753
764
|
except Exception:
|
754
765
|
raise ResourceNotFoundException("Lambda does not exist or could not be accessed")
|
755
766
|
|
756
|
-
secret = self.secrets[secret_id]
|
757
|
-
|
758
767
|
# The rotation function must end with the versions of the secret in
|
759
768
|
# one of two states:
|
760
769
|
#
|
@@ -782,7 +791,7 @@ def backend_rotate_secret(
|
|
782
791
|
pass
|
783
792
|
|
784
793
|
secret.rotation_lambda_arn = rotation_lambda_arn
|
785
|
-
secret.auto_rotate_after_days =
|
794
|
+
secret.auto_rotate_after_days = rotation_period
|
786
795
|
if secret.auto_rotate_after_days > 0:
|
787
796
|
wait_interval_s = int(rotation_period) * 86400
|
788
797
|
secret.next_rotation_date = int(time.time()) + wait_interval_s
|
@@ -30,9 +30,9 @@ from localstack.services.sqs.exceptions import (
|
|
30
30
|
)
|
31
31
|
from localstack.services.sqs.queue import InterruptiblePriorityQueue, InterruptibleQueue
|
32
32
|
from localstack.services.sqs.utils import (
|
33
|
-
decode_receipt_handle,
|
34
33
|
encode_move_task_handle,
|
35
34
|
encode_receipt_handle,
|
35
|
+
extract_receipt_handle_info,
|
36
36
|
global_message_sequence,
|
37
37
|
guess_endpoint_strategy_and_host,
|
38
38
|
is_message_deduplication_id_required,
|
@@ -445,7 +445,7 @@ class SqsQueue:
|
|
445
445
|
return len(self.delayed)
|
446
446
|
|
447
447
|
def validate_receipt_handle(self, receipt_handle: str):
|
448
|
-
if self.arn !=
|
448
|
+
if self.arn != extract_receipt_handle_info(receipt_handle).queue_arn:
|
449
449
|
raise ReceiptHandleIsInvalid(
|
450
450
|
f'The input receipt handle "{receipt_handle}" is not a valid receipt handle.'
|
451
451
|
)
|
@@ -490,6 +490,7 @@ class SqsQueue:
|
|
490
490
|
return
|
491
491
|
|
492
492
|
standard_message = self.receipts[receipt_handle]
|
493
|
+
self._pre_delete_checks(standard_message, receipt_handle)
|
493
494
|
standard_message.deleted = True
|
494
495
|
LOG.debug(
|
495
496
|
"deleting message %s from queue %s",
|
@@ -724,6 +725,18 @@ class SqsQueue:
|
|
724
725
|
|
725
726
|
return expired
|
726
727
|
|
728
|
+
def _pre_delete_checks(self, standard_message: SqsMessage, receipt_handle: str) -> None:
|
729
|
+
"""
|
730
|
+
Runs any potential checks if a message that has been successfully identified via a receipt handle
|
731
|
+
is indeed supposed to be deleted.
|
732
|
+
For example, a receipt handle that has expired might not lead to deletion.
|
733
|
+
|
734
|
+
:param standard_message: The message to be deleted
|
735
|
+
:param receipt_handle: The handle associated with the message
|
736
|
+
:return: None. Potential violations raise errors.
|
737
|
+
"""
|
738
|
+
pass
|
739
|
+
|
727
740
|
|
728
741
|
class StandardQueue(SqsQueue):
|
729
742
|
visible: InterruptiblePriorityQueue[SqsMessage]
|
@@ -1001,9 +1014,15 @@ class FifoQueue(SqsQueue):
|
|
1001
1014
|
for message in self.delayed:
|
1002
1015
|
message.delay_seconds = value
|
1003
1016
|
|
1017
|
+
def _pre_delete_checks(self, message: SqsMessage, receipt_handle: str) -> None:
|
1018
|
+
_, _, _, last_received = extract_receipt_handle_info(receipt_handle)
|
1019
|
+
if time.time() - float(last_received) > message.visibility_timeout:
|
1020
|
+
raise InvalidParameterValueException(
|
1021
|
+
f"Value {receipt_handle} for parameter ReceiptHandle is invalid. Reason: The receipt handle has expired."
|
1022
|
+
)
|
1023
|
+
|
1004
1024
|
def remove(self, receipt_handle: str):
|
1005
1025
|
self.validate_receipt_handle(receipt_handle)
|
1006
|
-
decode_receipt_handle(receipt_handle)
|
1007
1026
|
|
1008
1027
|
super().remove(receipt_handle)
|
1009
1028
|
|
localstack/services/sqs/utils.py
CHANGED
@@ -3,7 +3,7 @@ import itertools
|
|
3
3
|
import json
|
4
4
|
import re
|
5
5
|
import time
|
6
|
-
from typing import Literal, Optional, Tuple
|
6
|
+
from typing import Literal, NamedTuple, Optional, Tuple
|
7
7
|
from urllib.parse import urlparse
|
8
8
|
|
9
9
|
from localstack.aws.api.sqs import QueueAttributeName, ReceiptHandleIsInvalid
|
@@ -116,16 +116,25 @@ def parse_queue_url(queue_url: str) -> Tuple[str, Optional[str], str]:
|
|
116
116
|
return account_id, region, queue_name
|
117
117
|
|
118
118
|
|
119
|
-
|
119
|
+
class ReceiptHandleInformation(NamedTuple):
|
120
|
+
identifier: str
|
121
|
+
queue_arn: str
|
122
|
+
message_id: str
|
123
|
+
last_received: str
|
124
|
+
|
125
|
+
|
126
|
+
def extract_receipt_handle_info(receipt_handle: str) -> ReceiptHandleInformation:
|
120
127
|
try:
|
121
128
|
handle = base64.b64decode(receipt_handle).decode("utf-8")
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
129
|
+
parts = handle.split(" ")
|
130
|
+
if len(parts) != 4:
|
131
|
+
raise ValueError(f'The input receipt handle "{receipt_handle}" is incomplete.')
|
132
|
+
parse_arn(parts[1])
|
133
|
+
return ReceiptHandleInformation(*parts)
|
134
|
+
except (IndexError, ValueError) as e:
|
126
135
|
raise ReceiptHandleIsInvalid(
|
127
136
|
f'The input receipt handle "{receipt_handle}" is not a valid receipt handle.'
|
128
|
-
)
|
137
|
+
) from e
|
129
138
|
|
130
139
|
|
131
140
|
def encode_receipt_handle(queue_arn, message) -> str:
|
@@ -177,11 +177,7 @@ class SSMParameterProvider(ResourceProvider[SSMParameterProperties]):
|
|
177
177
|
|
178
178
|
ssm.put_parameter(Overwrite=True, Tags=[], **update_config_props)
|
179
179
|
|
180
|
-
return
|
181
|
-
status=OperationStatus.SUCCESS,
|
182
|
-
resource_model=model,
|
183
|
-
custom_context=request.custom_context,
|
184
|
-
)
|
180
|
+
return self.read(request)
|
185
181
|
|
186
182
|
def update_tags(self, ssm, model, new_tags):
|
187
183
|
current_tags = ssm.list_tags_for_resource(
|
@@ -7,6 +7,7 @@ from jsonpath_ng.jsonpath import Index
|
|
7
7
|
from localstack.services.events.utils import to_json_str
|
8
8
|
|
9
9
|
_PATTERN_SINGLETON_ARRAY_ACCESS_OUTPUT: Final[str] = r"\[\d+\]$"
|
10
|
+
_PATTERN_SLICE_OR_WILDCARD_ACCESS = r"\$(?:\.[^[]+\[(?:\*|\d*:\d*)\]|\[\*\])(?:\.[^[]+)*$"
|
10
11
|
|
11
12
|
|
12
13
|
def _is_singleton_array_access(path: str) -> bool:
|
@@ -14,6 +15,12 @@ def _is_singleton_array_access(path: str) -> bool:
|
|
14
15
|
return bool(re.search(_PATTERN_SINGLETON_ARRAY_ACCESS_OUTPUT, path))
|
15
16
|
|
16
17
|
|
18
|
+
def _contains_slice_or_wildcard_array(path: str) -> bool:
|
19
|
+
# Returns true if the json path contains a slice or wildcard in the array.
|
20
|
+
# Slices at the root are discarded, but wildcard at the root is allowed.
|
21
|
+
return bool(re.search(_PATTERN_SLICE_OR_WILDCARD_ACCESS, path))
|
22
|
+
|
23
|
+
|
17
24
|
class NoSuchJsonPathError(Exception):
|
18
25
|
json_path: Final[str]
|
19
26
|
data: Final[Any]
|
@@ -42,6 +49,8 @@ def extract_json(path: str, data: Any) -> Any:
|
|
42
49
|
|
43
50
|
matches = input_expr.find(data)
|
44
51
|
if not matches:
|
52
|
+
if _contains_slice_or_wildcard_array(path):
|
53
|
+
return []
|
45
54
|
raise NoSuchJsonPathError(json_path=path, data=data)
|
46
55
|
|
47
56
|
if len(matches) > 1 or isinstance(matches[0].path, Index):
|
@@ -648,6 +648,19 @@ class TransformerUtility:
|
|
648
648
|
),
|
649
649
|
"version_uuid",
|
650
650
|
),
|
651
|
+
KeyValueBasedTransformer(
|
652
|
+
lambda k, v: (
|
653
|
+
v
|
654
|
+
if (
|
655
|
+
isinstance(k, str)
|
656
|
+
and k == "RotationLambdaARN"
|
657
|
+
and isinstance(v, str)
|
658
|
+
and re.match(PATTERN_ARN, v)
|
659
|
+
)
|
660
|
+
else None
|
661
|
+
),
|
662
|
+
"lambda-arn",
|
663
|
+
),
|
651
664
|
SortingTransformer("VersionStages"),
|
652
665
|
SortingTransformer("Versions", lambda e: e.get("CreatedDate")),
|
653
666
|
]
|
@@ -31,6 +31,7 @@ if TYPE_CHECKING:
|
|
31
31
|
from mypy_boto3_cloudwatch import CloudWatchClient
|
32
32
|
from mypy_boto3_codebuild import CodeBuildClient
|
33
33
|
from mypy_boto3_codecommit import CodeCommitClient
|
34
|
+
from mypy_boto3_codeconnections import CodeConnectionsClient
|
34
35
|
from mypy_boto3_codedeploy import CodeDeployClient
|
35
36
|
from mypy_boto3_codepipeline import CodePipelineClient
|
36
37
|
from mypy_boto3_codestar_connections import CodeStarconnectionsClient
|
@@ -109,6 +110,7 @@ if TYPE_CHECKING:
|
|
109
110
|
from mypy_boto3_timestream_query import TimestreamQueryClient
|
110
111
|
from mypy_boto3_timestream_write import TimestreamWriteClient
|
111
112
|
from mypy_boto3_transcribe import TranscribeServiceClient
|
113
|
+
from mypy_boto3_verifiedpermissions import VerifiedPermissionsClient
|
112
114
|
from mypy_boto3_wafv2 import WAFV2Client
|
113
115
|
from mypy_boto3_xray import XRayClient
|
114
116
|
|
@@ -139,6 +141,9 @@ class TypedServiceClientFactory(abc.ABC):
|
|
139
141
|
cloudwatch: Union["CloudWatchClient", "MetadataRequestInjector[CloudWatchClient]"]
|
140
142
|
codebuild: Union["CodeBuildClient", "MetadataRequestInjector[CodeBuildClient]"]
|
141
143
|
codecommit: Union["CodeCommitClient", "MetadataRequestInjector[CodeCommitClient]"]
|
144
|
+
codeconnections: Union[
|
145
|
+
"CodeConnectionsClient", "MetadataRequestInjector[CodeConnectionsClient]"
|
146
|
+
]
|
142
147
|
codedeploy: Union["CodeDeployClient", "MetadataRequestInjector[CodeDeployClient]"]
|
143
148
|
codepipeline: Union["CodePipelineClient", "MetadataRequestInjector[CodePipelineClient]"]
|
144
149
|
codestar_connections: Union[
|
@@ -255,6 +260,9 @@ class TypedServiceClientFactory(abc.ABC):
|
|
255
260
|
"TimestreamWriteClient", "MetadataRequestInjector[TimestreamWriteClient]"
|
256
261
|
]
|
257
262
|
transcribe: Union["TranscribeServiceClient", "MetadataRequestInjector[TranscribeServiceClient]"]
|
263
|
+
verifiedpermissions: Union[
|
264
|
+
"VerifiedPermissionsClient", "MetadataRequestInjector[VerifiedPermissionsClient]"
|
265
|
+
]
|
258
266
|
wafv2: Union["WAFV2Client", "MetadataRequestInjector[WAFV2Client]"]
|
259
267
|
xray: Union["XRayClient", "MetadataRequestInjector[XRayClient]"]
|
260
268
|
|
localstack/utils/docker_utils.py
CHANGED
@@ -156,14 +156,14 @@ def container_ports_can_be_bound(
|
|
156
156
|
except Exception as e:
|
157
157
|
if "port is already allocated" not in str(e) and "address already in use" not in str(e):
|
158
158
|
LOG.warning(
|
159
|
-
"Unexpected error when attempting to determine container port status
|
159
|
+
"Unexpected error when attempting to determine container port status", exc_info=e
|
160
160
|
)
|
161
161
|
return False
|
162
162
|
# TODO(srw): sometimes the command output from the docker container is "None", particularly when this function is
|
163
163
|
# invoked multiple times consecutively. Work out why.
|
164
164
|
if to_str(result[0] or "").strip() != "test123":
|
165
165
|
LOG.warning(
|
166
|
-
"Unexpected output when attempting to determine container port status: %s", result
|
166
|
+
"Unexpected output when attempting to determine container port status: %s", result
|
167
167
|
)
|
168
168
|
return True
|
169
169
|
|
localstack/version.py
CHANGED
@@ -17,5 +17,5 @@ __version__: str
|
|
17
17
|
__version_tuple__: VERSION_TUPLE
|
18
18
|
version_tuple: VERSION_TUPLE
|
19
19
|
|
20
|
-
__version__ = version = '4.3.1.
|
21
|
-
__version_tuple__ = version_tuple = (4, 3, 1, '
|
20
|
+
__version__ = version = '4.3.1.dev28'
|
21
|
+
__version_tuple__ = version_tuple = (4, 3, 1, 'dev28')
|
@@ -1,15 +1,15 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: localstack-core
|
3
|
-
Version: 4.3.1.
|
3
|
+
Version: 4.3.1.dev28
|
4
4
|
Summary: The core library and runtime of LocalStack
|
5
5
|
Author-email: LocalStack Contributors <info@localstack.cloud>
|
6
|
+
License-Expression: Apache-2.0
|
6
7
|
Project-URL: Homepage, https://localstack.cloud
|
7
8
|
Project-URL: Documentation, https://docs.localstack.cloud
|
8
9
|
Project-URL: Repository, https://github.com/localstack/localstack.git
|
9
10
|
Project-URL: Issues, https://github.com/localstack/localstack/issues
|
10
11
|
Classifier: Programming Language :: Python :: 3
|
11
12
|
Classifier: Programming Language :: Python :: 3.11
|
12
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
13
13
|
Classifier: Topic :: Internet
|
14
14
|
Classifier: Topic :: Software Development :: Testing
|
15
15
|
Classifier: Topic :: System :: Emulators
|
@@ -31,8 +31,8 @@ Requires-Dist: requests>=2.20.0
|
|
31
31
|
Requires-Dist: semver>=2.10
|
32
32
|
Requires-Dist: tailer>=0.4.1
|
33
33
|
Provides-Extra: base-runtime
|
34
|
-
Requires-Dist: boto3==1.37.
|
35
|
-
Requires-Dist: botocore==1.37.
|
34
|
+
Requires-Dist: boto3==1.37.28; extra == "base-runtime"
|
35
|
+
Requires-Dist: botocore==1.37.28; extra == "base-runtime"
|
36
36
|
Requires-Dist: awscrt>=0.13.14; extra == "base-runtime"
|
37
37
|
Requires-Dist: cbor2>=5.5.0; extra == "base-runtime"
|
38
38
|
Requires-Dist: dnspython>=1.16.0; extra == "base-runtime"
|
@@ -93,5 +93,5 @@ Requires-Dist: ruff>=0.3.3; extra == "dev"
|
|
93
93
|
Requires-Dist: rstr>=3.2.0; extra == "dev"
|
94
94
|
Provides-Extra: typehint
|
95
95
|
Requires-Dist: localstack-core[dev]; extra == "typehint"
|
96
|
-
Requires-Dist: boto3-stubs[acm,acm-pca,amplify,apigateway,apigatewayv2,appconfig,appconfigdata,application-autoscaling,appsync,athena,autoscaling,backup,batch,ce,cloudcontrol,cloudformation,cloudfront,cloudtrail,cloudwatch,codebuild,codecommit,codedeploy,codepipeline,codestar-connections,cognito-identity,cognito-idp,dms,docdb,dynamodb,dynamodbstreams,ec2,ecr,ecs,efs,eks,elasticache,elasticbeanstalk,elbv2,emr,emr-serverless,es,events,firehose,fis,glacier,glue,iam,identitystore,iot,iot-data,iotanalytics,iotwireless,kafka,kinesis,kinesisanalytics,kinesisanalyticsv2,kms,lakeformation,lambda,logs,managedblockchain,mediaconvert,mediastore,mq,mwaa,neptune,opensearch,organizations,pi,pinpoint,pipes,qldb,qldb-session,rds,rds-data,redshift,redshift-data,resource-groups,resourcegroupstaggingapi,route53,route53resolver,s3,s3control,sagemaker,sagemaker-runtime,secretsmanager,serverlessrepo,servicediscovery,ses,sesv2,sns,sqs,ssm,sso-admin,stepfunctions,sts,timestream-query,timestream-write,transcribe,wafv2,xray]; extra == "typehint"
|
96
|
+
Requires-Dist: boto3-stubs[acm,acm-pca,amplify,apigateway,apigatewayv2,appconfig,appconfigdata,application-autoscaling,appsync,athena,autoscaling,backup,batch,ce,cloudcontrol,cloudformation,cloudfront,cloudtrail,cloudwatch,codebuild,codecommit,codeconnections,codedeploy,codepipeline,codestar-connections,cognito-identity,cognito-idp,dms,docdb,dynamodb,dynamodbstreams,ec2,ecr,ecs,efs,eks,elasticache,elasticbeanstalk,elbv2,emr,emr-serverless,es,events,firehose,fis,glacier,glue,iam,identitystore,iot,iot-data,iotanalytics,iotwireless,kafka,kinesis,kinesisanalytics,kinesisanalyticsv2,kms,lakeformation,lambda,logs,managedblockchain,mediaconvert,mediastore,mq,mwaa,neptune,opensearch,organizations,pi,pinpoint,pipes,qldb,qldb-session,rds,rds-data,redshift,redshift-data,resource-groups,resourcegroupstaggingapi,route53,route53resolver,s3,s3control,sagemaker,sagemaker-runtime,secretsmanager,serverlessrepo,servicediscovery,ses,sesv2,sns,sqs,ssm,sso-admin,stepfunctions,sts,timestream-query,timestream-write,transcribe,verifiedpermissions,wafv2,xray]; extra == "typehint"
|
97
97
|
Dynamic: license-file
|