fix(provisioning): enrich AWS::RDS::DBInstance Endpoint attributes on the Cloud Control path - #844
Merged
Conversation
…custom subnet/param groups New `tests/integration/rds-full-stack/` fixture (`CdkdRdsFullStackExample`, 15 synthesized resources). Test-only; no `src/` change. The two existing RDS fixtures use L1 (`CfnDBInstance` / `CfnDBCluster`) and target #609 silent-drop closure + the `provisionedBy=sdk` routing guard. Neither uses an explicit DBSubnetGroup + DBParameterGroup pair on an L2 `rds.DatabaseInstance`, and neither consumes a DBInstance's COMPUTED endpoint via a downstream reference. This fixture covers exactly that angle. Topology: VPC (natGateways:0, isolated subnets) + explicit rds.SubnetGroup + explicit rds.ParameterGroup (Postgres 17.4, non-default application_name) + explicit SecurityGroup + a small rds.DatabaseInstance (db.t3.micro, single-AZ, 20 GiB gp2, CDK-managed Secrets Manager credentials, deletionProtection false, RemovalPolicy DESTROY, no final snapshot) + an ssm.StringParameter whose value is Fn::GetAtt(<Database>, Endpoint.Address). Stresses cdkd's event-driven DAG + intrinsic resolution under a slow-create resource: cdkd must create the sub-groups + SG before the instance (Ref edges), wait ~5-10 min for the instance to become available, read its computed Endpoint.Address attribute back, then create the SSM Parameter with the resolved value. verify.sh (BSD/macOS-portable, real-rc capture, explicit [verify] PASS): - deploys (dumps state on failure for triage) - asserts the instance uses the custom subnet group + parameter group, and the group carries the non-default application_name - asserts the SSM parameter value equals the LIVE DescribeDBInstances endpoint address (proves the computed Fn::GetAtt resolved post-create) - destroys and asserts the instance, subnet group, parameter group, SSM parameter, and state file are all gone with 0 orphans - cleanup trap deletes in RDS-safe order (instance first + wait, then groups, then SG / VPC) Slow by RDS nature (~10-20 min end-to-end) — acceptable + expected. New scenario tag `rds-full-stack` in KNOWN_SCENARIOS; coverage matrices regenerated; changelog + README added. NOTE: not yet run against real AWS — needs /run-integ rds-full-stack before merge.
The real-AWS run failed at DBInstance create with: Cannot find version 17.4 for postgres (Service: Rds, Status Code: 400) PostgreSQL 17.4 is not offered for new DBInstances in us-east-1. Pin the fixture to 16.9, which is listed by: aws rds describe-db-engine-versions --engine postgres --region us-east-1 Both call sites are updated so the engine version and parameter-group family stay consistent: - rds.DatabaseInstance engine -> PostgresEngineVersion.VER_16_9 - rds.ParameterGroup engine -> PostgresEngineVersion.VER_16_9 (CDK derives the family from the major version, so the synthesized DBParameterGroup Family is now postgres16, matching the major) Synth confirms EngineVersion "16.9" + Family "postgres16" in the template. README updated to reflect 16.9 / postgres16. Informational note (not addressed here, separate #609 concern): the deploy log shows the RDS DBInstance routed via the Cloud Control API because cdkd's SDK provider does not yet wire BackupRetentionPeriod / CopyTagsToSnapshot / DBParameterGroupName / DeleteAutomatedBackups / MultiAZ / StorageType (silent-drop -> #614 routing). That is expected and acceptable: the CC-API path forwards the full property map, and the GetAtt(Endpoint.Address) -> SSM-parameter assertion validates on both the SDK and the CC-API path. No backfill is attempted here. Everything else is unchanged: the DBSubnetGroup + DBParameterGroup + SG, the SSM-parameter-from-GetAtt(Endpoint.Address) assertion, the RDS-safe destroy ordering, removalPolicy DESTROY, no final snapshot, and deletionProtection false (clean + cheap teardown).
…arsing The application_name assertion read the parameter value via `describe-db-parameters ... --query '...ParameterValue | [0]' --output text`, which under `--output text` could render a trailing "None" (a null/second field) on its own line, yielding "cdkd-rds-full-stack\nNone" and failing the equality check against the expected "cdkd-rds-full-stack". Switch the readback to `--output json` piped through `jq -r '. // "null"'` so the JMESPath `[0]` scalar is unwrapped to exactly the parameter value (or the literal "null" when absent), eliminating the multi-line text-mode contamination. No engine-version or other changes.
Add an AWS::RDS::DBInstance case to CloudControlProvider's enrichResourceAttributes, mirroring the existing AWS::RDS::DBCluster case (issue #381). When a DBInstance template sets a silent-drop top-level property (BackupRetentionPeriod / CopyTagsToSnapshot / MultiAZ / PubliclyAccessible / StorageType etc.), the #614 routing rule sends the whole resource through Cloud Control API, bypassing RDSProvider.create. RDSProvider.create is the only path that populated the flat-key attributes['Endpoint.Address'] / ['Endpoint.Port'], so a CC-routed DBInstance had no endpoint attributes and Fn::GetAtt(<DBInstance>, 'Endpoint.Address') / 'Endpoint.Port' fell through the resolver's constructAttribute branch to the DB identifier (physicalId) instead of the real endpoint hostname / port. The new case calls DescribeDBInstances once after create and overlays the flat-key Endpoint.Address / Endpoint.Port (coerced to string) / Endpoint.HostedZoneId / Arn attributes. SHAPE DIFFERENCE vs DBCluster: DescribeDBInstances returns Endpoint as a nested object { Address, Port, HostedZoneId }, not a flat string, so the values are read off the nested object. Best-effort: a failed Describe logs a debug line and leaves the CC-API attribute shape unchanged so it never fails the deploy. This is the CC-API DBInstance endpoint-enrichment parity fix for the GetAtt Endpoint.Address bug found by the rds-full-stack failure-seeking integ. Adds two unit tests (happy-path overlay + best-effort Describe failure).
Owner
Author
|
Independent review complete: pr-code-reviewer + pr-test-reviewer ran (3-axis; spec-reviewer N/A for a bug fix without a design doc). No blockers. One minor nit accepted as known cost: the rds-full-stack verify.sh post-destroy DBInstance assertion accepts |
github-actions Bot
pushed a commit
that referenced
this pull request
Jun 13, 2026
## [0.221.2](v0.221.1...v0.221.2) (2026-06-13) ### Bug Fixes * **provisioning:** enrich AWS::RDS::DBInstance Endpoint attributes on the Cloud Control path ([#844](#844)) ([bc4e44d](bc4e44d))
|
🎉 This PR is included in version 0.221.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
go-to-k
added a commit
that referenced
this pull request
Jun 15, 2026
Add a codegen + CI critic that makes the CC-API enrichment-gap bug class (#844 / #864 / #865 / #866) non-regressing. enrichResourceAttributes in cloud-control-provider.ts is a hand-maintained switch; previously nothing prevented a new CC-routed type with a computed readOnly Fn::GetAtt attribute from silently falling through the intrinsic resolver to the physicalId. scripts/gen-enrichment-coverage.ts (modeled on gen-property-coverage / gen-unsupported-types) parses the enrichResourceAttributes switch via the TypeScript Compiler API, cross-references each type's readOnlyProperties from the cached CFn schema fixtures, and classifies every CC-routable type into: enriched / no-computed-attr / sdk-fallback-gap (gap only on the #614 CC-fallback path, informational) / unenriched-computed (gap on a pure-CC type with no SDK provider, the real bug class). The audit:enrichment-coverage:check critic hard-fails ONLY on unenriched-computed. A readOnly prop that is the type's primaryIdentifier is auto-classified not-a-gap; refresh-cfn-schemas.mjs now captures primaryIdentifier into the fixtures so this is data-driven going forward. Seed ENRICHMENT_ALLOW_LIST carves out MSK::Cluster (Arn == primaryIdentifier) and Elasticsearch::Domain (Tier-3 non-provisionable). Current offline classification: 114 CC-routable types, 0 pure-CC latent gaps (every cached schema today is an SDK-backed Tier 1 type, so the critic passes by construction and becomes load-bearing the moment a pure-CC type's schema is cached). 98 SDK-fallback gaps reported informationally for a future #614-hardening pass; 8 enrichment cases lack a cached schema and are listed as needing a fixture refresh. - Emit docs/_generated/enrichment-coverage.{json,md} - vp run gen:enrichment-coverage + vp run audit:enrichment-coverage:check - CI staleness guard + critic step in ci.yml - 20 unit tests (switch parser, classifier buckets, buildReport) No AWS integ (pure static analysis / codegen); diff touches no integ-gate scope.
This was referenced Jun 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Enriches an
AWS::RDS::DBInstance's computed endpoint attributes on the Cloud Control provisioning path so a downstreamFn::GetAtt(<db>, 'Endpoint.Address')resolves to the real endpoint hostname instead of the raw physical id.Root cause
CloudControlProvider.enrichResourceAttributes(src/provisioning/cloud-control-provider.ts) had a per-type case forAWS::RDS::DBCluster(added per #381) but none forAWS::RDS::DBInstance.When a
DBInstancetemplate sets even one #614 silent-drop top-level property (e.g.BackupRetentionPeriod/CopyTagsToSnapshot/MultiAZ/PubliclyAccessible/StorageType), the #614 routing rule sends the entire resource through the Cloud Control API and bypassesRDSProvider.create. The SDK provider would normally populate the flat-keyEndpoint.Address/Endpoint.Portattributes after create; on the CC-API path those attributes were never set, so a downstream consumer doingFn::GetAtt(<DBInstance>, 'Endpoint.Address')fell through the resolver'sconstructAttributebranch to thephysicalId(the DB identifier, not the endpoint hostname).Fix
Add a parallel
AWS::RDS::DBInstancecase toenrichResourceAttributesthat issuesDescribeDBInstancesafter create and flattens the result into the SDK provider's flat-key attribute shape:Endpoint.AddressEndpoint.PortEndpoint.HostedZoneIdArnShape note: unlike the DBCluster case (whose
Endpoint/ReaderEndpointare flat scalars),DescribeDBInstancesreturnsEndpointas a NESTED object{ Address, Port, HostedZoneId }, so the case flattens it. The lookup is best-effort: a failedDescribeleaves the CC-API attribute shape unchanged and never fails the deploy (the resolver's nested-path walk is the second line of defence), exactly matching the DBCluster branch.Tests
tests/unit/provisioning/cloud-control-provider.test.tscover the new DBInstance case (endpoint/port/hosted-zone/ARN flattening from the nestedEndpointobject, plus the best-effort Describe-failure path).rds-full-stackfailure-seeking integ (tests/integration/rds-full-stack/**): a VPC (no NAT) + explicitrds.SubnetGroup+ explicitrds.ParameterGroup(Postgres, non-defaultapplication_name) + SecurityGroup + a smallrds.DatabaseInstance(db.t3.micro, 20 GiB, CDK-managed Secrets Manager credentials, no final snapshot) + anssm.StringParameterwhose value isFn::GetAtt(<Database>, Endpoint.Address). The integ asserts the SSM parameter value equals the LIVEDescribeDBInstancesendpoint address (proving the computedFn::GetAttresolved post-create), then destroys and asserts the instance, subnet group, parameter group, SSM parameter, and state file are all gone with 0 orphans. New scenario tagrds-full-stack; coverage matrices regenerated.Validation
Validated GREEN end-to-end against real AWS (
/run-integ rds-full-stack): deploy clean, the computed-endpointFn::GetAttresolved to the live endpoint address, destroy reported 15 deleted / 0 errors, and the post-destroy orphan sweep was empty (0 orphans).