Skip to content

fix: Fn::GetAtt with a nested intrinsic crashes on dump (#120)#122

Open
earfman wants to merge 2 commits into
awslabs:masterfrom
earfman:fix-getatt-nested-intrinsic
Open

fix: Fn::GetAtt with a nested intrinsic crashes on dump (#120)#122
earfman wants to merge 2 commits into
awslabs:masterfrom
earfman:fix-getatt-nested-intrinsic

Conversation

@earfman

@earfman earfman commented Jul 13, 2026

Copy link
Copy Markdown

Issue #, if available: #120

Description of changes:

What

Fn::GetAtt whose elements include a nested intrinsic (e.g. Fn::FindInMap inside GetAtt, which AWS::LanguageExtensions allows) crashes on dump:

TypeError: sequence item 0: expected str instance, ODict found

Fixes #120.

Why

fn_representer (cfn_flip/yaml_dumper.py) collapses a GetAtt list into the dotted short form via ".".join(value), which assumes every element is a string. A nested intrinsic is an ODict, so the join raises. This is a valid CloudFormation shape, so cfn-flip shouldn't crash on it.

The fix

Collapse to the dotted short form only when all elements are strings; otherwise emit the long-form Fn::GetAtt mapping.

The long form is used deliberately rather than the !GetAtt [ ... ] short-tag sequence: the loader's construct_getatt reads short-form !GetAtt elements as raw scalar node values ([s.value for s in node.value]), so a !GetAtt short tag wrapping a nested !FindInMap fails to load. The long-form Fn::GetAtt mapping round-trips cleanly through the existing machinery and is valid CloudFormation.

Tests

Added tests/test_getatt_intrinsic.py:

  • test_flip_to_yaml_with_getatt_containing_intrinsicGetAtt with a nested FindInMap emits long form and round-trips through to_json(to_yaml(x)). Fails on master with the exact TypeError; passes with this change.
  • test_flip_to_yaml_getatt_all_strings_still_dotted — guards the common case: an all-string GetAtt still collapses to !GetAtt 'Res.Attr'.

Full suite: 91 → 93 pass (2 new tests). Scope: the single crashing branch (+14/-1) plus a two-test file; no behavior change for all-string GetAtt, other intrinsics, or any non-GetAtt path.

This change was prepared with AI assistance and independently verified against the project's full test suite before submission — reproduced on a clean clone, checked for round-trip correctness and sibling-case regressions, and confirmed to fail without the change.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

earfman added 2 commits July 13, 2026 01:24
GetAtt collapses its list into the dotted short form via ".".join(value), which assumes every element is a string. A GetAtt with a nested intrinsic (e.g. Fn::FindInMap, allowed by AWS::LanguageExtensions) is an ODict, so the join raises TypeError on dump. Collapse to the dotted short form only when all elements are strings; otherwise emit the long-form Fn::GetAtt mapping, which round-trips and is valid CloudFormation.
@earfman earfman changed the title Fix getatt nested intrinsic fix: Fn::GetAtt with a nested intrinsic crashes on dump (#120) Jul 13, 2026
@earfman

earfman commented Jul 13, 2026

Copy link
Copy Markdown
Author

Coretexa gate report — cfnflip-getatt-intrinsic

fix: Fn::GetAtt containing a nested intrinsic crashes on dump (aws-cfn-template-flip)

status: closed · doer: doer-claude · verifier: verifier-cfnflip · repo: awslabs/aws-cfn-template-flip@master

Acceptance criteria

  • A template whose Fn::GetAtt contains a nested intrinsic (Fn::FindInMap, allowed by AWS::LanguageExtensions) dumps without crashing
  • The dumped output is itself re-loadable by cfn-flip and round-trips (to_json(to_yaml(x)) preserves structure)
  • Existing behavior unchanged for all-string GetAtt (still collapses to the dotted short form), other intrinsics, and non-GetAtt paths
  • Full suite passes with no new failures; a regression test is added that fails without the fix

Evidence

check result by detail
repro ✓ pass verifier-cfnflip clean clone: nested-intrinsic GetAttTypeError: sequence item 0: expected str instance, ODict found, at both operand positions
fix-works ✓ pass verifier-cfnflip after patch, #120 template dumps to long-form Fn::GetAtt: with nested !FindInMap; no crash
round-trip ✓ pass verifier-cfnflip dumped output reloads with no error and is byte-identical on re-dump; to_json(to_yaml(x)) structure-equal
naive-fix-rejected ✓ pass verifier-cfnflip independently confirmed the !GetAtt [ !FindInMap ] short-tag form FAILS to load (construct_getatt reads raw scalar nodes) — long form is required, not optional
no-over-reach ✓ pass verifier-cfnflip all-string GetAtt still dotted; Ref/Sub elements, GetAtt-in-GetAtt, first/second-intrinsic all round-trip
full-suite ✓ pass verifier-cfnflip baseline 91 pass / 1 fail → patched 91 pass / 1 fail (dumper hunk only); the 1 fail is a pre-existing env-only test_cli_with_version, present in baseline. With the new test file: 93 pass.

All required checks have passing evidence: repro, fix-works, round-trip, no-over-reach, full-suite

Verification

--- VERIFIED 2026-07-13 by verifier-cfnflip (independent session, not the doer) ---
Gate 1: reproduced the crash on a fresh clone with own template (both operand positions).
Gate 2: the FIRST fix attempt (dumper-only, emit !GetAtt short-tag sequence) stopped the dump
        crash but produced YAML that cfn-flip's own loader could not re-parse. Caught here and
        rejected; corrected to emit the long-form Fn::GetAtt mapping, which round-trips.
Gate 3: patch touches only the crashing branch (+14/-1); all-string path byte-for-byte unchanged.
Gate 4: adversarial inputs (Sub element, deep nesting, mixed positions, empty list) all safe;
        the one 3-part dotted-form asymmetry is a PRE-EXISTING library quirk, unchanged by the fix.

Verified by a second agent · claimer ≠ verifier · coretexa.dev

@koiker

koiker commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Nice to see a code written 100% by humans years ago got a fix from AI. Considering it's a minor fix, we humans did a good job on this app.

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.

Failure to load and dump template which has FindInMap inside GetAtt

2 participants