Skip to content

Qualify inline sub-component output names to prevent config collisions#205

Open
jaredbrook wants to merge 2 commits into
masterfrom
feature/resolve-inline-config-collisions
Open

Qualify inline sub-component output names to prevent config collisions#205
jaredbrook wants to merge 2 commits into
masterfrom
feature/resolve-inline-config-collisions

Conversation

@jaredbrook
Copy link
Copy Markdown
Collaborator

Problem

When multiple sibling components use the same template with render: Inline (e.g. several fargate-v2 instances each creating an application-autoscaling sub-component named "autoscaling"), the compiler writes their config and cfndsl output to the same filename. The last component to compile overwrites all previous ones, so every instance evaluates using a single shared config — the last writer wins.

Example: A project defines five ECS services as fargate-v2 components. Each creates an inline application-autoscaling component which in turn creates an inline ecs-scaling sub-component named "autoscaling". All five write to autoscaling.config.yaml and autoscaling.compiled.cfndsl.rb. The last one to compile overwrites the rest, causing all services to share identical scaling policies regardless of their individual config.

Fix

Qualify inline sub-component @component_name values with their parent's component name, producing unique output filenames per instance. The qualified name is passed into the constructor via a new optional qualified_name parameter so it propagates recursively through the entire component tree.

Non-inline (nested stack) components keep their original unqualified names so that template URLs and S3 publishing paths remain compatible.

Impact

  • Final flattened templates are unchanged — inline resources are merged into the parent by flattenCloudformation, which is unaffected. The existing flatten spec passes.
  • Intermediate output filenames change for all inline sub-components (e.g. myTask.compiled.yamlmyproject_myservice_myTask.compiled.yaml). Any tooling that references these intermediate paths will need updating.
  • Non-inline component filenames are unchanged — no impact on template URLs or publishing.

Testing

  • Existing test_cloudformation_util_spec (flatten test) passes — confirms the final CloudFormation output is identical.
  • New test_inline_config_isolation_spec — creates two inline instances of the same template with different configs (via a three-level parent/child/grandchild hierarchy to trigger the collision). Verified that the spec fails against unpatched 0.13.4 (child_a gets "beta" instead of "alpha") and passes with the fix.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a compiler output collision where multiple sibling inline components (and their inline subcomponents) can overwrite each other’s generated config/cfndsl artifacts due to identical output filenames, causing later compiles to “win” and earlier instances to evaluate with the wrong config.

Changes:

  • Extend ComponentCompiler to accept an optional qualified_name and use it to generate unique output basenames for inline subcomponents.
  • Qualify inline subcomponent compiler names using their parent compiler name to avoid *.config.yaml / *.compiled.cfndsl.rb collisions.
  • Add a new RSpec regression test + fixtures that reproduce the collision across a multi-level inline hierarchy and assert per-instance config isolation.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
lib/cfhighlander.compiler.rb Adds qualified_name support and qualifies inline subcomponent output names to reduce artifact collisions.
spec/test_inline_config_isolation_spec.rb New regression spec verifying two inline instances of the same template compile with distinct configs.
spec/data/inline_config_isolation/src/p.config.yaml Test config providing distinct values for child_a vs child_b.
spec/data/inline_config_isolation/src/p.cfndsl.rb Minimal parent CFNDSL stub for the regression test.
spec/data/inline_config_isolation/src/p.cfhighlander.rb Parent template wiring two inline child components with different configs.
spec/data/inline_config_isolation/src/child/child.cfndsl.rb Minimal child CFNDSL stub for the regression test.
spec/data/inline_config_isolation/src/child/child.cfhighlander.rb Child template inlining the grandchild component (passes config through).
spec/data/inline_config_isolation/src/grandchild/grandchild.cfndsl.rb Produces an S3 bucket whose name is derived from config (assertion target).
spec/data/inline_config_isolation/src/grandchild/grandchild.cfhighlander.rb Minimal grandchild template stub for the regression test.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +61 to +69
# Inline sub-components share the parent's output directory and their
# resources get flattened into the parent template, so they don't need
# stable filenames. Qualify with parent name to prevent collisions when
# multiple sibling components define sub-components with the same name.
child_name = if sub_component.inlined
"#{@component_name}_#{sub_component.name}"
else
sub_component.name
end
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.

2 participants