fix(ecr): wire ImageTagMutabilityExclusionFilters onto the create and mutability calls - #1406
Merged
Merged
Conversation
… mutability calls
ECRProvider declared ImageTagMutabilityExclusionFilters in handledProperties
but never sent it: CreateRepository omitted it and the update path's
PutImageTagMutability sent only imageTagMutability. A repository using
IMMUTABLE_WITH_EXCLUSION therefore lost its exclusions silently, while the
property-coverage pre-flight passed on the false handled claim.
The member names diverge (not just their casing): CFn
{ImageTagMutabilityExclusionFilterType, ImageTagMutabilityExclusionFilterValue}
vs SDK {filterType, filter}, so the blob cannot be forwarded verbatim.
- Map CFn to SDK on create and on PutImageTagMutability.
- Fire the update on a filters-only change (both members ride the same call,
and imageTagMutability is a required member, so it is re-sent).
- Read the filters back off DescribeRepositories through the inverse mapping
so drift compares against a template-shaped baseline, and correct the
readCurrentState comment that claimed the property was not readable.
- Extend the ecr-scanning integ fixture to deploy IMMUTABLE_WITH_EXCLUSION
with a filter, then change ONLY the filters on the UPDATE phase, asserting
both reach AWS.
Closes #1392
go-to-k
force-pushed
the
fix/1392-ecr-tag-mutability-exclusion
branch
from
August 9, 2026 06:01
9d71e62 to
48983bf
Compare
github-actions Bot
pushed a commit
that referenced
this pull request
Aug 9, 2026
## [0.278.6](v0.278.5...v0.278.6) (2026-08-09) ### Bug Fixes * **ecr:** wire ImageTagMutabilityExclusionFilters onto the create and mutability calls ([#1406](#1406)) ([5518934](5518934))
|
🎉 This PR is included in version 0.278.6 🎉 The release is available on: Your semantic-release bot 📦🚀 |
go-to-k
added a commit
that referenced
this pull request
Aug 9, 2026
…first run caught gen-property-coverage verifies every CFn property is ACCOUNTED FOR (declared in handledProperties or unhandledByDesign); gen-nested-key-coverage audits spellings INSIDE a forwarded blob. Neither checks that a handledProperties entry is actually WIRED. ECRProvider declared ImageTagMutabilityExclusionFilters handled while the property appeared on NO API call, so the pre-flight passed on the declaration alone and the value silently vanished (#1392, fixed in #1406) -- a FALSE handled claim, the exact thing the declaration system exists to prevent. The critic requires per-property read evidence in one of four AST shapes (element-read, property-read, destructure, table-loop), plus a delegated tag when the read happens in a callable reached by a call edge. Evidence is CLASS-SCOPED via a taint walk seeded from each method's desired-state parameter and propagated only through calls that pass the bag WHOLE, so a sibling class in the same file, a comment, a getDriftUnknownPaths entry, the declaration itself, and a readCurrentState write-back all fail to vouch for a property. Two strictness decisions were forced by the real tree, not by fixtures: - A whole-bag forward does NOT blanket-excuse un-read declarations. The first draft's excuse silenced the very #1392 property via ECRProvider's hasCdkAutoDeleteTag(properties) call in delete(); measured across the tree it rescued 0 of 1063 properties. Blind spots are recorded for visibility only. - A read of previousProperties is NOT evidence: a diff-only read proves change DETECTION, not delivery. Also 0 of 1063 today, so the strictness is free now and closes the disguise later. Coverage floors are per SHAPE rather than a grand total (84 classes / 1063 properties), with property-read and destructure pinned === 0 so a future first user cannot regress those recognizers silently. The first real-tree run found two live gaps, seeded as KNOWN GAP allow-list entries and FILED rather than fixed here (this PR introduces the tool; the fixes are separate): AWS::EC2::NatGateway.MaxDrainDurationSeconds (#1411) and AWS::Logs::LogGroup.ResourcePolicyDocument (#1412). IAMAccessKeyProvider#Serial and NestedStackProvider#TemplateURL are rationale'd NOT-A-BUG entries. Stale entries fail in both modes, so wiring a property forces its entry's removal. Real-code fail probe (the repo's checker rule, re-run independently): reverting the real ecr-provider.ts to its pre-#1406 state makes --check exit 1 naming ECRProvider#ImageTagMutabilityExclusionFilters, and the file restores byte-identical. A first probe that stripped only the lowercase-p reads PASSED -- the surviving previousProperties read cleared it -- and that false clean is what drove the previousProperties exclusion; both variants are now automated. Closes #1404
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
ECRProviderdeclaredImageTagMutabilityExclusionFiltersinhandledPropertiesbut sent it on no API call:CreateRepositoryomitted it entirely and update'sPutImageTagMutabilitysent onlyimageTagMutability. A repository usingIMMUTABLE_WITH_EXCLUSIONtherefore lost its exclusions silently, while theproperty-coveragepre-flight passed on the strength of the false handled claim.The member names diverge — not just their casing — so the blob cannot be forwarded verbatim: CFn
{ImageTagMutabilityExclusionFilterType, ImageTagMutabilityExclusionFilterValue}vs SDK{filterType, filter}(@aws-sdk/client-ecrmodels_0.d.ts:591-603).What changed
CreateRepositoryRequest(:663) and toPutImageTagMutabilityRequest(:3549), both verified against the installed model. Absent / empty lists omit the key rather than sending[], matching the provider's existing spread idiom.PutImageTagMutabilitycall, and the old gate only comparedImageTagMutability— so a filters-only edit (exclusion mode throughout, only the patterns changing) never reached AWS at all.imageTagMutabilityis a required member of that request, so it is re-sent alongside the new filters.DescribeRepositoriesreturns the value on theRepositoryshape (:725), soreadCurrentStatereads it back through the inverse mapping and compares against a template-shaped baseline. The stale comment claiming the property was "not part of the persisted AWS state" is corrected;EmptyOnDeletestays in the omitted list with an accurate reason.Test plan
[]" contract./run-integ ecr-scanning, us-east-1). The fixture now deploysIMMUTABLE_WITH_EXCLUSIONwith one filter (dev-*), then changes only the filters on the UPDATE phase (two different patterns, mutability unchanged) — precisely the case the old gate skipped. Phase 1 assertedimageTagMutability, the filter pattern and theWILDCARDfilter type all reached AWS; Phase 2 asserted the changed patterns landed. Destroy 2 deleted / 0 errors / 0 orphans.Won't-do (recorded)
Removal semantics — dropping the property omits the key rather than sending
[]— are documented in an in-code comment but not covered by the integ.PutImageTagMutabilityis a full-replace setter, and the only reachable removal path is a mutability change away from an exclusion mode (AWS rejects an exclusion mode with no filters), which already fires the call with the key omitted. Building a fixture phase for the unreachable case is not worth the extra deploy cycle.Known gap
A repository deployed by a pre-fix binary carries
ImageTagMutabilityExclusionFiltersin its statepropertieswhile AWS has none, and itsobservedPropertieswere captured by the old reader that omitted the key — so neither a no-change redeploy norcdkd driftheals it. Any template edit that reachesPutImageTagMutabilitydoes. Not worth a migration for a property this new.Follow-ups
handledPropertiescan lie (audit:handledPropertiescan lie — a property declared handled but named on NO API call passes the property-coverage pre-flight #1404): a property declared handled but named on no API call passes theproperty-coveragepre-flight, which is exactly what let this bug through. Proposes a critic, filed from this work.AWS::ECR::Repositoryis not inNESTED_KEY_TARGETS, so the nested-key critic would not have caught this class here. That target expansion is tracked in (audit: nested-key critic blind spots found by the 0809 sweep — mixed-case SDK models, file-global literal heuristic, missing targets, selective sub-key forwards #1393).Closes #1392