Skip to content

Conversation

roger-zhangg
Copy link
Member

Description

This PR fixes an issue where CloudFormation internal placeholders were being incorrectly resolved during SAM transformation, causing changeset creation failures when using the --include-nested-stacks flag.

Problem

When creating changesets with --include-nested-stacks, CloudFormation passes internal placeholders for cross-references between nested stacks that don't exist yet. These placeholders follow the format:

{{IntrinsicFunction:stack-name/Resource.Outputs.Property/Fn::GetAtt}}

Previously, SAM was resolving these placeholders as regular parameter values, which caused them to be wrapped in arrays for list-type fields. This resulted in CloudFormation validation errors:

Usage of {{IntrinsicFunction:debugging-cloudformation-issues/Cognito.Outputs.UserPoolArn/Fn::GetAtt}} is not allowed

Solution

  1. Added a wrapper function _get_parameter_value() that checks if a parameter value is a CloudFormation internal placeholder

    • Returns None (or a default value) if the parameter value starts with {{IntrinsicFunction:
    • Returns the actual value for normal parameters
  2. Updated intrinsic functions to use the wrapper:

    • RefAction.resolve_parameter_refs(): Returns the original {"Ref": "ParamName"} unchanged for placeholders
    • SubAction.resolve_parameter_refs(): Keeps the original ${ParamName} reference in Sub strings for placeholders
  3. Added comprehensive test coverage in tests/intrinsics/test_resolver.py to verify:

    • CloudFormation placeholders are not resolved
    • Normal parameters continue to work correctly
    • Placeholders in nested structures and lists are handled properly
    • Both Ref and Fn::Sub handle placeholders correctly

Impact

Before

# SAM would resolve this:
UserPoolArn: !Ref UserPoolArn
# Where UserPoolArn parameter = "{{IntrinsicFunction:stack/Cognito.Outputs.UserPoolArn/Fn::GetAtt}}"

# Into this (causing errors):
UserPoolArn: 
  - "{{IntrinsicFunction:stack/Cognito.Outputs.UserPoolArn/Fn::GetAtt}}"

After

# Now it remains as:
UserPoolArn: !Ref UserPoolArn
# The intrinsic function is preserved, allowing CloudFormation to handle it properly

Testing

  • Added test cases for CloudFormation placeholder handling in both Ref and Fn::Sub intrinsic functions
  • All existing tests pass, ensuring no regression in normal parameter resolution
  • Verified with the reproduction case from the issue report

Related Issues

Fixes the issue where sam package followed by aws cloudformation create-change-set --include-nested-stacks would fail with "Usage of {{IntrinsicFunction:...}} is not allowed" error.

Checklist

  • Code changes are covered by tests
  • No breaking changes to existing functionality
  • Tests pass locally
  • Documentation updated (inline comments explain the placeholder handling)

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@roger-zhangg roger-zhangg requested a review from a team as a code owner October 7, 2025 18:06
@roger-zhangg roger-zhangg reopened this Oct 7, 2025
valerena
valerena previously approved these changes Oct 7, 2025
@roger-zhangg roger-zhangg merged commit 56ebe73 into aws:develop Oct 9, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants