Skip to content

refactor(cloudformation): move the single-service types to provisioners - #2744

Open
hectorvent wants to merge 1 commit into
docs/cfn-generate-resource-type-tablefrom
refactor/cfn-leaf-provisioners
Open

refactor(cloudformation): move the single-service types to provisioners#2744
hectorvent wants to merge 1 commit into
docs/cfn-generate-resource-type-tablefrom
refactor/cfn-leaf-provisioners

Conversation

@hectorvent

Copy link
Copy Markdown
Collaborator

Summary

First slice that actually moves types. Migrates the seven whose provisioning is a single service
call, out of CloudFormationResourceProvisioner's switch and into per-service provisioners:

Provisioner Types
KmsCfnProvisioner AWS::KMS::Key, AWS::KMS::Alias
SsmCfnProvisioner AWS::SSM::Parameter
EcrCfnProvisioner AWS::ECR::Repository
PipesCfnProvisioner AWS::Pipes::Pipe
FirehoseCfnProvisioner AWS::KinesisFirehose::DeliveryStream
CdkMetadataCfnProvisioner AWS::CDK::Metadata

Behaviour-preserving. Bodies are ported verbatim apart from the mechanical rewrites onto
ProvisionContext (enginectx.engine(), region/account/stack → ctx.*, resolveOptional,
generatePhysicalName), so physical ids, Fn::GetAtt keys and delete calls are unchanged. The
generated docs table is byte-identical after this change: only the owner moved, not the types.

Monolith: 7,603 → 7,396 lines; legacy switch 79 → 72 types.

Stacked on #2739#2732. Review those first.

Two judgement calls worth flagging

ProvisionContext.resolveTags was deliberately not substituted for parseCfnTags. They are
not equivalent: resolveTags skips a blank key that parseCfnTags keeps, orders entries by
insertion rather than hash, and resolves the whole property so an Fn::If around the list works.
Swapping would be a silent behaviour change in a move PR, so parseCfnTags is copied into the
three provisioners that need it (as are blankToNull and parseIntProp), each still having
callers left in the monolith. Adoption is filed as a follow-up.

Five service fields left the monolith, but their constructor parameters stayed. Unused
parameters are legal, and shrinking the signature now would churn CfnProvisionerFixture for no
gain; the final cleanup drops all of them at once.

AWS::CDK::Metadata gains a real provisioner rather than being left to the stub arm. The stub
reports CREATE_COMPLETE with a synthetic id and a fake Arn attribute; the real type has no
attributes at all, so the stub was quietly wrong.

Type of change

  • Bug fix (fix:)
  • New feature (feat:)
  • Breaking change (feat!: or fix!:)
  • Docs / chore

refactor(cloudformation): — no user-visible behaviour change, release-neutral.

AWS Compatibility

N/A for the wire protocol. Every migrated type keeps its exact physical id and Fn::GetAtt
attribute keys, verified per type against its CloudFormation registry schema:

Type schema primaryIdentifier / readOnlyProperties asserted
KMS::Key KeyId / Arn, KeyId both keys, exact map
KMS::Alias AliasName / none physical id
SSM::Parameter Name / none physical id + Name/Type/Value
ECR::Repository RepositoryName / Arn, RepositoryUri both keys, exact map
Pipes::Pipe Name / Arn, +4 Arn (see follow-up)
KinesisFirehose::DeliveryStream DeliveryStreamName / Arn exact map

Checklist

  • ./mvnw test passes locally
  • New or updated integration test added
  • Commit messages follow Conventional Commits

CloudFormation + Cloud Control: 835 tests, 0 failures, 0 errors. LeafCfnProvisionerTest adds
20 covering every migrated type: exact physical id, exact Fn::GetAtt keys, delegated arguments
via captors, and delete delegation. The pre-existing CloudFormation integration tests were not
touched, which is the real evidence nothing regressed.

The inventory guard from #2732 is what proves the migration actually took effect: it compares the
checked-in inventory against the CDI-resolved registry, so a provisioner missing
@ApplicationScoped (silently never registered, its types quietly stubbed) fails the build.

Follow-ups, deliberately not fixed here

  1. AWS::Pipes::Pipe sets only Arn. The registry schema also lists CreationTime,
    CurrentState, LastModifiedTime and StateReason as read-only, so Fn::GetAtt on any of
    those resolves to the literal "LogicalId.Attr". Pre-existing, carried over unchanged.
  2. Adopt ProvisionContext.resolveTags across the parseCfnTags call sites once the
    behaviour difference is settled, and delete the copies.

@hectorvent
hectorvent requested a review from pgermosen as a code owner August 29, 2026 23:22
@greptile-apps

greptile-apps Bot commented Aug 29, 2026

Copy link
Copy Markdown

Greptile Summary

The PR moves seven single-service CloudFormation resource types from the monolithic switch into CDI-managed per-service provisioners while preserving their service calls, physical IDs, attributes, and deletion delegation.

  • Adds dedicated provisioners for KMS, SSM, ECR, Pipes, Firehose, and CDK metadata.
  • Removes the migrated dispatch branches and service fields from the monolithic provisioner.
  • Adds focused tests for registration, delegated arguments, resource identities, attributes, and deletion.
  • Updates the checked-in supported-resource ownership inventory.

Confidence Score: 4/5

The PR is not yet safe to merge because the previously reported update path still recreates migrated resources or changes their physical identities.

The extracted provisioners receive update invocations carrying the prior resource identity but do not branch on that state; unnamed ECR repositories and other service-backed resources are created under fresh generated names, while CDK metadata receives a new physical ID.

Files Needing Attention: src/main/java/io/github/hectorvent/floci/services/cloudformation/provisioners/EcrCfnProvisioner.java and the sibling leaf provisioners that unconditionally execute creation logic

Important Files Changed

Filename Overview
src/main/java/io/github/hectorvent/floci/services/cloudformation/CloudFormationResourceProvisioner.java Removes the migrated resource-type branches and delegates their ownership to the provisioner registry.
src/main/java/io/github/hectorvent/floci/services/cloudformation/provisioners/EcrCfnProvisioner.java Extracts ECR repository provisioning and deletion, while the previously reported update-time recreation behavior remains.
src/main/java/io/github/hectorvent/floci/services/cloudformation/provisioners/KmsCfnProvisioner.java Extracts KMS key and alias lifecycle handling, including unconditional key creation when provisioning is invoked for an update.
src/main/java/io/github/hectorvent/floci/services/cloudformation/provisioners/SsmCfnProvisioner.java Extracts SSM parameter provisioning and deletion but continues to run put/create-style logic on updates.
src/main/java/io/github/hectorvent/floci/services/cloudformation/provisioners/FirehoseCfnProvisioner.java Extracts Firehose stream provisioning and deletion while retaining create-style behavior for update invocations.
src/main/java/io/github/hectorvent/floci/services/cloudformation/provisioners/PipesCfnProvisioner.java Extracts EventBridge Pipes provisioning and deletion while retaining unconditional creation on updates.
src/main/java/io/github/hectorvent/floci/services/cloudformation/provisioners/CdkMetadataCfnProvisioner.java Replaces stub ownership with a real provisioner but still generates a new metadata identity whenever provisioning runs.
src/test/java/io/github/hectorvent/floci/services/cloudformation/provisioners/LeafCfnProvisionerTest.java Adds broad create/delete delegation and resource-contract coverage for the extracted provisioners.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    CFN[CloudFormation stack operation] --> Registry[Resource provisioner registry]
    Registry --> KMS[KmsCfnProvisioner]
    Registry --> SSM[SsmCfnProvisioner]
    Registry --> ECR[EcrCfnProvisioner]
    Registry --> Pipes[PipesCfnProvisioner]
    Registry --> Firehose[FirehoseCfnProvisioner]
    Registry --> CDK[CdkMetadataCfnProvisioner]
    KMS --> KmsService
    SSM --> SsmService
    ECR --> EcrService
    Pipes --> PipesService
    Firehose --> FirehoseService
    CDK --> Identity[Metadata physical ID]
Loading

Reviews (2): Last reviewed commit: "refactor(cloudformation): move the singl..." | Re-trigger Greptile

Map<String, String> tags = parseCfnTags(props != null ? props.get("Tags") : null, ctx);

Repository repo;
try {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Update path recreates resources

When UpdateStack dispatches with the prior physical ID and attributes, these extracted provisioners ignore that state and execute create logic again, causing migrated resources to be recreated or overwritten and CDK metadata to receive a new identity.

Context Used: AGENTS.md (source)

@pgermosen pgermosen added the cloudformation AWS CloudFormation label Aug 30, 2026

@pgermosen pgermosen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving. On greptile's finding about the update path recreating resources / CDK metadata getting a new identity each time: I pulled the exact pre-migration provisionEcrRepository and provisionCdkMetadata methods from the monolith's history and diffed them against these new provisioners. Both are byte-identical in behavior — no create-vs-update branching existed before this move either. So this is a real, pre-existing gap across the CFN provisioner set, not something this migration introduced. The "ported verbatim" claim holds up.

One small correction for the description: CDK::Metadata actually had its own dedicated provisionCdkMetadata case before, not the generic stub arm — doesn't change anything functionally, both generated a random UUID every call.

Migrates the seven resource types whose provisioning is one service call:
KMS Key and Alias, SSM Parameter, ECR Repository, Pipes Pipe, Kinesis
Firehose DeliveryStream, and CDK Metadata. Behaviour-preserving move: the
bodies are ported verbatim apart from the mechanical rewrites onto
ProvisionContext, so physical ids, Fn::GetAtt keys and delete calls are
unchanged.

Each provisioner injects only the service it wraps, so five service fields
leave the monolith. Their constructor parameters stay, unused, until the
final cleanup drops them all at once; shrinking the signature now would
churn the fixture for no gain.

parseCfnTags, blankToNull and parseIntProp are copied rather than shared,
because each still has callers in the monolith. ProvisionContext.resolveTags
is deliberately NOT substituted for parseCfnTags: it skips a blank key that
parseCfnTags keeps, orders entries by insertion rather than hash, and
resolves the whole property so an Fn::If around the list works. Adopting it
is a behaviour change and belongs in its own PR.

CDK::Metadata gains a real provisioner rather than staying on the stub arm.
The stub reports CREATE_COMPLETE with a synthetic id and a fake Arn
attribute; the real type has no attributes at all.

Tests assert the exact physical id and the exact Fn::GetAtt keys against
each type's registry schema, plus delegated arguments and delete calls.
Asserting status alone would pass against the stub arm.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cloudformation AWS CloudFormation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants