@go-to-k/cdkd 0.281.18 → 0.281.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/{asg-provider-CRgl7pV6.js → asg-provider-Cv9YCLsx.js} +2 -2
- package/dist/{asg-provider-CRgl7pV6.js.map → asg-provider-Cv9YCLsx.js.map} +1 -1
- package/dist/cli.js +314 -32
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-D-0t_IlI.js → deploy-engine-C3-CvvrB.js} +61 -4
- package/dist/deploy-engine-C3-CvvrB.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-D-0t_IlI.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as configStringRefusal, $t as CFN_TEMPLATE_URL_LIMIT, A as green, At as validateContainerRepoName, B as slowCcOperationTimeoutMs, Bt as synthesisStatusMessage, C as MULTI_REGION_RECREATE_BLOCKED_TYPES, Cn as PartialFailureError, Ct as rewriteTemplateAssetReferences, D as bold, Dn as StackHasActiveImportsError, Dt as getBootstrapMarkerKey, E as formatResourceLine, En as ResourceUpdateNotSupportedError, Et as ensureAssetStorage, F as clearOnUpdateRemoval, Ft as runDockerForeground, G as getAccountInfo, Gt as resolveCaptureObservedState, H as isTerminationProtectionPropagationError, Ht as getLegacyStateBucketName, I as ProviderRegistry, It as runDockerStreaming, J as normalizeAwsTagsToCfn, Jt as resolveStateBucketWithDefaultAndSource, K as refStateLookupFromResource, Kt as resolveSkipPrefix, L as findActionableSilentDrops, Lt as AssetManifestLoader, M as yellow, Mt as buildDockerImage, N as IAMRoleProvider, Nn as normalizeAwsError, Nt as formatDockerLoginError, O as cyan, On as StackTerminationProtectionError, Ot as parseBootstrapMarker, P as collectInlinePolicyNamesManagedBySiblings, Pn as withErrorHandling, Pt as getDockerCmd, Q as configBooleanRefusal, Qt as CFN_TEMPLATE_BODY_LIMIT, R as findSilentDropProperties, Rt as getDockerImageBySourceHash, S as extractDeploymentEventError, Sn as NestedStackChildDirectDestroyError, St as loadPublishableAssetManifest, T as renderStatefulReason, Tn as ResourceTimeoutError, Tt as BOOTSTRAP_MARKER_PREFIX, U as IntrinsicFunctionResolver, Ut as resolveApp, V as disableInstanceApiTermination, Vt as getDefaultStateBucketName, W as cfnRefValueFromPhysicalId, Wt as resolveAutoAssetStorage, X as assertRegionMatch, Xt as stateBucketExistenceConfirmed, Y as resolveExplicitPhysicalId, Yt as resolveUseCdkBootstrapAssets, Z as coerceCfnBoolean, Zt as warnDeprecatedNoPrefixCliFlag, _ as createPreDeleteFinalSnapshot, _n as LocalInvokeBuildError$1, _t as AssetPublisher, a as DeploymentEventsStore, an as processStackMessages, at as applyRoleArnIfSet, b as unsupportedFinalSnapshotError, bt as buildAssetRedirectMap, c as replayFailedOperations, cn as AwsClients, ct as withRetry, d as IMPLICIT_DELETE_DEPENDENCIES, dn as setAwsClients, dt as DagBuilder, en as MIGRATE_TMP_PREFIX, et as readConfigString, f as computeImplicitDeleteEdges, ft as TemplateParser, g as ccRoutedFinalSnapshotError, gn as DeployCancelledError, gt as shouldRetainResource, h as buildFinalSnapshotIdentifier, ht as rebuildClientForBucketRegion, i as DeploymentEventsReader, in as AssemblyReader, it as requireConfigString, j as red, jt as derivePartitionAndUrlSuffix, k as gray, kt as validateAssetBucketName, l as replayRollback, ln as getAwsClients, lt as isRetryableTransientError, m as PRE_DELETE_SNAPSHOT_TYPES, mt as S3StateBackend, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as uploadCfnTemplate, nt as requireConfigArray, o as planFailedOps, ot as DiffCalculator, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as CdkdError, pt as LockManager, q as WAFv2WebACLProvider, qt as resolveStateBucketWithDefault, r as DeployEngine, rn as expectedOwnerParam, rt as requireConfigObject, s as planRollback, sn as resolveBucketRegion, st as describeTypeWithThrottleRetry, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as findLargeInlineResources, tt as replayWarn, u as withResourceDeadline, un as resetAwsClients, ut as isThrottlingError, v as isFinalSnapshotError, vn as LocalMigrateError, vt as stringifyValue, w as isStatefulRecreateTargetSync, wn as ProvisioningError, wt as AssetModeResolver, x as makeCanonicalizePropertiesFn, xn as MissingCdkCliError, xt as createAssetRedirectResolver, y as refusesFinalSnapshot, yn as LocalStartServiceError, yt as WorkGraph, z as CloudControlProvider, zt as Synthesizer } from "./deploy-engine-C3-CvvrB.js";
|
|
3
3
|
import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, h as withStackName, i as runStackBuffered, m as withSkipPrefix, n as getLogger, o as PATTERN_B_NAME_OPTIONS, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-zRrlbaQt.js";
|
|
4
|
-
import { t as ASGProvider } from "./asg-provider-
|
|
4
|
+
import { t as ASGProvider } from "./asg-provider-Cv9YCLsx.js";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
7
7
|
import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -5048,7 +5048,12 @@ const INVENTORY_DEFAULT_SCHEDULE_FREQUENCY = "Weekly";
|
|
|
5048
5048
|
*/
|
|
5049
5049
|
function effectiveInventoryItem(item, sent) {
|
|
5050
5050
|
const patch = {};
|
|
5051
|
-
|
|
5051
|
+
const declaredEnabled = item["Enabled"];
|
|
5052
|
+
if (declaredEnabled === void 0) patch["Enabled"] = INVENTORY_DEFAULT_ENABLED;
|
|
5053
|
+
else {
|
|
5054
|
+
const coercedEnabled = coerceCfnBoolean(declaredEnabled);
|
|
5055
|
+
if (coercedEnabled !== void 0 && !Object.is(declaredEnabled, coercedEnabled)) patch["Enabled"] = coercedEnabled;
|
|
5056
|
+
}
|
|
5052
5057
|
if (item["IncludedObjectVersions"] === void 0) patch["IncludedObjectVersions"] = INVENTORY_DEFAULT_INCLUDED_OBJECT_VERSIONS;
|
|
5053
5058
|
const declaredSchedule = item["Schedule"];
|
|
5054
5059
|
const declaresScheduleFrequency = item["ScheduleFrequency"] !== void 0;
|
|
@@ -5133,9 +5138,191 @@ function effectiveIntelligentTieringItem(item) {
|
|
|
5133
5138
|
};
|
|
5134
5139
|
}
|
|
5135
5140
|
/**
|
|
5136
|
-
*
|
|
5137
|
-
*
|
|
5138
|
-
*
|
|
5141
|
+
* Normalize a bag's TOLERATED key spellings onto the ONE spelling the readback
|
|
5142
|
+
* emits — the shared core of the two #1748 folds.
|
|
5143
|
+
*
|
|
5144
|
+
* Each entry is `[emitted, tolerated]`: where the applier reads
|
|
5145
|
+
* `(bag['emitted'] ?? bag['tolerated'])`, this writes the SAME value under
|
|
5146
|
+
* `emitted` and REMOVES `tolerated`. The `??` is the licensed ALIAS form (the
|
|
5147
|
+
* one {@link declaredOrDefault} carves out): it supplies no DEFAULT, it picks
|
|
5148
|
+
* between two spellings of one declared value exactly as the applier's own read
|
|
5149
|
+
* does, so a nullish first spelling falls through to the second here for the
|
|
5150
|
+
* same reason it does on the wire.
|
|
5151
|
+
*
|
|
5152
|
+
* Keyed off the DECLARED shape, never off a refusal — the population that
|
|
5153
|
+
* matters carries no malformed value at all, so a condition riding a
|
|
5154
|
+
* substitution arm would miss it (issue #1686's first generalization).
|
|
5155
|
+
*
|
|
5156
|
+
* The tolerated key is REMOVED rather than set to `undefined`: `JSON.stringify`
|
|
5157
|
+
* drops an `undefined` member but the state record is written from this object
|
|
5158
|
+
* and a present-but-`undefined` key survives a `structuredClone`, so a consumer
|
|
5159
|
+
* walking `Object.keys` — the `unionWalkObjects` drift path does — would still
|
|
5160
|
+
* see two different key sets.
|
|
5161
|
+
*
|
|
5162
|
+
* @returns `bag` BY IDENTITY when no tolerated spelling is declared, so an
|
|
5163
|
+
* ordinary CFn-spelled template records and diffs byte-for-byte as before.
|
|
5164
|
+
*/
|
|
5165
|
+
function foldToleratedAliases(bag, aliases) {
|
|
5166
|
+
let out;
|
|
5167
|
+
for (const [emitted, tolerated] of aliases) {
|
|
5168
|
+
if (bag[tolerated] === void 0) continue;
|
|
5169
|
+
out ??= { ...bag };
|
|
5170
|
+
out[emitted] = bag[emitted] ?? bag[tolerated];
|
|
5171
|
+
delete out[tolerated];
|
|
5172
|
+
}
|
|
5173
|
+
return out ?? bag;
|
|
5174
|
+
}
|
|
5175
|
+
/** The lifecycle `Transitions[]` aliases the applier accepts (issue #1748). */
|
|
5176
|
+
const TRANSITION_ALIASES = [["TransitionInDays", "Days"], ["TransitionDate", "Date"]];
|
|
5177
|
+
/** The lifecycle `NoncurrentVersionTransitions[]` alias (issue #1748). */
|
|
5178
|
+
const NONCURRENT_VERSION_TRANSITION_ALIASES = [["TransitionInDays", "NoncurrentDays"]];
|
|
5179
|
+
/** The `NotificationConfiguration` ARN aliases, per family (issue #1748). */
|
|
5180
|
+
const NOTIFICATION_ARN_ALIASES = [
|
|
5181
|
+
["TopicConfigurations", [["Topic", "TopicArn"]]],
|
|
5182
|
+
["QueueConfigurations", [["Queue", "QueueArn"]]],
|
|
5183
|
+
["LambdaConfigurations", [["Function", "LambdaFunctionArn"]]]
|
|
5184
|
+
];
|
|
5185
|
+
/**
|
|
5186
|
+
* The `Event` / `Events` half of the same item (issue #1748).
|
|
5187
|
+
*
|
|
5188
|
+
* The ARN alias is not the only never-emitted spelling on a notification item,
|
|
5189
|
+
* and this one is the WIDER of the two: `TopicArn` is a cdkd-only tolerance
|
|
5190
|
+
* almost no template uses, while `Event` is the member the CFn registry schema
|
|
5191
|
+
* declares (`TopicConfiguration` is `{Event, Filter, Topic}` — there is no
|
|
5192
|
+
* `Events`) and therefore the one EVERY template carries. The applier accepts
|
|
5193
|
+
* both (`t['Event'] !== undefined ? [t['Event']] : t['Events']`).
|
|
5194
|
+
*
|
|
5195
|
+
* Unlike the ARN pair this is not a pure rename — the SDK member is a LIST — so
|
|
5196
|
+
* it folds by ARITY: a single-element list is the CFn `Event`, and a longer one
|
|
5197
|
+
* has no CFn spelling at all and is left as `Events`, which is what the readback
|
|
5198
|
+
* emits for it. That asymmetry is why it is a separate step rather than another
|
|
5199
|
+
* {@link foldToleratedAliases} entry.
|
|
5200
|
+
*
|
|
5201
|
+
* `readNotification` was emitting `Events` unconditionally, so the record and
|
|
5202
|
+
* the readback disagreed on every notification-configured bucket; it now
|
|
5203
|
+
* reverse-maps to the CFn spelling on the same arity rule, exactly as
|
|
5204
|
+
* `readLifecycle` already does for `TransitionInDays`. One-time drift on upgrade
|
|
5205
|
+
* for an already-deployed bucket, the same accepted cost the sibling reverse-map
|
|
5206
|
+
* changes in this file document, and it clears on the next deploy.
|
|
5207
|
+
*/
|
|
5208
|
+
function foldNotificationEvents(item) {
|
|
5209
|
+
const events = item["Events"];
|
|
5210
|
+
if (events === void 0) return item;
|
|
5211
|
+
const out = { ...item };
|
|
5212
|
+
if (item["Event"] === void 0) {
|
|
5213
|
+
if (!Array.isArray(events) || events.length !== 1) return item;
|
|
5214
|
+
out["Event"] = events[0];
|
|
5215
|
+
}
|
|
5216
|
+
delete out["Events"];
|
|
5217
|
+
return out;
|
|
5218
|
+
}
|
|
5219
|
+
/**
|
|
5220
|
+
* The `NotificationConfiguration` cdkd ACTUALLY SENDS, in the spelling
|
|
5221
|
+
* `readNotification` emits (issue #1748) — the never-emitted-KEY class of issue
|
|
5222
|
+
* #1686 reached through the SHAPE rather than through a value.
|
|
5223
|
+
*
|
|
5224
|
+
* `applyNotificationConfiguration` accepts the SDK spelling of each destination
|
|
5225
|
+
* ARN alongside the CFn one (`t['Topic'] ?? t['TopicArn']`, and the two
|
|
5226
|
+
* siblings), while `readNotification` emits only `Topic` / `Queue` /
|
|
5227
|
+
* `Function` — the spellings the live CFn registry schema declares
|
|
5228
|
+
* (`TopicConfiguration` is `{Event, Filter, Topic}`, with no `TopicArn`
|
|
5229
|
+
* member at all, so the SDK spellings are cdkd-only tolerances). A record
|
|
5230
|
+
* written in the tolerated spelling therefore can never match the readback:
|
|
5231
|
+
* `cdkd drift` re-reports it forever and `--revert` re-issues the same Put,
|
|
5232
|
+
* with NO warning anywhere, because nothing is malformed and nothing is
|
|
5233
|
+
* substituted.
|
|
5234
|
+
*
|
|
5235
|
+
* This NORMALIZES rather than retracting the tolerance, per #1686's third
|
|
5236
|
+
* generalization: refusing the SDK spelling would break templates that deploy
|
|
5237
|
+
* today, and buys nothing the normalization does not.
|
|
5238
|
+
*
|
|
5239
|
+
* The Put is a FULL REPLACE with no skip arm, so there is no
|
|
5240
|
+
* previous-value-retained case to distinguish — whenever it succeeds, this is
|
|
5241
|
+
* what AWS holds.
|
|
5242
|
+
*
|
|
5243
|
+
* @returns `config` BY IDENTITY when no tolerated spelling is declared, or when
|
|
5244
|
+
* it is not a shape this can fold at all (left for the applier's own
|
|
5245
|
+
* handling).
|
|
5246
|
+
*/
|
|
5247
|
+
function effectiveNotificationConfiguration(config) {
|
|
5248
|
+
if (!isPlainObject$1(config)) return config;
|
|
5249
|
+
let out = config;
|
|
5250
|
+
for (const [listKey, aliases] of NOTIFICATION_ARN_ALIASES) out = canonicalizeItemList(out, listKey, (item) => foldNotificationEvents(foldToleratedAliases(item, aliases)));
|
|
5251
|
+
return out;
|
|
5252
|
+
}
|
|
5253
|
+
/**
|
|
5254
|
+
* The `LifecycleConfiguration` cdkd ACTUALLY SENDS, in the spelling
|
|
5255
|
+
* `readLifecycle` emits (issue #1748) — the lifecycle half of the same class.
|
|
5256
|
+
*
|
|
5257
|
+
* `applyLifecycleConfiguration` accepts the SDK day/date spellings alongside the
|
|
5258
|
+
* CFn ones on both transition families (`t['TransitionInDays'] ?? t['Days']`,
|
|
5259
|
+
* `t['TransitionDate'] ?? t['Date']`, `nvt['TransitionInDays'] ??
|
|
5260
|
+
* nvt['NoncurrentDays']`) while `readLifecycle` emits only `TransitionInDays` /
|
|
5261
|
+
* `TransitionDate` — again the only spellings the registry schema declares
|
|
5262
|
+
* (`Transition` is `{StorageClass, TransitionDate, TransitionInDays}`,
|
|
5263
|
+
* `NoncurrentVersionTransition` is `{StorageClass, TransitionInDays,
|
|
5264
|
+
* NewerNoncurrentVersions}`).
|
|
5265
|
+
*
|
|
5266
|
+
* The issue named the `Date` alias; the mechanical audit it asks for (match the
|
|
5267
|
+
* `(a['X'] ?? a['Y'])` ALIAS form, not a plain bracket read) found all THREE in
|
|
5268
|
+
* the same two item shapes, so fixing only the reported one would have left its
|
|
5269
|
+
* siblings broken — the "diff the WHOLE blob, not the reported key" rule.
|
|
5270
|
+
*
|
|
5271
|
+
* Two things deliberately NOT folded here, tracked rather than left unstated:
|
|
5272
|
+
* the legacy SINGULAR `Transition` / `NoncurrentVersionTransition` objects,
|
|
5273
|
+
* which `mergeLegacySingular` folds into the plural on the wire so the readback
|
|
5274
|
+
* can never emit them either — a MERGE with a collision arm that WARNS, not an
|
|
5275
|
+
* alias rename, so it needs its own decision (issue #1754); and the RULE-level
|
|
5276
|
+
* divergences the round-trip fence measured beside these
|
|
5277
|
+
* (`ExpirationInDays` / `NoncurrentVersionExpirationInDays` recorded against an
|
|
5278
|
+
* `Expiration` / `NoncurrentVersionExpiration` readback, and the sent-but-
|
|
5279
|
+
* unrecorded `Filter: {Prefix: ''}`), which are reshapes belonging on the
|
|
5280
|
+
* READBACK side and are wider than this class (issue #1755). So a rule using
|
|
5281
|
+
* these aliases converges on the aliases and still differs on those keys until
|
|
5282
|
+
* #1755 lands — which is the honest state, not a claim this makes lifecycle
|
|
5283
|
+
* whole.
|
|
5284
|
+
*
|
|
5285
|
+
* @returns `config` BY IDENTITY when no tolerated spelling is declared.
|
|
5286
|
+
*/
|
|
5287
|
+
function effectiveLifecycleConfiguration(config) {
|
|
5288
|
+
if (!isPlainObject$1(config)) return config;
|
|
5289
|
+
return canonicalizeItemList(config, "Rules", (rule) => {
|
|
5290
|
+
let out = canonicalizeItemList(rule, "Transitions", (t) => foldToleratedAliases(t, TRANSITION_ALIASES));
|
|
5291
|
+
out = canonicalizeItemList(out, "NoncurrentVersionTransitions", (nvt) => foldToleratedAliases(nvt, NONCURRENT_VERSION_TRANSITION_ALIASES));
|
|
5292
|
+
return out;
|
|
5293
|
+
});
|
|
5294
|
+
}
|
|
5295
|
+
/**
|
|
5296
|
+
* Apply a WHOLE-BLOCK fold to one top-level property on BOTH sides of a diff —
|
|
5297
|
+
* the {@link canonicalizeItemList} sibling for the two #1748 folds, whose unit
|
|
5298
|
+
* is the block rather than an item of a list.
|
|
5299
|
+
*
|
|
5300
|
+
* The COMPUTED `[key]:` write is load-bearing and must not be "tidied" into a
|
|
5301
|
+
* named-member spread (`{ ...out, LifecycleConfiguration: folded }`), which is
|
|
5302
|
+
* how this was first written. `gen-nested-key-coverage`'s write-evidence walk
|
|
5303
|
+
* recognizes a bag-derived spread-and-patch literal as a whole-blob HAND-OFF
|
|
5304
|
+
* (its #1475 recognizer) and credits everything beneath the named path as
|
|
5305
|
+
* delivered — so naming the member here made a DIFF-side pure function vouch for
|
|
5306
|
+
* the forward mapper and retired three reviewed `AWS::S3::Bucket` allow-list
|
|
5307
|
+
* entries (`LifecycleConfiguration.TransitionDefaultMinimumObjectSize`,
|
|
5308
|
+
* `…Rules.TagFilters.Key` / `.Value`), i.e. it silently switched the write pass
|
|
5309
|
+
* off for that whole subtree. Measured both ways via the critic's
|
|
5310
|
+
* `--providers-dir=` seam. A computed key names no member, which is exactly why
|
|
5311
|
+
* the pre-existing folds in this file are spelled that way.
|
|
5312
|
+
*/
|
|
5313
|
+
function canonicalizeBlock(properties, key, fold) {
|
|
5314
|
+
const folded = fold(properties[key]);
|
|
5315
|
+
return folded === properties[key] ? properties : {
|
|
5316
|
+
...properties,
|
|
5317
|
+
[key]: folded
|
|
5318
|
+
};
|
|
5319
|
+
}
|
|
5320
|
+
/**
|
|
5321
|
+
* Apply a per-ITEM fold to an array-valued member on BOTH sides of a diff — the
|
|
5322
|
+
* `canonicalizeDesiredProperties` plumbing every fold in this file shares, from
|
|
5323
|
+
* the top-level `Id`-keyed properties down to the nested `Rules[].Transitions[]`
|
|
5324
|
+
* list (the bag is the containing OBJECT, which at the top level is the property
|
|
5325
|
+
* bag and one level down is the rule).
|
|
5139
5326
|
*
|
|
5140
5327
|
* Identity-returns at every level (untouched item -> untouched array ->
|
|
5141
5328
|
* untouched bag), and leaves a non-array property or a non-object element ALONE
|
|
@@ -5201,15 +5388,6 @@ function mergeLegacySingular(plural, singular, onCollision) {
|
|
|
5201
5388
|
}
|
|
5202
5389
|
return [...out, singular];
|
|
5203
5390
|
}
|
|
5204
|
-
/** Coerce a CFn boolean, which may arrive as the string `"true"` / `"false"`. */
|
|
5205
|
-
function coerceCfnBoolean(value) {
|
|
5206
|
-
if (typeof value === "boolean") return value;
|
|
5207
|
-
if (typeof value === "string") {
|
|
5208
|
-
const lowered = value.toLowerCase();
|
|
5209
|
-
if (lowered === "true") return true;
|
|
5210
|
-
if (lowered === "false") return false;
|
|
5211
|
-
}
|
|
5212
|
-
}
|
|
5213
5391
|
/**
|
|
5214
5392
|
* SDK Provider for AWS::S3::Bucket
|
|
5215
5393
|
*
|
|
@@ -6047,6 +6225,13 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
6047
6225
|
skipped.push(index);
|
|
6048
6226
|
continue;
|
|
6049
6227
|
}
|
|
6228
|
+
const enabledRefusal = configBooleanRefusal(config, "Enabled", "AWS::S3::Bucket InventoryConfigurations[]");
|
|
6229
|
+
if (enabledRefusal !== void 0) {
|
|
6230
|
+
if (!onUnusable) throw new Error(`${enabledRefusal}. Omit the field entirely to use the default (${INVENTORY_DEFAULT_ENABLED})`);
|
|
6231
|
+
onUnusable(`${enabledRefusal}. Skipping this inventory configuration: defaulting to ${INVENTORY_DEFAULT_ENABLED} would ENABLE an inventory report the template may have been disabling; the same value is REFUSED on a template-path create`);
|
|
6232
|
+
skipped.push(index);
|
|
6233
|
+
continue;
|
|
6234
|
+
}
|
|
6050
6235
|
const inventoryDestPath = "AWS::S3::Bucket InventoryConfigurations[].Destination";
|
|
6051
6236
|
const rawDest = config["Destination"];
|
|
6052
6237
|
const s3Dest = this.resolveS3BucketDestination(rawDest, inventoryDestPath, onUnusable);
|
|
@@ -6071,7 +6256,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
6071
6256
|
const frequency = useScheduleFrequency ? requireConfigString(config["ScheduleFrequency"], "Weekly", "AWS::S3::Bucket InventoryConfigurations[].ScheduleFrequency") : readConfigString(config["Schedule"], "Frequency", "Weekly", "AWS::S3::Bucket InventoryConfigurations[].Schedule");
|
|
6072
6257
|
const inventoryConfig = {
|
|
6073
6258
|
Id: id,
|
|
6074
|
-
IsEnabled: config["Enabled"] ?? INVENTORY_DEFAULT_ENABLED,
|
|
6259
|
+
IsEnabled: coerceCfnBoolean(config["Enabled"]) ?? INVENTORY_DEFAULT_ENABLED,
|
|
6075
6260
|
IncludedObjectVersions: readConfigString(config, "IncludedObjectVersions", INVENTORY_DEFAULT_INCLUDED_OBJECT_VERSIONS, "AWS::S3::Bucket InventoryConfigurations[]"),
|
|
6076
6261
|
Schedule: { Frequency: frequency },
|
|
6077
6262
|
Destination: { S3BucketDestination: s3Dest ? {
|
|
@@ -6647,6 +6832,17 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
6647
6832
|
overrides.set(key, previousProperties[key]);
|
|
6648
6833
|
};
|
|
6649
6834
|
/**
|
|
6835
|
+
* Record a WHOLE-BLOCK fold: the effective value is what was SENT.
|
|
6836
|
+
*
|
|
6837
|
+
* Identity means the declared bag IS what went on the wire, so no override
|
|
6838
|
+
* is set at all and the engine records the desired properties unchanged —
|
|
6839
|
+
* which is what keeps an ordinary CFn-spelled template byte-for-byte
|
|
6840
|
+
* unaffected by the #1748 folds.
|
|
6841
|
+
*/
|
|
6842
|
+
const recordEffectiveFold = (key, sent) => {
|
|
6843
|
+
if (sent !== properties[key]) overrides.set(key, sent);
|
|
6844
|
+
};
|
|
6845
|
+
/**
|
|
6650
6846
|
* Per-property accumulator for one of the four `Id`-keyed appliers.
|
|
6651
6847
|
*
|
|
6652
6848
|
* Keyed by `Id` rather than by index because on THIS path the diff loop
|
|
@@ -6725,6 +6921,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
6725
6921
|
return;
|
|
6726
6922
|
}
|
|
6727
6923
|
if (!await this.applyLifecycleConfiguration(bucketName, cfg, (m) => this.logger.warn(m))) retainPrevious("LifecycleConfiguration");
|
|
6924
|
+
else recordEffectiveFold("LifecycleConfiguration", effectiveLifecycleConfiguration(cfg));
|
|
6728
6925
|
}, async () => {
|
|
6729
6926
|
await this.s3Client.send(new DeleteBucketLifecycleCommand({ Bucket: bucketName }));
|
|
6730
6927
|
this.logger.debug(`Deleted lifecycle configuration on bucket ${bucketName}`);
|
|
@@ -6753,7 +6950,10 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
6753
6950
|
}, async () => {
|
|
6754
6951
|
await this.applyLoggingConfiguration(bucketName, void 0);
|
|
6755
6952
|
});
|
|
6756
|
-
await this.diffSubConfig(bucketName, previousProperties["NotificationConfiguration"], properties["NotificationConfiguration"], async (cfg) =>
|
|
6953
|
+
await this.diffSubConfig(bucketName, previousProperties["NotificationConfiguration"], properties["NotificationConfiguration"], async (cfg) => {
|
|
6954
|
+
await this.applyNotificationConfiguration(bucketName, cfg);
|
|
6955
|
+
recordEffectiveFold("NotificationConfiguration", effectiveNotificationConfiguration(cfg));
|
|
6956
|
+
}, async () => this.applyNotificationConfiguration(bucketName, void 0));
|
|
6757
6957
|
await this.diffSubConfig(bucketName, previousProperties["ReplicationConfiguration"], properties["ReplicationConfiguration"], async (cfg) => {
|
|
6758
6958
|
if (!await this.applyReplicationConfiguration(bucketName, cfg, (m) => this.logger.warn(m))) retainPrevious("ReplicationConfiguration");
|
|
6759
6959
|
}, async () => {
|
|
@@ -6843,6 +7043,15 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
6843
7043
|
async applyAllSubConfigsForCreate(bucketName, properties, context) {
|
|
6844
7044
|
const overrides = /* @__PURE__ */ new Map();
|
|
6845
7045
|
/**
|
|
7046
|
+
* Record a WHOLE-BLOCK fold: the effective value is what was SENT (issue
|
|
7047
|
+
* #1748). The create-path twin of `applySubConfigDiffs`'s helper of the same
|
|
7048
|
+
* name; identity sets no override, so an ordinary CFn-spelled template is
|
|
7049
|
+
* byte-for-byte unaffected.
|
|
7050
|
+
*/
|
|
7051
|
+
const recordEffectiveFold = (key, sent) => {
|
|
7052
|
+
if (sent !== properties[key]) overrides.set(key, sent);
|
|
7053
|
+
};
|
|
7054
|
+
/**
|
|
6846
7055
|
* Record a per-ITEM applier outcome.
|
|
6847
7056
|
*
|
|
6848
7057
|
* A SKIPPED item is DROPPED — there is no previously-applied item to
|
|
@@ -6858,14 +7067,17 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
6858
7067
|
};
|
|
6859
7068
|
const replayOnUnusable = replayWarn(this.logger, context).onUnusable;
|
|
6860
7069
|
const notifConfig = properties["NotificationConfiguration"];
|
|
6861
|
-
if (notifConfig)
|
|
7070
|
+
if (notifConfig) {
|
|
7071
|
+
await this.applyNotificationConfiguration(bucketName, notifConfig);
|
|
7072
|
+
recordEffectiveFold("NotificationConfiguration", effectiveNotificationConfiguration(notifConfig));
|
|
7073
|
+
}
|
|
6862
7074
|
const corsConfig = properties["CorsConfiguration"];
|
|
6863
7075
|
if (corsConfig?.CorsRules && Array.isArray(corsConfig.CorsRules) && corsConfig.CorsRules.length > 0) await this.applyCorsConfiguration(bucketName, corsConfig);
|
|
6864
7076
|
else if (corsConfig != null) this.announceCreateEmptyCollectionSkip("CorsConfiguration", "CorsConfiguration.CorsRules");
|
|
6865
7077
|
const lifecycleConfig = properties["LifecycleConfiguration"];
|
|
6866
|
-
if (lifecycleConfig?.Rules && Array.isArray(lifecycleConfig.Rules) && lifecycleConfig.Rules.length > 0)
|
|
6867
|
-
|
|
6868
|
-
|
|
7078
|
+
if (lifecycleConfig?.Rules && Array.isArray(lifecycleConfig.Rules) && lifecycleConfig.Rules.length > 0) if (!await this.applyLifecycleConfiguration(bucketName, lifecycleConfig, replayOnUnusable)) overrides.set("LifecycleConfiguration", void 0);
|
|
7079
|
+
else recordEffectiveFold("LifecycleConfiguration", effectiveLifecycleConfiguration(lifecycleConfig));
|
|
7080
|
+
else if (lifecycleConfig != null) this.announceCreateEmptyCollectionSkip("LifecycleConfiguration", "LifecycleConfiguration.Rules");
|
|
6869
7081
|
const loggingConfig = properties["LoggingConfiguration"];
|
|
6870
7082
|
const loggingRefusal = replayOnUnusable ? configStringRefusal(loggingConfig, "DestinationBucketName", "", "AWS::S3::Bucket LoggingConfiguration") : void 0;
|
|
6871
7083
|
if (loggingRefusal !== void 0) {
|
|
@@ -7051,6 +7263,8 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
7051
7263
|
let out = canonicalizeItemList(properties, "InventoryConfigurations", (item) => effectiveInventoryItem(item));
|
|
7052
7264
|
out = canonicalizeItemList(out, "AnalyticsConfigurations", (item) => effectiveAnalyticsItem(item));
|
|
7053
7265
|
out = canonicalizeItemList(out, "IntelligentTieringConfigurations", effectiveIntelligentTieringItem);
|
|
7266
|
+
out = canonicalizeBlock(out, "NotificationConfiguration", effectiveNotificationConfiguration);
|
|
7267
|
+
out = canonicalizeBlock(out, "LifecycleConfiguration", effectiveLifecycleConfiguration);
|
|
7054
7268
|
return out;
|
|
7055
7269
|
}
|
|
7056
7270
|
/**
|
|
@@ -7333,6 +7547,27 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
7333
7547
|
}
|
|
7334
7548
|
return out;
|
|
7335
7549
|
}
|
|
7550
|
+
/**
|
|
7551
|
+
* Emit a notification item's event list in the CFn spelling (issue #1748).
|
|
7552
|
+
*
|
|
7553
|
+
* The SDK member is the LIST `Events`; CFn declares only the scalar `Event`
|
|
7554
|
+
* (`TopicConfiguration` is `{Event, Filter, Topic}`), which is what every
|
|
7555
|
+
* template — and therefore every state record written from one — carries. So
|
|
7556
|
+
* emitting `Events` unconditionally made the record and the readback disagree
|
|
7557
|
+
* on EVERY notification-configured bucket: `cdkd drift` re-reported it forever
|
|
7558
|
+
* and `--revert` re-issued the same Put, with nothing malformed to warn about.
|
|
7559
|
+
*
|
|
7560
|
+
* Reverse-mapping to the CFn spelling is the same answer the `Transitions`
|
|
7561
|
+
* sibling in `readLifecycle` already takes for `TransitionInDays`. The arity
|
|
7562
|
+
* rule is what keeps it lossless: a longer list has no CFn spelling, so it
|
|
7563
|
+
* stays `Events` — which is also what {@link foldNotificationEvents} leaves on
|
|
7564
|
+
* the desired side, so the two still meet.
|
|
7565
|
+
*/
|
|
7566
|
+
emitNotificationEvents(target, events) {
|
|
7567
|
+
if (events === void 0) return;
|
|
7568
|
+
if (events.length === 1) target["Event"] = events[0];
|
|
7569
|
+
else target["Events"] = events;
|
|
7570
|
+
}
|
|
7336
7571
|
async readNotification(bucket) {
|
|
7337
7572
|
const resp = await this.s3Client.send(new GetBucketNotificationConfigurationCommand({ Bucket: bucket }));
|
|
7338
7573
|
const out = {};
|
|
@@ -7340,7 +7575,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
7340
7575
|
const e = {};
|
|
7341
7576
|
if (t.Id !== void 0) e["Id"] = t.Id;
|
|
7342
7577
|
if (t.TopicArn !== void 0) e["Topic"] = t.TopicArn;
|
|
7343
|
-
|
|
7578
|
+
this.emitNotificationEvents(e, t.Events);
|
|
7344
7579
|
if (t.Filter) e["Filter"] = this.sdkNotifFilterToCfn(t.Filter);
|
|
7345
7580
|
return e;
|
|
7346
7581
|
});
|
|
@@ -7348,7 +7583,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
7348
7583
|
const e = {};
|
|
7349
7584
|
if (q.Id !== void 0) e["Id"] = q.Id;
|
|
7350
7585
|
if (q.QueueArn !== void 0) e["Queue"] = q.QueueArn;
|
|
7351
|
-
|
|
7586
|
+
this.emitNotificationEvents(e, q.Events);
|
|
7352
7587
|
if (q.Filter) e["Filter"] = this.sdkNotifFilterToCfn(q.Filter);
|
|
7353
7588
|
return e;
|
|
7354
7589
|
});
|
|
@@ -7356,7 +7591,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
7356
7591
|
const e = {};
|
|
7357
7592
|
if (l.Id !== void 0) e["Id"] = l.Id;
|
|
7358
7593
|
if (l.LambdaFunctionArn !== void 0) e["Function"] = l.LambdaFunctionArn;
|
|
7359
|
-
|
|
7594
|
+
this.emitNotificationEvents(e, l.Events);
|
|
7360
7595
|
if (l.Filter) e["Filter"] = this.sdkNotifFilterToCfn(l.Filter);
|
|
7361
7596
|
return e;
|
|
7362
7597
|
});
|
|
@@ -14337,6 +14572,18 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
14337
14572
|
delete copy["GlobalSecondaryIndexes"];
|
|
14338
14573
|
return copy;
|
|
14339
14574
|
});
|
|
14575
|
+
const keptKeyAttributes = collectDesiredKeyAttributeNames(properties, { indexListKeys: ["LocalSecondaryIndexes"] });
|
|
14576
|
+
if (keptKeyAttributes.size > 0 && Array.isArray(attributeDefinitions)) {
|
|
14577
|
+
const prunedAttributeDefinitions = attributeDefinitions.filter((definition) => {
|
|
14578
|
+
const name = asRecord$1(definition)?.["AttributeName"];
|
|
14579
|
+
if (typeof name !== "string") return true;
|
|
14580
|
+
return keptKeyAttributes.has(name);
|
|
14581
|
+
});
|
|
14582
|
+
if (prunedAttributeDefinitions.length !== attributeDefinitions.length) {
|
|
14583
|
+
createParams.AttributeDefinitions = prunedAttributeDefinitions;
|
|
14584
|
+
effectiveProperties["AttributeDefinitions"] = [...prunedAttributeDefinitions];
|
|
14585
|
+
}
|
|
14586
|
+
}
|
|
14340
14587
|
}
|
|
14341
14588
|
if (sdkIndexes.length > 0) createParams.GlobalSecondaryIndexes = sdkIndexes;
|
|
14342
14589
|
if (properties["LocalSecondaryIndexes"]) createParams.LocalSecondaryIndexes = properties["LocalSecondaryIndexes"];
|
|
@@ -15710,6 +15957,31 @@ var DynamoDBGlobalTableProvider = class {
|
|
|
15710
15957
|
return [];
|
|
15711
15958
|
}
|
|
15712
15959
|
/**
|
|
15960
|
+
* `AttributeDefinitions` is an unordered SET, and the comparator compares
|
|
15961
|
+
* arrays positionally (issue #1742).
|
|
15962
|
+
*
|
|
15963
|
+
* `DescribeTable` returns the definitions in an order matching neither the
|
|
15964
|
+
* request nor alphabetical — measured us-east-1 2026-08-13 on the
|
|
15965
|
+
* `rollback-replay-effective-props` fixture, where a table declaring
|
|
15966
|
+
* `[pk, gsipk]` read back as `[gsipk, pk]` — so an UNTOUCHED table drifted
|
|
15967
|
+
* forever. Sorting cannot hide a real change here because the list is a
|
|
15968
|
+
* genuine set: members are keyed by `AttributeName`, so adding, removing or
|
|
15969
|
+
* retyping one still changes the canonicalized form.
|
|
15970
|
+
*
|
|
15971
|
+
* Reachable whenever the drift baseline is `properties` rather than
|
|
15972
|
+
* `observedProperties` — i.e. after any reverse-replacement rollback, which
|
|
15973
|
+
* `rollback-executor.ts` strips `observedProperties` on. That is also why it
|
|
15974
|
+
* went unseen: on the ordinary path both sides come from the same readback.
|
|
15975
|
+
*
|
|
15976
|
+
* `KeySchema` is deliberately NOT declared, at the table level or per index:
|
|
15977
|
+
* it is order-SIGNIFICANT (HASH before RANGE), so sorting it would silently
|
|
15978
|
+
* hide a real key change — the failure direction this file's sibling rules
|
|
15979
|
+
* call the worse one.
|
|
15980
|
+
*/
|
|
15981
|
+
getDriftUnorderedPaths(_resourceType) {
|
|
15982
|
+
return ["AttributeDefinitions"];
|
|
15983
|
+
}
|
|
15984
|
+
/**
|
|
15713
15985
|
* Adopt an existing DynamoDB GlobalTable into cdkd state.
|
|
15714
15986
|
*
|
|
15715
15987
|
* Lookup order:
|
|
@@ -16058,12 +16330,21 @@ function collectAutoScalingTargets(properties, localRegion) {
|
|
|
16058
16330
|
* redefine-in-place (replacement required); one outside it is the normal
|
|
16059
16331
|
* bookkeeping of a GSI deletion and must NOT force a replacement.
|
|
16060
16332
|
*
|
|
16061
|
-
* Malformed / intrinsic-valued entries contribute nothing
|
|
16062
|
-
*
|
|
16063
|
-
* mode is a forced replacement of a live table, and AWS
|
|
16064
|
-
*
|
|
16065
|
-
|
|
16066
|
-
|
|
16333
|
+
* Malformed / intrinsic-valued entries contribute nothing. For the `update()`
|
|
16334
|
+
* guard that errs on the PERMISSIVE side — correct there, because that guard's
|
|
16335
|
+
* failure mode is a forced replacement of a live table, and AWS still rejects a
|
|
16336
|
+
* genuinely-bad `UpdateTable` loudly. For the create-path prune below it errs
|
|
16337
|
+
* the other way (an unreadable LSI key schema prunes MORE), which is only
|
|
16338
|
+
* reachable on a bag AWS would reject anyway.
|
|
16339
|
+
*
|
|
16340
|
+
* `options.indexListKeys` narrows which index lists contribute, for the ONE
|
|
16341
|
+
* caller whose question is not "what does the template reference" but "what
|
|
16342
|
+
* will this call actually key on" — `create()`'s replay-CREATE GSI omit arm
|
|
16343
|
+
* (issue #1741), which sends NO indexes and therefore must not count the
|
|
16344
|
+
* omitted block's key attributes as still-referenced. It defaults to BOTH
|
|
16345
|
+
* lists, so the `update()` guard above reads exactly as it did before.
|
|
16346
|
+
*/
|
|
16347
|
+
function collectDesiredKeyAttributeNames(properties, options) {
|
|
16067
16348
|
const names = /* @__PURE__ */ new Set();
|
|
16068
16349
|
const addKeySchema = (value) => {
|
|
16069
16350
|
if (!Array.isArray(value)) return;
|
|
@@ -16073,7 +16354,8 @@ function collectDesiredKeyAttributeNames(properties) {
|
|
|
16073
16354
|
}
|
|
16074
16355
|
};
|
|
16075
16356
|
addKeySchema(properties["KeySchema"]);
|
|
16076
|
-
|
|
16357
|
+
const indexListKeys = options?.indexListKeys ?? ["GlobalSecondaryIndexes", "LocalSecondaryIndexes"];
|
|
16358
|
+
for (const indexListKey of indexListKeys) {
|
|
16077
16359
|
const indexes = properties[indexListKey];
|
|
16078
16360
|
if (!Array.isArray(indexes)) continue;
|
|
16079
16361
|
for (const index of indexes) addKeySchema(asRecord$1(index)?.["KeySchema"]);
|
|
@@ -74064,7 +74346,7 @@ function createMigrateCommand() {
|
|
|
74064
74346
|
*/
|
|
74065
74347
|
function buildProgram() {
|
|
74066
74348
|
const program = new Command();
|
|
74067
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.281.
|
|
74349
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.281.20");
|
|
74068
74350
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
74069
74351
|
const { profile } = actionCommand.optsWithGlobals();
|
|
74070
74352
|
if (profile !== void 0) process.env["AWS_PROFILE"] = profile;
|