You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/changelog-cdkd.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,6 +18,8 @@ The CLAUDE.md `## Known Limitations` section retains the load-bearing summary
18
18
19
19
**Recently Implemented** (2026-06-15):
20
20
21
+
- ✅ **Fix: stop unwrapping `AWS::CloudFront::Distribution.OriginGroups` in drift readback (closes the OriginGroups phantom drift, issue [#873](https://github.com/go-to-k/cdkd/issues/873))** — `src/provisioning/providers/cloudfront-distribution-provider.ts`. **Bug:** `OriginGroups` was listed in `QUANTITY_ITEM_FIELDS` (the top-level fields that are a bare array in CFn and a `{ Quantity, Items }` wrapper in the SDK, so cdkd wraps them on write and unwraps them on read). But unlike `Origins` / `CacheBehaviors` / `Aliases` / `CustomErrorResponses` (genuinely bare lists in CFn), the CFn `DistributionConfig.OriginGroups` property is ITSELF a `{ Quantity, Items }` object — confirmed by synthesizing a distribution with an origin group (`Quantity` + `Items[]`, each item carrying inner `{ Quantity, Items }` `Members` and `FailoverCriteria.StatusCodes`). So `convertToCfnFormat` was unwrapping the top-level OriginGroups to a bare array, which no longer matched the template's `{ Quantity, Items }`, firing phantom drift on every `cdkd drift` for any distribution with an origin group. (#871 had suppressed OriginGroups via `getDriftUnknownPaths` as a stopgap, under the mistaken assumption — from that PR's review — that the inner Members/StatusCodes were bare arrays needing a `revertOriginGroup`; the synth evidence shows the whole subtree is `{ Quantity, Items }`, so the real fix is the opposite: don't touch it at all.) **Fix:** remove `OriginGroups` from `QUANTITY_ITEM_FIELDS` so it passes through UNTOUCHED in both directions (create still works — `wrapWithQuantity` was a no-op on the already-`{ Quantity, Items }` value), and remove `DistributionConfig.OriginGroups` from `getDriftUnknownPaths` so origin-group drift is now actually reported. 1 new unit test (OriginGroups `{ Quantity, Items }` with inner Members/StatusCodes passes through byte-equal, not unwrapped); `getDriftUnknownPaths` test updated. Validated against real AWS: the `s3-cloudfront` fixture gains an `OriginGroup` (primary S3-OAI origin + HTTP fallback + failover status codes), and `verify.sh` asserts the distribution carries exactly 1 OriginGroup AND that the whole distribution (OriginGroups now included) reports clean on a fresh deploy.
22
+
21
23
- ✅ **Fix: canonicalize CloudFront OAI grant principals in `S3BucketPolicyProvider.readCurrentState` (closes the phantom drift on an S3 BucketPolicy granting an OAI, issue [#872](https://github.com/go-to-k/cdkd/issues/872))** — `src/provisioning/providers/s3-bucket-policy-provider.ts`. **Bug:** a bucket policy statement that grants a CloudFront Origin Access Identity (OAI) read access stores its principal as the OAI's S3 canonical user id (`{ CanonicalUser: <64-hex> }`, what CDK's `Fn::GetAtt [<OAI>, S3CanonicalUserId]` resolves to). But `s3:GetBucketPolicy` returns that same principal in TWO other unstable forms over the policy's lifetime: a transient `{ AWS: <IAM-unique-id> }` (e.g. `AIDA…`) right after `PutBucketPolicy`, then the settled `{ AWS: arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <id> }`. The drift comparator saw these three equivalent representations as different and fired a guaranteed false positive on every `cdkd drift` run for any stack with an OAI + S3 bucket policy (the deploy-time `observedProperties` capture caught the transient unique-id form; the later drift read got the ARN form — neither matched the template's canonical user id). **Fix:** `readCurrentState` now canonicalizes every recognizable OAI principal back to `{ CanonicalUser: <id> }`. For the settled `arn:…:cloudfront:user/…<oaiId>` form it maps the OAI id to its `S3CanonicalUserId`, **preferring the same-stack sibling OAI resource's already-read state attribute** (zero AWS call / no `cloudfront:GetCloudFrontOriginAccessIdentity` IAM grant — the OAI's `S3CanonicalUserId` is a readOnly attribute cdkd already resolved at deploy time, threaded into the drift read via the new `ReadCurrentStateContext.siblings[].attributes` + `.physicalId` fields) and falling back to `GetCloudFrontOriginAccessIdentity(<oaiId>)` only when the OAI is NOT a same-stack sibling (an imported / external OAI). The transient bare-IAM-unique-id form (which carries no recoverable link to the OAI) is canonicalized only by matching the corresponding template statement (same Effect / Action / Resource) carrying a `{ CanonicalUser }` principal — safe because a user cannot author a bare IAM unique id as a bucket-policy principal, so it only ever fires for AWS's transient rendering. Both the deploy-time capture and the drift read run through the same normalization, so both converge to the canonical user id and compare equal; a genuinely-different OAI resolves to a different canonical id so real drift is still detected (strict reconcile — never a blanket suppress). Non-OAI principals (`*`, service principals, normal role ARNs) are untouched. The `ReadCurrentStateContext.siblings` shape gained optional `physicalId` + `attributes` (populated by `buildReadCurrentStateContext` in `src/cli/commands/drift.ts`) so any provider can reconcile a sibling's computed identity from already-read state without an extra AWS call. 13 unit tests (ARN→CanonicalUser via sibling state attribute with NO CloudFront call; strict-reconcile: a DIFFERENT OAI resolves to a DIFFERENT canonical id so real drift is NOT suppressed; AWS-array principal + ambiguous-template-match left unchanged; ARN→CanonicalUser via `GetCloudFrontOriginAccessIdentity` fallback when not a sibling; bare-unique-id→template-match; no-template-match left unchanged; best-effort ARN-lookup-failure left unchanged; non-OAI principals untouched; one CloudFront call cached across statements). Validated against real AWS by extending the `s3-cloudfront` integ's `verify.sh` to assert the `AWS::S3::BucketPolicy` reports clean (in the `clean` drift bucket, not `drifted`) on a fresh deploy — the distribution-scoping caveat the CloudFront PR (#871) added is removed now that the bucket policy no longer phantom-drifts. (Approach mirrors the sibling cdk-real-drift project's fix per the #872 cross-note: read the OAI's `S3CanonicalUserId` from already-read state rather than re-fetching it.)
0 commit comments