Skip to content

fix: Require object for CreationPolicy and UpdatePolicy - #4641

Merged
kddejong merged 1 commit into
aws-cloudformation:mainfrom
kddejong:fix/issue/creationpolicy
Aug 18, 2026
Merged

kddejong merged 1 commit into
aws-cloudformation:mainfrom
kddejong:fix/issue/creationpolicy

Conversation

@kddejong

Copy link
Copy Markdown
Contributor

Issue #, if available:

Description of changes:

CreationPolicy and UpdatePolicy must resolve to an object. CloudFormation
rejects a bare intrinsic standing in for the whole object with
Template format error: Expected an object (verified against live
CloudFormation). Only an object literal or Fn::If (which resolves to an
object) is valid there; Ref/Fn::Sub/Fn::FindInMap, and Ref to a
resource or pseudo parameter, are not. Intrinsics nested at leaf properties
(e.g. ResourceSignal.Count: !Ref Count) remain valid.

Previously these were missed: E3055/E3016 allowed the full function set and
leaned on type inference, and UpdatePolicy errors were swallowed entirely.

Changes

  • allOf no longer flips unresolvable_function_mode or rolls errors up into a
    single "Cannot determine allOf". allOf is conjunctive — every subschema
    must hold and there is no branch to select — so an unresolvable intrinsic
    creates no ambiguity there; the suppression only hid legitimate errors. That
    mode still applies to the disjunctive keywords (anyOf/oneOf/if). This
    lets UpdatePolicy (E3016), whose schema is expressed via allOf/if/then,
    surface these errors the way CreationPolicy (E3055) already does.
  • E3055/E3016 validate against plain object schemas and blank Resources from
    the reference context, so Ref to a resource is caught.
  • Ref (E1020) now resolves pseudo-parameter types (string, or list for
    AWS::NotificationARNs) and validates them against the schema, mirroring the
    existing named-parameter check, so Ref to a pseudo at an object slot is
    caught.
  • Added integration templates and snapshots for CreationPolicy and
    UpdatePolicy (test/fixtures/templates/integration/,
    test/fixtures/results/integration/).

Verified against live CloudFormation (CreateStack):

Value at the policy slot CloudFormation
object literal accepted
Fn::If (object branches) accepted
Ref (param / resource / pseudo), Fn::Sub, Fn::FindInMap Expected an object
Ref: AWS::NoValue Expected an object
nested leaf intrinsic (Count: !Ref P) accepted

Known follow-up: Fn::Select is not yet rejected at the object slot
because its declared output type is all_types (it can legitimately resolve to
an object via a list of objects, e.g. through Fn::FindInMap). Tracked
separately.

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

@codecov

codecov Bot commented Aug 18, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.61%. Comparing base (d8d5bfb) to head (ea6590b).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4641      +/-   ##
==========================================
+ Coverage   94.58%   94.61%   +0.02%     
==========================================
  Files         432      432              
  Lines       15417    15426       +9     
  Branches     2986     2991       +5     
==========================================
+ Hits        14582    14595      +13     
+ Misses        456      453       -3     
+ Partials      379      378       -1     
Flag Coverage Δ
unittests 94.61% <100.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

CreationPolicy and UpdatePolicy must resolve to an object. CloudFormation
rejects a bare intrinsic standing in for the whole object with "Template
format error: Expected an object" (verified against live CloudFormation).
Only an object literal or Fn::If (which resolves to an object) is valid;
Ref/Fn::Sub/Fn::FindInMap and Ref to a resource or pseudo parameter are not.
Intrinsics nested at leaf properties (e.g. ResourceSignal.Count: !Ref P)
remain valid.

Changes:
- allOf no longer flips unresolvable_function_mode or rolls errors up into a
  single "Cannot determine allOf". allOf is conjunctive (every subschema must
  hold, no branch selection), so an unresolvable intrinsic creates no ambiguity
  there; the suppression only hid legitimate errors (that mode belongs in the
  disjunctive keywords anyOf/oneOf/if). This lets UpdatePolicy (E3016), whose
  schema is expressed via allOf/if/then, surface these errors like
  CreationPolicy (E3055) already does.
- E3055/E3016 validate against plain object schemas and blank Resources from
  the reference context so Ref to a resource is caught.
- Ref (E1020) resolves pseudo-parameter types (string, or list for
  AWS::NotificationARNs) and validates them against the schema, mirroring the
  existing named-parameter check, so Ref to a pseudo at an object slot is
  caught.
- Add integration templates and snapshots for CreationPolicy and UpdatePolicy.

Known follow-up: Fn::Select is not yet rejected at the object slot because its
declared output type is all_types (it can legitimately resolve to an object via
a list of objects).
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.

1 participant