+- ✅ **CloudFront Distribution: CFn -> SDK casing/shape maps + UpdateDistribution read-modify-write merge** (issues #1370, #1371 — both externally reported) — `src/provisioning/providers/cloudfront-distribution-provider.ts`, plus unit tests in `tests/unit/provisioning/cloudfront-distribution-provider.test.ts` and an UPDATE phase + casing assertions added to the `tests/integration/s3-cloudfront/` fixture. **(#1370)** `convertToSdkFormat` passed most `DistributionConfig` keys through verbatim, but three `ViewerCertificate` members (`AcmCertificateArn` / `SslSupportMethod` / `IamCertificateId`) and top-level `IPV6Enabled` differ in ACRONYM CASING between the CFn schema and the CloudFront API (`ACMCertificateArn` / `SSLSupportMethod` / `IAMCertificateId` / `IsIPV6Enabled`), and `Restrictions.GeoRestriction` carries a bare CFn `Locations` array where the SDK wants `{ RestrictionType, Quantity, Items }` — so a custom-domain distribution failed to create ("Your ViewerCertificate is missing one of ACMCertificateArn, IAMCertificateId, or CloudFrontDefaultCertificate"), IPv6 silently ended up disabled, and a geo restriction never reached AWS. Both directions are now mapped (`convertToSdkFormat` + the `convertToCfnFormat` inverse, so `cdkd drift` compares in CFn spelling with no phantom drift). The pre-flight property-coverage check cannot catch this class (it compares TOP-LEVEL properties only; `DistributionConfig` is handled) — the nested-sub-property audit remains tracked under the #1160/#1225 umbrella. **(#1371)** `update()` documented itself as merging the current config but actually sent the template's `DistributionConfig` verbatim (only `CallerReference` was reused), while `UpdateDistribution` is a read-modify-write API expecting the COMPLETE config — so EVERY update of a distribution failed on the first required-on-update member the template legitimately omits ("WebACLId is missing for the resource"). The new `mergeUpdateConfig` merges per top-level member: template is the authority for members it carries, the live config fills members it never templated, and a member REMOVED since the previous template resets to its CloudFormation default (`REMOVAL_RESET_DEFAULTS`, sourced from the registry schema's `default` annotations + empty-list wrappers + the documented Logging-off shape) — members with no documented default (e.g. `IsIPV6Enabled` / `Staging`) keep their live value with a WARN instead of a silent guess. `convertToSdkFormat` also stopped mutating its input's nested `Logging` object (state-sourced `previousProperties` now flow through it). The live UPDATE run then surfaced a SECOND required-field layer: the API accepts SPARSE `Origins` / cache-behavior sub-shapes on CREATE but rejects them on UPDATE ("The 'OriginCustomHeaders' field is missing" / "OriginReadTimeout is required for updates" / "The parameter SmoothStreaming flag is missing" / field-level-encryption-id / allowed-method-settings / lambda-function-associations), so `mergeUpdateConfig` now runs `completeRequiredUpdateFields` — an absent-only fill of the empirically probed required set (per origin: `OriginPath` '' + `CustomHeaders` empty + CustomOriginConfig read/keepalive timeouts 30/5; per cache behavior: `SmoothStreaming` false, `FieldLevelEncryptionId` '', `LambdaFunctionAssociations`/`FunctionAssociations` empty, `TrustedSigners`/`TrustedKeyGroups` disabled, `AllowedMethods` GET/HEAD default with nested `CachedMethods`) — validated by driving the exact payload to a live `UpdateDistribution` success. The probe also exposed two more members of the casing/shape family, fixed in both directions: the CFn template spelling `CustomOriginConfig.OriginSSLProtocols` (capital SSL) never matched the converter's `OriginSslProtocols` lookup (the protocol list was silently dropped on every create), and the CFn SIBLING `CachedMethods` array was never nested inside the SDK's `AllowedMethods` wrapper (`revertCacheBehavior` has always hoisted it back out — the forward direction was simply missing). The first live run of the extended fixture immediately caught a third defect the shape fix newly exposed: CloudFront does not preserve the submitted order of `GeoRestriction` country codes (template `[JP, US]` read back `[US, JP]`), so the positional drift compare fired guaranteed phantom drift on any multi-country restriction — `getDriftUnorderedPaths` now declares `DistributionConfig.Restrictions.GeoRestriction.Locations` as an unordered set (the FSx `WindowsConfiguration.Aliases` precedent, issue #1096 mechanism). Live-verified end-to-end by the extended `s3-cloudfront` integ: create asserts `IsIPV6Enabled=true` + the geo allowlist reached AWS, drift reports clean on the fresh deploy, the new Phase 1.5 re-deploys with `CDKD_TEST_UPDATE=true` (comment + geo change) through the merge — a phase that failed unconditionally before #1371 — and destroy completes clean.
0 commit comments