Skip to content

cdk migrate: deduplicateResources() drops distinct resources with compound identifiers #1878

Description

@Adityaj0

Describe the bug

cdk migrate --from-scan (and the underlying CfnTemplateGeneratorProvider.listResourceScanResources / getResourceScanRelatedResources methods) can silently drop real resources from the generated CloudFormation template / migrate.json when two distinct scanned resources share the value of only the first key of a compound ResourceIdentifier.

The bug is in deduplicateResources() in packages/aws-cdk/lib/commands/migrate.ts:

function deduplicateResources(resources: ResourceDetail[]) {
  let uniqueResources: { [key: string]: ResourceDetail } = {};

  for (const resource of resources) {
    const key = Object.keys(resource.ResourceIdentifier!)[0];   // <-- only the FIRST key

    const uniqueIdentifer = `${resource.ResourceType}:${key}:${resource.ResourceIdentifier![key]}`;
    uniqueResources[uniqueIdentifer] = resource;
  }

  return Object.values(uniqueResources);
}

ResourceIdentifier (returned by the CloudFormation ListResourceScanResources / ListResourceScanRelatedResources APIs) can legitimately contain more than one key for resource types with compound identifiers. For example AWS::Route53::KeySigningKey is identified by the pair (HostedZoneId, Name) — the CLI itself documents this elsewhere (packages/@aws-cdk/toolkit-lib/lib/api/resource-import/importer.ts).

Because deduplicateResources only reads Object.keys(resource.ResourceIdentifier!)[0] and ignores the remaining identifier components, two genuinely distinct resources that happen to share the value of just their first identifier key collide on the same synthetic dedup key and one silently overwrites the other in uniqueResources.

Impact

Any customer running cdk migrate --from-scan against an account that has multiple resources of a compound-identifier type sharing the leading identifier key (e.g. two AWS::Route53::KeySigningKey resources in the same hosted zone with different names) will have some of those resources silently dropped — no error, no warning — from the generated CDK app/template. The gap is only discovered later when resources turn out to be missing from the migrated stack.

Expected Behavior

deduplicateResources should use the entire ResourceIdentifier map (all key/value pairs) to determine resource uniqueness, not just the first key.

Reproduction

Unit-test level repro: call deduplicateResources (or exercise it via generateTemplate) with two ResourceDetail entries such as:

{ ResourceType: 'AWS::Route53::KeySigningKey', ResourceIdentifier: { HostedZoneId: 'Z1', Name: 'ksk-one' } }
{ ResourceType: 'AWS::Route53::KeySigningKey', ResourceIdentifier: { HostedZoneId: 'Z1', Name: 'ksk-two' } }

Both resources share HostedZoneId: 'Z1' as their first key, so today they collapse to a single entry in the deduplicated list even though they are two distinct resources.

CDK CLI Version

main (current)

Environment

N/A - code-level bug, not environment specific

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions