Repository navigation
Conversation
Generated resources are merged into the output template with dict.update(), and verify_unique_logical_id only checks them against resources written in the input template. When two SAM resources generate an IAM role with the same logical ID (e.g. Function "NetOperator" -> "NetOperatorRole" and NetworkConnector "Net" -> "NetOperatorRole"), the later role silently overwrites the earlier one and a resource ends up with another resource's permissions. Add GeneratedLogicalIdTracker to record which SAM resource generated each logical ID, and raise DuplicateLogicalIdException when a different SAM resource generates the same one. The check also covers the CodeDeploy service role, which is added after the main loop. The scope is limited to AWS::IAM::Role for now, because other resource types (shared usage plans, custom domains, Route53 record set groups) are intentionally generated by multiple SAM resources. The scope is a parameter of the tracker so it can be widened later.
The CodeDeploy service role was recorded in GeneratedLogicalIdTracker under the first function with a DeploymentPreference. When that same function is named "CodeDeployService", its execution role "CodeDeployServiceRole" and the CodeDeploy service role share both the logical ID and the recorded source, so the tracker reported no conflict and the execution role was silently overwritten. Record the CodeDeploy service role under a dedicated source that no SAM logical ID can match, and report the collision as an invalid resource with a message explaining that the role id is reserved for the CodeDeploy service role.
vicheey
approved these changes
Oct 7, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue #, if available
N/A
Description of changes
Generated resources are merged into the output template with
dict.update(), andverify_unique_logical_idonly checks them against resources written in the input template. When two generators produce an IAM role with the same logical ID, the later role silently overwrites the earlier one and a resource ends up with another resource's permissions.Example: Function
NetOperatorgeneratesNetOperatorRole(<Id>Role), and NetworkConnectorNetgeneratesNetOperatorRole(<Id>OperatorRole). Today the transform succeeds and the function's role is the NetworkConnector operator role.Changes:
verify_logical_id.py: addGeneratedLogicalIdTracker, which records which source generated each logical ID and reports a conflict when a different source generates the same one. Which resources are checked is ashould_checkparameter (defaultis_iam_role), so the scope can be widened later without changing the tracker or its callers.translator.py:CodeDeployServiceRole), which is added after the loop and is not generated by any single SAM resource. It is recorded under a dedicated source,CODEDEPLOY_SERVICE_ROLE_SOURCE = "AWS::CodeDeploy::ServiceRole", which can never equal a SAM logical ID. This catches a collision with any function's execution role, including the function that has the DeploymentPreference itself.InvalidResourceExceptionon the colliding function:It generates an IAM role with id [CodeDeployServiceRole], which is reserved for the CodeDeploy service role generated for DeploymentPreference. Please use a different id for this resource.exceptions.py:DuplicateLogicalIdExceptiontakes an optionalconflicting_logical_idso the message names both resources. The existing message is unchanged when it is not passed.Why only IAM roles: SAM never intentionally generates the same IAM role from two different generators (every generated role name derives from its own resource's logical ID;
CodeDeployServiceRoleis generated once). Other types are intentionally shared across SAM resources under one logical ID (ServerlessUsagePlan/ServerlessApiKey/ServerlessUsagePlanKey,ApiGatewayDomainName<hash>,RecordSetGroup<hash>), so checking all types would need an allowlist and risk breaking existing templates.No existing logical IDs change. Templates that currently hit this collision will now fail to transform instead of silently getting the wrong role.
Description of how you validated changes
error_generated_role_logical_id_collision(Function + NetworkConnector)error_codedeploy_role_logical_id_collision(FunctionCodeDeployService+ a different function with DeploymentPreference)error_codedeploy_role_logical_id_self_collision(single FunctionCodeDeployServicethat has the DeploymentPreference)tests/translator/test_verify_logical_id.pyfor the tracker, including a widened scope.pytest tests/translator: 2428 passed.bin/run_cfn_lint.sh: exit 0.ruff check: passes.Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.