cdk-factory 0.8.0__py3-none-any.whl → 0.8.2__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.

Potentially problematic release.


This version of cdk-factory might be problematic. Click here for more details.

@@ -86,7 +86,9 @@ class EnhancedSsmConfig:
86
86
  self, attribute: str, custom_path: Optional[str] = None
87
87
  ) -> str:
88
88
  """Generate SSM parameter path using pattern or custom path"""
89
- if custom_path and custom_path.startswith("/"):
89
+ # Handle custom_path - must be a string starting with "/"
90
+ # Protect against incorrect config like: "exports": {"enabled": true}
91
+ if custom_path and isinstance(custom_path, str) and custom_path.startswith("/"):
90
92
  return custom_path
91
93
 
92
94
  # Convert underscore attribute names to hyphen format for consistent SSM paths
@@ -142,28 +142,39 @@ class EnhancedSsmParameterMixin:
142
142
  Returns:
143
143
  Created SSM parameter
144
144
  """
145
- # Handle different value types
146
- if isinstance(value, list):
147
- string_value = ",".join(str(v) for v in value)
148
- cdk_param_type = ssm.ParameterType.STRING_LIST
149
- elif param_type == "SecureString":
150
- string_value = str(value)
151
- cdk_param_type = ssm.ParameterType.SECURE_STRING
152
- else:
153
- string_value = str(value)
154
- cdk_param_type = ssm.ParameterType.STRING
155
-
156
145
  # Generate a unique construct ID from the path
157
146
  construct_id = f"ssm-param-{path.replace('/', '-').replace('_', '-')}"
158
147
 
159
- return ssm.StringParameter(
160
- self.scope,
161
- construct_id,
162
- parameter_name=path,
163
- string_value=string_value,
164
- description=description,
165
- type=cdk_param_type
166
- )
148
+ # Handle different value types - use appropriate CDK constructs
149
+ if isinstance(value, list):
150
+ # For list values, use StringListParameter
151
+ return ssm.StringListParameter(
152
+ self.scope,
153
+ construct_id,
154
+ parameter_name=path,
155
+ string_list_value=value,
156
+ description=description
157
+ )
158
+ elif param_type == "SecureString":
159
+ # For secure strings, use L1 CfnParameter with Type=SecureString
160
+ return ssm.CfnParameter(
161
+ self.scope,
162
+ construct_id,
163
+ name=path,
164
+ value=str(value),
165
+ type="SecureString",
166
+ description=description
167
+ )
168
+ else:
169
+ # For regular strings, use StringParameter (no type parameter needed in CDK v2)
170
+ return ssm.StringParameter(
171
+ self.scope,
172
+ construct_id,
173
+ parameter_name=path,
174
+ string_value=str(value),
175
+ description=description
176
+ # Note: 'type' parameter removed - deprecated in CDK v2
177
+ )
167
178
 
168
179
  def _import_enhanced_ssm_parameter(self, path: str, attribute: str) -> Optional[str]:
169
180
  """
@@ -304,9 +304,28 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
304
304
  )
305
305
 
306
306
  def _setup_cognito_authorizer(self, api_gateway, api_id):
307
- """Setup Cognito authorizer if configured"""
307
+ """Setup Cognito authorizer if configured AND if any routes need it"""
308
308
  if not self.api_config.cognito_authorizer:
309
309
  return None
310
+
311
+ # Check if any routes actually need the authorizer
312
+ # Don't create it if all routes are public (authorization_type: NONE)
313
+ routes = self.api_config.routes or []
314
+ needs_authorizer = any(
315
+ route.get("authorization_type") != "NONE"
316
+ for route in routes
317
+ )
318
+
319
+ # If we're not creating an authorizer but Cognito is configured,
320
+ # inform the integration utility so it can still perform security validations
321
+ if not needs_authorizer:
322
+ logger.info(
323
+ "Cognito authorizer configured but no routes require authorization. "
324
+ "Skipping authorizer creation but maintaining security validation context."
325
+ )
326
+ # Set a flag so the integration utility knows Cognito was available
327
+ self.integration_utility.cognito_configured = True
328
+ return None
310
329
 
311
330
  route_config = ApiGatewayConfigRouteConfig({})
312
331
  return self.integration_utility.get_or_create_authorizer(
@@ -40,6 +40,7 @@ class ApiGatewayIntegrationUtility:
40
40
  self.account = scope.account
41
41
  self.api_gateway = None
42
42
  self.authorizer = None
43
+ self.cognito_configured = False # Flag for when Cognito is configured but authorizer not created
43
44
  self._log_group = None
44
45
  self._log_role = None
45
46
 
@@ -55,8 +56,10 @@ class ApiGatewayIntegrationUtility:
55
56
  raise ValueError("API Gateway config is missing in Lambda function config")
56
57
 
57
58
  # Validate authorization configuration for security
59
+ # Check if Cognito is available (either authorizer created OR configured but not created)
58
60
  has_cognito_authorizer = (
59
61
  self.authorizer is not None
62
+ or self.cognito_configured
60
63
  or self._get_existing_authorizer_id_with_ssm_fallback(
61
64
  api_config, stack_config
62
65
  )
@@ -614,6 +617,10 @@ class ApiGatewayIntegrationUtility:
614
617
  authorizer_name=authorizer_name,
615
618
  identity_source=identity_source,
616
619
  )
620
+
621
+ # The authorizer is automatically attached to the API Gateway when used in a method
622
+ # But we need to ensure it's created in the context of the API's scope
623
+ # The actual attachment happens when the authorizer is referenced in method creation
617
624
 
618
625
  return self.authorizer
619
626
 
@@ -61,35 +61,63 @@ class JsonLoadingUtility:
61
61
  """Resolve references in a configuration section."""
62
62
  if isinstance(section, dict):
63
63
  if self.nested_key in section:
64
- nested_path = str(section.pop(self.nested_key))
65
- # print(f"Resolving parent path: {nested_path}")
66
- if nested_path.endswith(".json"):
67
- nested_root_path = os.path.join(self.base_path, nested_path)
68
- nested_section = self.__load_json_file(nested_root_path)
69
- elif os.path.isdir(os.path.join(self.base_path, nested_path)):
70
- nested_section = []
71
- dir_path = os.path.join(self.base_path, nested_path)
72
- for filename in os.listdir(dir_path):
73
- if filename.endswith(".json"):
74
- file_path = os.path.join(dir_path, filename)
75
- # print(f"Loading file: {file_path}")
76
- file_section = self.__load_json_file(file_path)
77
- nested_section.append(file_section)
78
-
79
- # print("done with nested sections")
80
- else:
81
- nested_section = self.get_nested_config(root_config, nested_path)
82
-
83
- nested_section_resolved = self.resolve_references(
84
- nested_section, root_config
85
- )
86
- if len(section) > 0 and isinstance(nested_section_resolved, dict):
87
- nested_section_resolved.update(section)
88
- elif len(section) > 0 and isinstance(nested_section_resolved, list):
64
+ nested_paths = section.pop(self.nested_key)
65
+
66
+ # Support both single path (string) and multiple paths (list)
67
+ if isinstance(nested_paths, str):
68
+ nested_paths = [nested_paths]
69
+ elif not isinstance(nested_paths, list):
70
+ raise ValueError(f"__inherits__ must be a string or list, got {type(nested_paths)}")
71
+
72
+ # Process each path and merge results
73
+ merged_section = None
74
+
75
+ for nested_path in nested_paths:
76
+ nested_path = str(nested_path)
77
+ # print(f"Resolving parent path: {nested_path}")
78
+
79
+ if nested_path.endswith(".json"):
80
+ nested_root_path = os.path.join(self.base_path, nested_path)
81
+ nested_section = self.__load_json_file(nested_root_path)
82
+ elif os.path.isdir(os.path.join(self.base_path, nested_path)):
83
+ nested_section = []
84
+ dir_path = os.path.join(self.base_path, nested_path)
85
+ for filename in os.listdir(dir_path):
86
+ if filename.endswith(".json"):
87
+ file_path = os.path.join(dir_path, filename)
88
+ # print(f"Loading file: {file_path}")
89
+ file_section = self.__load_json_file(file_path)
90
+ nested_section.append(file_section)
91
+ # print("done with nested sections")
92
+ else:
93
+ nested_section = self.get_nested_config(root_config, nested_path)
94
+
95
+ nested_section_resolved = self.resolve_references(
96
+ nested_section, root_config
97
+ )
98
+
99
+ # Merge resolved sections
100
+ if merged_section is None:
101
+ merged_section = nested_section_resolved
102
+ else:
103
+ # Merge logic based on type
104
+ if isinstance(merged_section, dict) and isinstance(nested_section_resolved, dict):
105
+ self.merge_sections(merged_section, nested_section_resolved)
106
+ elif isinstance(merged_section, list) and isinstance(nested_section_resolved, list):
107
+ merged_section.extend(nested_section_resolved)
108
+ else:
109
+ raise RuntimeError(
110
+ f"Cannot merge incompatible types: {type(merged_section)} and {type(nested_section_resolved)}"
111
+ )
112
+
113
+ # Apply any additional properties from the section
114
+ if len(section) > 0 and isinstance(merged_section, dict):
115
+ merged_section.update(section)
116
+ elif len(section) > 0 and isinstance(merged_section, list):
89
117
  raise RuntimeError("we need to resolve this section")
90
- # nested_section_resolved.append(section)
118
+ # merged_section.append(section)
91
119
 
92
- section = nested_section_resolved
120
+ section = merged_section
93
121
 
94
122
  if isinstance(section, dict):
95
123
  for key, value in section.items():
cdk_factory/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.8.0"
1
+ __version__ = "0.8.2"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cdk_factory
3
- Version: 0.8.0
3
+ Version: 0.8.2
4
4
  Summary: CDK Factory. A QuickStarter and best practices setup for CDK projects
5
5
  Author-email: Eric Wilson <eric.wilson@geekcafe.com>
6
6
  License: MIT License
@@ -1,7 +1,7 @@
1
1
  cdk_factory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  cdk_factory/app.py,sha256=xv863N7O6HPKznB68_t7O4la9JacrkG87t9TjoDUk7s,2827
3
3
  cdk_factory/cdk.json,sha256=SKZKhJ2PBpFH78j-F8S3VDYW-lf76--Q2I3ON-ZIQfw,3106
4
- cdk_factory/version.py,sha256=iPlYCcIzuzW7T2HKDkmYlMkRI51dBLfNRxPPiWrfw9U,22
4
+ cdk_factory/version.py,sha256=B7GiO0rd49YwtLYjvPg4lmCZEDlMTonslQKdSImaMJk,22
5
5
  cdk_factory/builds/README.md,sha256=9BBWd7bXpyKdMU_g2UljhQwrC9i5O_Tvkb6oPvndoZk,90
6
6
  cdk_factory/commands/command_loader.py,sha256=QbLquuP_AdxtlxlDy-2IWCQ6D-7qa58aphnDPtp_uTs,3744
7
7
  cdk_factory/configurations/base_config.py,sha256=JKjhNsy0RCUZy1s8n5D_aXXI-upR9izaLtCTfKYiV9k,9624
@@ -10,7 +10,7 @@ cdk_factory/configurations/deployment.py,sha256=LO2gd1yv1nqlX_2MIjRXptylFybWiTKs
10
10
  cdk_factory/configurations/deployment_wave.py,sha256=TFX7CYgr5SmLyziEb-R_OTteFWtlMHB4pT53ekV3d1Y,233
11
11
  cdk_factory/configurations/devops.py,sha256=PG-s2ldZmMULheWdKf2lf2LSugLoKiOKyLELTZJJxu8,2506
12
12
  cdk_factory/configurations/enhanced_base_config.py,sha256=Y1gcGZxyf_O2KFnVpCBORSGHWHqHxw0vNx_ijMad_QA,6654
13
- cdk_factory/configurations/enhanced_ssm_config.py,sha256=8TRZX-gsv_fYjMKufAe2_-iF76RRE3grkC2MTYQxiJo,12718
13
+ cdk_factory/configurations/enhanced_ssm_config.py,sha256=VDmIUSrj8nYS6fE9DdOp5yi9jUfMfitz5A7kCuPS-kI,12895
14
14
  cdk_factory/configurations/management.py,sha256=TSOIyxO9hGNxbgiTsS8a3pz03ungXiNqPPtZtfOpr8M,1373
15
15
  cdk_factory/configurations/pipeline.py,sha256=3RmRP1GIk42rjYZ-A9H3357RcO13IA47N-2IQcBkySQ,4939
16
16
  cdk_factory/configurations/pipeline_stage.py,sha256=eAT-FoIepIuv5tObk4TXlCN47FaatQO2rrFchgbMdXU,3415
@@ -57,7 +57,7 @@ cdk_factory/constructs/s3_buckets/s3_bucket_construct.py,sha256=5DK5aVUAveJYBjmP
57
57
  cdk_factory/constructs/s3_buckets/s3_bucket_replication_destination_construct.py,sha256=H-EJ2Q71LI5FPQ9thMkXDGRuwJdFc_2OzGIrWA98lxg,2517
58
58
  cdk_factory/constructs/s3_buckets/s3_bucket_replication_source_construct.py,sha256=ZLKbRcMK1q73VruxCH62XbymebKt-lKV5Kul9OjkZiA,3763
59
59
  cdk_factory/constructs/sqs/policies/sqs_policies.py,sha256=4p0G8G-fqNKSr68I55fvqH-DkhIeXyGaFBKkICIJ-qM,1277
60
- cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py,sha256=k-jfwRJhIs6sxifmh7rFaX92tpHMdxiZ8mgPP4NNu5E,13041
60
+ cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py,sha256=GYFaUo_vzmuox8dK0U-cI9d-OBhToXlTkrWeveGZr3k,13522
61
61
  cdk_factory/interfaces/istack.py,sha256=bhTBs-o9FgKwvJMSuwxjUV6D3nUlvZHVzfm27jP9x9Y,987
62
62
  cdk_factory/interfaces/live_ssm_resolver.py,sha256=3FIr9a02SXqZmbFs3RT0WxczWEQR_CF7QSt7kWbDrVE,8163
63
63
  cdk_factory/interfaces/ssm_parameter_mixin.py,sha256=uA2j8HmAOpuEA9ynRj51s0WjUHMVLsbLQN-QS9NKyHA,12089
@@ -73,7 +73,7 @@ cdk_factory/stack/stack_module_registry.py,sha256=J14-A75VZESzRQa8p-Fepdap7Z8T7m
73
73
  cdk_factory/stack/stack_modules.py,sha256=kgEK-j0smZPozVwTCfM1g1V17EyTBT0TXAQZq4vZz0o,784
74
74
  cdk_factory/stack_library/__init__.py,sha256=5Y9TpIe8ZK1688G60PGcuP-hM0RvYEY_3Hl2qJCJJrw,581
75
75
  cdk_factory/stack_library/stack_base.py,sha256=tTleSFmlf26DuKVF_ytftf8P7IVWb5iex8cYfYupfvQ,4940
76
- cdk_factory/stack_library/api_gateway/api_gateway_stack.py,sha256=ekfu1BaA_b-Yn7U1SlfGLyskTQXMPjjotZDkxqYeysk,36984
76
+ cdk_factory/stack_library/api_gateway/api_gateway_stack.py,sha256=5rWHwLc6kI99YHUA1xqLtzcEhDmMB4p-xB9gLQ6o8JE,37916
77
77
  cdk_factory/stack_library/auto_scaling/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
78
  cdk_factory/stack_library/auto_scaling/auto_scaling_stack.py,sha256=UsFqUb_3XPJAlmZ6F75nXna3elOggD1KuFmmdmhi0Lg,19070
79
79
  cdk_factory/stack_library/aws_lambdas/lambda_stack.py,sha256=SFbBPvvCopbyiuYtq-O5sQkFCf94Wzua6aDUXiFDSB4,26161
@@ -100,19 +100,19 @@ cdk_factory/stack_library/vpc/__init__.py,sha256=7pIqP97Gf2AJbv9Ebp1WbQGHYhgEbWJ
100
100
  cdk_factory/stack_library/vpc/vpc_stack.py,sha256=zdDiGilf03esxuya5Z8zVYSVMAIuZBeD-ZKgfnEd6aw,10077
101
101
  cdk_factory/stack_library/websites/static_website_stack.py,sha256=KBQiV6PI09mpHGtH-So5Hk3uhfFLDepoXInGbfin0cY,7938
102
102
  cdk_factory/stages/websites/static_website_stage.py,sha256=X4fpKXkhb0zIbSHx3QyddBhVSLBryb1vf1Cg2fMTqog,755
103
- cdk_factory/utilities/api_gateway_integration_utility.py,sha256=xzKOdoKrd8AxuBWtV8uFa3r6I7wSKdC74m7tewBhzT8,62933
103
+ cdk_factory/utilities/api_gateway_integration_utility.py,sha256=yblKiMIHGXqKb7JK5IbzGM_TXjX9j893BMqgqBT44DE,63449
104
104
  cdk_factory/utilities/commandline_args.py,sha256=0FiNEJFbWVN8Ct7r0VHnJEx7rhUlaRKT7R7HMNJBSTI,2216
105
105
  cdk_factory/utilities/configuration_loader.py,sha256=z0ZdGLNbTO4_yfluB9zUh_i_Poc9qj-7oRyjMRlNkN8,1522
106
106
  cdk_factory/utilities/docker_utilities.py,sha256=9r8C-lXYpymqEfi3gTeWCQzHldvfjttPqn6p3j2khTE,8111
107
107
  cdk_factory/utilities/environment_services.py,sha256=cd2T0efJtFPMLa1Fm7MPL-sqUlhKXCB7_XHsR8sfymE,9696
108
108
  cdk_factory/utilities/file_operations.py,sha256=HCZevKlmnHNB2wkIEPtdm-g2nJSKT3B9uipLk8Kx_Yk,8946
109
109
  cdk_factory/utilities/git_utilities.py,sha256=7Xac8PaThc7Lmk5jtDBHaJOj-fWRT017cgZmgXkVizM,3155
110
- cdk_factory/utilities/json_loading_utility.py,sha256=zdvqO2Bw5OpImJymfQRgqr6wfpZSCVtL20sYCYPAvMg,7617
110
+ cdk_factory/utilities/json_loading_utility.py,sha256=Yeqdjkkly0JLa7-V8j7ipmybsPoyPIKdRe7My7JTk3o,9203
111
111
  cdk_factory/utilities/lambda_function_utilities.py,sha256=j3tBdv_gC2MdEwBINDwAqYey5vgn7YiQtJ0XZybTsCQ,15197
112
112
  cdk_factory/utilities/os_execute.py,sha256=5Op0LY_8Y-pUm04y1k8MTpNrmQvcLmQHPQITEP7EuSU,1019
113
113
  cdk_factory/utils/api_gateway_utilities.py,sha256=If7Xu5s_UxmuV-kL3JkXxPLBdSVUKoLtohm0IUFoiV8,4378
114
114
  cdk_factory/workload/workload_factory.py,sha256=yBUDGIuB8-5p_mGcVFxsD2ZoZIziak3yh3LL3JvS0M4,5903
115
- cdk_factory-0.8.0.dist-info/METADATA,sha256=74xL4nv4hBAxFNfxS3OTUkb91bBl3ooiLVwxMgQpPqc,2450
116
- cdk_factory-0.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
117
- cdk_factory-0.8.0.dist-info/licenses/LICENSE,sha256=NOtdOeLwg2il_XBJdXUPFPX8JlV4dqTdDGAd2-khxT8,1066
118
- cdk_factory-0.8.0.dist-info/RECORD,,
115
+ cdk_factory-0.8.2.dist-info/METADATA,sha256=PbYIaV_hrIj-7YZxLTQvR-GdLk6WErUYjuYP99HsjHA,2450
116
+ cdk_factory-0.8.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
117
+ cdk_factory-0.8.2.dist-info/licenses/LICENSE,sha256=NOtdOeLwg2il_XBJdXUPFPX8JlV4dqTdDGAd2-khxT8,1066
118
+ cdk_factory-0.8.2.dist-info/RECORD,,