localstack-core 4.13.2.dev59__py3-none-any.whl → 4.13.2.dev61__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.
@@ -61,7 +61,13 @@ class IAMManagedPolicyProvider(ResourceProvider[IAMManagedPolicyProperties]):
61
61
  group_name = util.generate_default_name(request.stack_name, request.logical_resource_id)
62
62
  model["ManagedPolicyName"] = group_name
63
63
 
64
- policy_doc = json.dumps(util.remove_none_values(model["PolicyDocument"]))
64
+ # PolicyDocument can be either a dict or a JSON string (e.g., from Fn::Sub)
65
+ policy_document = model["PolicyDocument"]
66
+ if isinstance(policy_document, str):
67
+ policy_doc = policy_document
68
+ else:
69
+ policy_doc = json.dumps(util.remove_none_values(policy_document))
70
+
65
71
  policy = iam_client.create_policy(
66
72
  PolicyName=model["ManagedPolicyName"], PolicyDocument=policy_doc
67
73
  )
@@ -53,7 +53,13 @@ class IAMPolicyProvider(ResourceProvider[IAMPolicyProperties]):
53
53
  model = request.desired_state
54
54
  iam_client = request.aws_client_factory.iam
55
55
 
56
- policy_doc = json.dumps(util.remove_none_values(model["PolicyDocument"]))
56
+ # PolicyDocument can be either a dict or a JSON string (e.g., from Fn::Sub)
57
+ policy_document = model["PolicyDocument"]
58
+ if isinstance(policy_document, str):
59
+ policy_doc = policy_document
60
+ else:
61
+ policy_doc = json.dumps(util.remove_none_values(policy_document))
62
+
57
63
  policy_name = model["PolicyName"]
58
64
 
59
65
  if not any([model.get("Roles"), model.get("Users"), model.get("Groups")]):
@@ -122,7 +128,14 @@ class IAMPolicyProvider(ResourceProvider[IAMPolicyProperties]):
122
128
  iam_client = request.aws_client_factory.iam
123
129
  model = request.desired_state
124
130
  # FIXME: this wasn't properly implemented before as well, still needs to be rewritten
125
- policy_doc = json.dumps(util.remove_none_values(model["PolicyDocument"]))
131
+
132
+ # PolicyDocument can be either a dict or a JSON string (e.g., from Fn::Sub)
133
+ policy_document = model["PolicyDocument"]
134
+ if isinstance(policy_document, str):
135
+ policy_doc = policy_document
136
+ else:
137
+ policy_doc = json.dumps(util.remove_none_values(policy_document))
138
+
126
139
  policy_name = model["PolicyName"]
127
140
 
128
141
  for role in model.get("Roles", []):
@@ -276,7 +276,9 @@ from localstack.services.s3.utils import (
276
276
  base_64_content_md5_to_etag,
277
277
  create_redirect_for_post_request,
278
278
  create_s3_kms_managed_key_for_region,
279
+ decode_continuation_token,
279
280
  decode_user_metadata,
281
+ encode_continuation_token,
280
282
  encode_user_metadata,
281
283
  etag_to_base_64_content_md5,
282
284
  extract_bucket_key_version_id_from_copy_source,
@@ -321,6 +323,7 @@ from localstack.services.s3.validation import (
321
323
  validate_canned_acl,
322
324
  validate_checksum_value,
323
325
  validate_cors_configuration,
326
+ validate_encoding_type,
324
327
  validate_inventory_configuration,
325
328
  validate_lifecycle_configuration,
326
329
  validate_object_key,
@@ -1722,6 +1725,7 @@ class S3Provider(S3Api, ServiceLifecycleHook):
1722
1725
  **kwargs,
1723
1726
  ) -> ListObjectsOutput:
1724
1727
  store, s3_bucket = self._get_cross_account_bucket(context, bucket)
1728
+ validate_encoding_type(encoding_type)
1725
1729
 
1726
1730
  common_prefixes = set()
1727
1731
  count = 0
@@ -1730,7 +1734,7 @@ class S3Provider(S3Api, ServiceLifecycleHook):
1730
1734
  max_keys = max_keys or 1000
1731
1735
  prefix = prefix or ""
1732
1736
  delimiter = delimiter or ""
1733
- if encoding_type:
1737
+ if encoding_type == EncodingType.url:
1734
1738
  prefix = urlparse.quote(prefix)
1735
1739
  delimiter = urlparse.quote(delimiter)
1736
1740
 
@@ -1839,6 +1843,7 @@ class S3Provider(S3Api, ServiceLifecycleHook):
1839
1843
  "The continuation token provided is incorrect",
1840
1844
  ArgumentName="continuation-token",
1841
1845
  )
1846
+ validate_encoding_type(encoding_type)
1842
1847
 
1843
1848
  common_prefixes = set()
1844
1849
  count = 0
@@ -1847,14 +1852,14 @@ class S3Provider(S3Api, ServiceLifecycleHook):
1847
1852
  max_keys = max_keys or 1000
1848
1853
  prefix = prefix or ""
1849
1854
  delimiter = delimiter or ""
1850
- if encoding_type:
1855
+ start_after = start_after or ""
1856
+ decoded_continuation_token = decode_continuation_token(continuation_token)
1857
+
1858
+ if encoding_type == EncodingType.url:
1851
1859
  prefix = urlparse.quote(prefix)
1852
1860
  delimiter = urlparse.quote(delimiter)
1853
- decoded_continuation_token = (
1854
- to_str(base64.urlsafe_b64decode(continuation_token.encode()))
1855
- if continuation_token
1856
- else None
1857
- )
1861
+ start_after = urlparse.quote(start_after)
1862
+ decoded_continuation_token = urlparse.quote(decoded_continuation_token)
1858
1863
 
1859
1864
  s3_objects: list[Object] = []
1860
1865
 
@@ -1890,7 +1895,7 @@ class S3Provider(S3Api, ServiceLifecycleHook):
1890
1895
  # After skipping all entries, verify we're not over the MaxKeys before adding a new entry
1891
1896
  if count >= max_keys:
1892
1897
  is_truncated = True
1893
- next_continuation_token = to_str(base64.urlsafe_b64encode(s3_object.key.encode()))
1898
+ next_continuation_token = encode_continuation_token(s3_object.key)
1894
1899
  break
1895
1900
 
1896
1901
  # if we found a new CommonPrefix, add it to the CommonPrefixes
@@ -1971,6 +1976,7 @@ class S3Provider(S3Api, ServiceLifecycleHook):
1971
1976
  ArgumentName="version-id-marker",
1972
1977
  ArgumentValue=version_id_marker,
1973
1978
  )
1979
+ validate_encoding_type(encoding_type)
1974
1980
 
1975
1981
  store, s3_bucket = self._get_cross_account_bucket(context, bucket)
1976
1982
  common_prefixes = set()
@@ -1981,7 +1987,7 @@ class S3Provider(S3Api, ServiceLifecycleHook):
1981
1987
  max_keys = max_keys or 1000
1982
1988
  prefix = prefix or ""
1983
1989
  delimiter = delimiter or ""
1984
- if encoding_type:
1990
+ if encoding_type == EncodingType.url:
1985
1991
  prefix = urlparse.quote(prefix)
1986
1992
  delimiter = urlparse.quote(delimiter)
1987
1993
  version_key_marker_found = False
@@ -2968,6 +2974,7 @@ class S3Provider(S3Api, ServiceLifecycleHook):
2968
2974
  **kwargs,
2969
2975
  ) -> ListMultipartUploadsOutput:
2970
2976
  store, s3_bucket = self._get_cross_account_bucket(context, bucket)
2977
+ validate_encoding_type(encoding_type)
2971
2978
 
2972
2979
  common_prefixes = set()
2973
2980
  count = 0
@@ -2975,7 +2982,7 @@ class S3Provider(S3Api, ServiceLifecycleHook):
2975
2982
  max_uploads = max_uploads or 1000
2976
2983
  prefix = prefix or ""
2977
2984
  delimiter = delimiter or ""
2978
- if encoding_type:
2985
+ if encoding_type == EncodingType.url:
2979
2986
  prefix = urlparse.quote(prefix)
2980
2987
  delimiter = urlparse.quote(delimiter)
2981
2988
  upload_id_marker_found = False
@@ -1173,3 +1173,23 @@ def get_bucket_location_xml(location_constraint: str) -> str:
1173
1173
  '<LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/"'
1174
1174
  + ("/>" if not location_constraint else f">{location_constraint}</LocationConstraint>")
1175
1175
  )
1176
+
1177
+
1178
+ def encode_continuation_token(value: str) -> str:
1179
+ """
1180
+ :param value: a string value to be encoded
1181
+ :return: a base64 encoded S3 ContinuationMarker
1182
+ """
1183
+ return base64.b64encode(value.encode(), altchars=b"._").decode("ascii")
1184
+
1185
+
1186
+ def decode_continuation_token(value: str | None) -> str:
1187
+ """
1188
+ Pendant to ``encode_continuation_token``, will decode the value back to its original form
1189
+ :param value: a ContinuationMarker value
1190
+ :return: a string from the base64 decoded value
1191
+ """
1192
+ if value is None:
1193
+ return ""
1194
+
1195
+ return base64.b64decode(value, altchars=b"._").decode("ascii")
@@ -15,6 +15,7 @@ from localstack.aws.api.s3 import (
15
15
  BucketName,
16
16
  ChecksumAlgorithm,
17
17
  CORSConfiguration,
18
+ EncodingType,
18
19
  Grant,
19
20
  Grantee,
20
21
  Grants,
@@ -520,3 +521,12 @@ def validate_checksum_value(checksum_value: str, checksum_algorithm: ChecksumAlg
520
521
  valid_length = 0
521
522
 
522
523
  return len(checksum) == valid_length
524
+
525
+
526
+ def validate_encoding_type(encoding_type: EncodingType):
527
+ if encoding_type is not None and not encoding_type == EncodingType.url:
528
+ raise InvalidArgument(
529
+ "Invalid Encoding Method specified in Request",
530
+ ArgumentName="encoding-type",
531
+ ArgumentValue=encoding_type,
532
+ )
localstack/version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '4.13.2.dev59'
32
- __version_tuple__ = version_tuple = (4, 13, 2, 'dev59')
31
+ __version__ = version = '4.13.2.dev61'
32
+ __version_tuple__ = version_tuple = (4, 13, 2, 'dev61')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: localstack-core
3
- Version: 4.13.2.dev59
3
+ Version: 4.13.2.dev61
4
4
  Summary: The core library and runtime of LocalStack
5
5
  Author-email: LocalStack Contributors <info@localstack.cloud>
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ localstack/deprecations.py,sha256=-3IYgCd6LEC3PjO7hbr3Dg-p0PIS6phjmv1qZnj1uo0,15
4
4
  localstack/openapi.yaml,sha256=jFUzv-NKkJttxb8HRrmKiNYOmJD-zVfPxG3DDMrRwfg,30865
5
5
  localstack/plugins.py,sha256=BIJC9dlo0WbP7lLKkCiGtd_2q5oeqiHZohvoRTcejXM,2457
6
6
  localstack/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- localstack/version.py,sha256=FjFqaxO0JCqsR8nnNY9lAH4P4onmdnBvmOt59wDntJg,721
7
+ localstack/version.py,sha256=zJLAnFG15jxKHdc81amA43C3SU17fo3IFV2ITv3vdvM,721
8
8
  localstack/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  localstack/aws/accounts.py,sha256=102zpGowOxo0S6UGMpfjw14QW7WCLVAGsnFK5xFMLoo,3043
10
10
  localstack/aws/app.py,sha256=n9bJCfJRuMz_gLGAH430c3bIQXgUXeWO5NPfcdL2MV8,5145
@@ -488,10 +488,10 @@ localstack/services/iam/resource_providers/aws_iam_group_plugin.py,sha256=HxHgFw
488
488
  localstack/services/iam/resource_providers/aws_iam_instanceprofile.py,sha256=mQwYGsTYvo1cYvvbxISQqjbGp_ofjeWMcDAd25p5wc4,4135
489
489
  localstack/services/iam/resource_providers/aws_iam_instanceprofile.schema.json,sha256=_rfb9g_qP-pqOh7N9EQRPPugzy2GdS6QPBe__M4r6ho,1915
490
490
  localstack/services/iam/resource_providers/aws_iam_instanceprofile_plugin.py,sha256=zHcxteFVBHYeDX-i63hD7HJW4Hu67ij4WbiRFRcQu1Y,547
491
- localstack/services/iam/resource_providers/aws_iam_managedpolicy.py,sha256=d-pshK_Be6-MVRUlNBiA29pjeSAVTo3XhWEa2cPejKM,3781
491
+ localstack/services/iam/resource_providers/aws_iam_managedpolicy.py,sha256=nvGQe1bvFqX9hi-eVqCO7wgYLSW3AG2AAv4fqkHJBio,4012
492
492
  localstack/services/iam/resource_providers/aws_iam_managedpolicy.schema.json,sha256=GxtGVfjju7x9EP1IJkzUV6VxIY2HNGMNtPliPtVVgX4,1058
493
493
  localstack/services/iam/resource_providers/aws_iam_managedpolicy_plugin.py,sha256=I14EYfMfaAOatcFwsvKqUaHA4fHT2odV9eKJS44zqvA,537
494
- localstack/services/iam/resource_providers/aws_iam_policy.py,sha256=IFLF40CgQA6cmzt4MoXnzR5zEGY0wTw3lIuUSZYRX2w,4951
494
+ localstack/services/iam/resource_providers/aws_iam_policy.py,sha256=YzJFutnaSyVORTXuAViRiDqlxzmq0kv8redsJAlHX-Y,5414
495
495
  localstack/services/iam/resource_providers/aws_iam_policy.schema.json,sha256=RPhlO0dUuuaTm3Lc-AIVbdsaktrn0u6iAh1JF45t6-Q,837
496
496
  localstack/services/iam/resource_providers/aws_iam_policy_plugin.py,sha256=bERNjS_uApjiUrJl0Q6l9bs_t3c0IXtF2htSRYVwZ6M,477
497
497
  localstack/services/iam/resource_providers/aws_iam_role.py,sha256=zqJIYWvETTny7n9tvs1ycrZKF-rTFghaTdxtX9CfwqA,9238
@@ -690,9 +690,9 @@ localstack/services/s3/headers.py,sha256=jh0R2vhdnB5pWiVCoV26kqup53dBWz3iQIE3mhP
690
690
  localstack/services/s3/models.py,sha256=EwywhCScxHnbbbwM_Zp5x5rJMsy4Uf7CpvO1LaDj18k,31315
691
691
  localstack/services/s3/notifications.py,sha256=JRvZTs3YpEXX-tPdliarVKjKsp42fdzrTNOC51y2-8I,32568
692
692
  localstack/services/s3/presigned_url.py,sha256=2rbkrEYMimmanUW6RQdYGSb9PGFDZa6MmLru8ZkBri8,38438
693
- localstack/services/s3/provider.py,sha256=ShFkGoSw_E5BcM1gtzmvc4p38bs9nKf1CEpBaG5xtxM,201373
694
- localstack/services/s3/utils.py,sha256=mBubuZVrdTBhMxCsTw6I1mmCxI8O_fiZVd9rRAgrGLs,43815
695
- localstack/services/s3/validation.py,sha256=n4XdJLJdGddKd9JFBjtbRHaPzzTW8H1I_1uQS4N_w1s,20202
693
+ localstack/services/s3/provider.py,sha256=O_Z7SNJ4XV7J45ofMg8QNNqhzlTNhSPE-dPaadkQMYA,201794
694
+ localstack/services/s3/utils.py,sha256=yRE4P_ULUIt4WxU55WtIkxj584lObisjolzPKtlIYnM,44432
695
+ localstack/services/s3/validation.py,sha256=KPs960rBpUOK9Ui3TqPubqT7t2PNox8l5vRP9U-o9CE,20539
696
696
  localstack/services/s3/website_hosting.py,sha256=I4cE7omiN7EBQjdlvueSb_DaD8cwEZxeh7K-H_We30k,16672
697
697
  localstack/services/s3/resource_providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
698
698
  localstack/services/s3/resource_providers/aws_s3_bucket.py,sha256=usTd16U_pw5MG3DBCLNNFQfwWiW5iAPvsT-OGQRjm9k,22770
@@ -1311,10 +1311,10 @@ localstack/utils/server/tcp_proxy.py,sha256=y2NJAmvftTiAYsLU_8qe4W5LGqwUw21i90Pu
1311
1311
  localstack/utils/xray/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1312
1312
  localstack/utils/xray/trace_header.py,sha256=ahXk9eonq7LpeENwlqUEPj3jDOCiVRixhntQuxNor-Q,6209
1313
1313
  localstack/utils/xray/traceid.py,sha256=GKO-R2sMMjlrH2UaLPXlQlZ6flbE7ZKb6IZMtMu_M5U,1110
1314
- localstack_core-4.13.2.dev59.data/scripts/localstack-supervisor,sha256=nm1Il2d6ASyOB6Vo4CRHd90w7TK9FdRl9VPp0NN6hUk,6378
1315
- localstack_core-4.13.2.dev59.dist-info/licenses/LICENSE.txt,sha256=3PC-9Z69UsNARuQ980gNR_JsLx8uvMjdG6C7cc4LBYs,606
1316
- localstack_core-4.13.2.dev59.dist-info/METADATA,sha256=q4MPlyJb1PiOy7-FBN-gtQzz8jqM6f-FHknRHhnMNNw,5867
1317
- localstack_core-4.13.2.dev59.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
1318
- localstack_core-4.13.2.dev59.dist-info/entry_points.txt,sha256=59aAnn8KVHWAHkMg2dOgmgYtRZ-xTX9T4UiIchWgK6k,20975
1319
- localstack_core-4.13.2.dev59.dist-info/top_level.txt,sha256=3sqmK2lGac8nCy8nwsbS5SpIY_izmtWtgaTFKHYVHbI,11
1320
- localstack_core-4.13.2.dev59.dist-info/RECORD,,
1314
+ localstack_core-4.13.2.dev61.data/scripts/localstack-supervisor,sha256=nm1Il2d6ASyOB6Vo4CRHd90w7TK9FdRl9VPp0NN6hUk,6378
1315
+ localstack_core-4.13.2.dev61.dist-info/licenses/LICENSE.txt,sha256=3PC-9Z69UsNARuQ980gNR_JsLx8uvMjdG6C7cc4LBYs,606
1316
+ localstack_core-4.13.2.dev61.dist-info/METADATA,sha256=NAnOOm-Rad-8_6mcSlokP3M3_wNfzLMITQHm88gGhjI,5867
1317
+ localstack_core-4.13.2.dev61.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
1318
+ localstack_core-4.13.2.dev61.dist-info/entry_points.txt,sha256=59aAnn8KVHWAHkMg2dOgmgYtRZ-xTX9T4UiIchWgK6k,20975
1319
+ localstack_core-4.13.2.dev61.dist-info/top_level.txt,sha256=3sqmK2lGac8nCy8nwsbS5SpIY_izmtWtgaTFKHYVHbI,11
1320
+ localstack_core-4.13.2.dev61.dist-info/RECORD,,