@go-to-k/cdkd 0.284.13 → 0.284.14
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/dist/{asg-provider-H-Dl8qng.js → asg-provider-DZAeGqBC.js} +2 -2
- package/dist/{asg-provider-H-Dl8qng.js.map → asg-provider-DZAeGqBC.js.map} +1 -1
- package/dist/cli.js +272 -8
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-4Eh5Qqlm.js → deploy-engine-C2OBi4mp.js} +4 -4
- package/dist/{deploy-engine-4Eh5Qqlm.js.map → deploy-engine-C2OBi4mp.js.map} +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as isTerminationProtectionPropagationError, $n as ResourceUpdateNotSupportedError, $t as validateAssetBucketName, A as renderStatefulReason, An as derivePartitionAndUrlSuffix, At as INTRINSIC_KEYS, B as exportAliasCollisionScrubWarning, Bn as CdkdError, Bt as stringifyValue, C as isFinalSnapshotError, Cn as CFN_TEMPLATE_URL_LIMIT, Ct as s3BucketArn, D as extractDeploymentEventError, Dn as expectedOwnerParam, Dt as s3BucketWebsiteUrl, E as makeCanonicalizePropertiesFn, En as uploadCfnTemplate, Et as s3BucketRegionalDomainName, F as green, Fn as AwsClients, Ft as LockManager, G as collectInlinePolicyNamesManagedBySiblings, Gn as LocalMigrateError, Gt as rewriteTemplateAssetReferences, H as secretBearingStateKeyWarning, Ht as buildAssetRedirectMap, I as red, In as getAwsClients, It as S3StateBackend, J as findActionableSilentDrops, Jn as MissingCdkCliError, Jt as AssetModeResolver, K as clearOnUpdateRemoval, Kn as LocalStartServiceError, Kt as escapeRegExp, L as yellow, Ln as resetAwsClients, Lt as rebuildClientForBucketRegion, M as bold, Mn as processStackMessages, Mt as withRetry, N as cyan, Nt as DagBuilder, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as PARTITION_TABLE, Ot as applyRoleArnIfSet, P as gray, Pn as resolveBucketRegion, Pt as TemplateParser, Q as disableInstanceApiTermination, Qn as ResourceTimeoutError, Qt as parseBootstrapMarker, R as collectDeclaredOutputNames, Rn as setAwsClients, Rt as shouldRetainResource, S as createPreDeleteFinalSnapshot, Sn as CFN_TEMPLATE_BODY_LIMIT, St as scrubResourceRecord, T as unsupportedFinalSnapshotError, Tn as findLargeInlineResources, Tt as s3BucketDualStackDomainName, U as stateKeySecretExposure, Un as DeployCancelledError, Ut as createAssetRedirectResolver, V as isExportAliasCollision, Vt as WorkGraph, W as IAMRoleProvider, Wn as LocalInvokeBuildError$1, Wt as loadPublishableAssetManifest, X as CloudControlProvider, Xn as PartialFailureError, Xt as ensureAssetStorage, Y as findSilentDropProperties, Yn as NestedStackChildDirectDestroyError, Yt as BOOTSTRAP_MARKER_PREFIX, Z as slowCcOperationTimeoutMs, Zn as ProvisioningError, Zt as getBootstrapMarkerKey, _ as computeImplicitDeleteEdges, _n as resolveStateBucketWithDefault, _t as STATE_SOURCED_READBACK_RULES, a as DeploymentEventsStore, an as runDockerForeground, at as normalizeAwsTagsToCfn, b as buildFinalSnapshotIdentifier, bn as stateBucketExistenceConfirmed, bt as maskSecretsInText, c as replayFailedOperations, cn as getDockerImageBySourceHash, cr as isMarkedNonRetryable, ct as coerceCfnBoolean, d as updatePartialReason, dn as getDefaultStateBucketName, dr as markNonRetryable, dt as readConfigString, en as validateContainerRepoName, er as StackHasActiveImportsError, et as IntrinsicFunctionResolver, f as UNSPECIFIED_SKIP_REASON, fn as getLegacyStateBucketName, ft as replayWarn, g as IMPLICIT_DELETE_DEPENDENCIES, gn as resolveSkipPrefix, gt as STATE_SOURCED_CROSS_GENERATION_RULES, h as maskingRetryLogger, hn as resolveCaptureObservedState, ht as requireConfigString, i as DeploymentEventsReader, in as getDockerCmd, it as WAFv2WebACLProvider, j as formatResourceLine, jn as AssemblyReader, jt as describeTypeWithThrottleRetry, k as isStatefulRecreateTargetSync, kn as canonicalizeRegion, kt as DiffCalculator, l as replayRollback, ln as Synthesizer, lr as isRetryableTransientError, lt as configBooleanRefusal, m as withResourceDeadline, mn as resolveAutoAssetStorage, mt as requireConfigObject, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as buildDockerImage, nt as getAccountInfo, o as planFailedOps, on as runDockerStreaming, or as normalizeAwsError, ot as resolveExplicitPhysicalId, p as deleteSkipReason, pn as resolveApp, pt as requireConfigArray, q as ProviderRegistry, qt as stripControlChars, r as DeployEngine, rn as formatDockerLoginError, rt as refStateLookupFromResource, s as planRollback, sn as AssetManifestLoader, sr as withErrorHandling, st as assertRegionMatch, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as buildDenyExternalAccessPolicy, tr as StackTerminationProtectionError, tt as cfnRefValueFromPhysicalId, u as updatePartialMessage, un as synthesisStatusMessage, ur as isThrottlingError, ut as configStringRefusal, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as resolveStateBucketWithDefaultAndSource, vt as TEMPLATE_SOURCED_RULES, w as refusesFinalSnapshot, wn as MIGRATE_TMP_PREFIX, wt as s3BucketDomainName, x as ccRoutedFinalSnapshotError, xn as warnDeprecatedNoPrefixCliFlag, xt as redactSecretsForState, y as PRE_DELETE_SNAPSHOT_TYPES, yn as resolveUseCdkBootstrapAssets, yt as createSecretMasker, z as collectPublishedOutputNames, zt as AssetPublisher } from "./deploy-engine-
|
|
2
|
+
import { $ as isTerminationProtectionPropagationError, $n as ResourceUpdateNotSupportedError, $t as validateAssetBucketName, A as renderStatefulReason, An as derivePartitionAndUrlSuffix, At as INTRINSIC_KEYS, B as exportAliasCollisionScrubWarning, Bn as CdkdError, Bt as stringifyValue, C as isFinalSnapshotError, Cn as CFN_TEMPLATE_URL_LIMIT, Ct as s3BucketArn, D as extractDeploymentEventError, Dn as expectedOwnerParam, Dt as s3BucketWebsiteUrl, E as makeCanonicalizePropertiesFn, En as uploadCfnTemplate, Et as s3BucketRegionalDomainName, F as green, Fn as AwsClients, Ft as LockManager, G as collectInlinePolicyNamesManagedBySiblings, Gn as LocalMigrateError, Gt as rewriteTemplateAssetReferences, H as secretBearingStateKeyWarning, Ht as buildAssetRedirectMap, I as red, In as getAwsClients, It as S3StateBackend, J as findActionableSilentDrops, Jn as MissingCdkCliError, Jt as AssetModeResolver, K as clearOnUpdateRemoval, Kn as LocalStartServiceError, Kt as escapeRegExp, L as yellow, Ln as resetAwsClients, Lt as rebuildClientForBucketRegion, M as bold, Mn as processStackMessages, Mt as withRetry, N as cyan, Nt as DagBuilder, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as PARTITION_TABLE, Ot as applyRoleArnIfSet, P as gray, Pn as resolveBucketRegion, Pt as TemplateParser, Q as disableInstanceApiTermination, Qn as ResourceTimeoutError, Qt as parseBootstrapMarker, R as collectDeclaredOutputNames, Rn as setAwsClients, Rt as shouldRetainResource, S as createPreDeleteFinalSnapshot, Sn as CFN_TEMPLATE_BODY_LIMIT, St as scrubResourceRecord, T as unsupportedFinalSnapshotError, Tn as findLargeInlineResources, Tt as s3BucketDualStackDomainName, U as stateKeySecretExposure, Un as DeployCancelledError, Ut as createAssetRedirectResolver, V as isExportAliasCollision, Vt as WorkGraph, W as IAMRoleProvider, Wn as LocalInvokeBuildError$1, Wt as loadPublishableAssetManifest, X as CloudControlProvider, Xn as PartialFailureError, Xt as ensureAssetStorage, Y as findSilentDropProperties, Yn as NestedStackChildDirectDestroyError, Yt as BOOTSTRAP_MARKER_PREFIX, Z as slowCcOperationTimeoutMs, Zn as ProvisioningError, Zt as getBootstrapMarkerKey, _ as computeImplicitDeleteEdges, _n as resolveStateBucketWithDefault, _t as STATE_SOURCED_READBACK_RULES, a as DeploymentEventsStore, an as runDockerForeground, at as normalizeAwsTagsToCfn, b as buildFinalSnapshotIdentifier, bn as stateBucketExistenceConfirmed, bt as maskSecretsInText, c as replayFailedOperations, cn as getDockerImageBySourceHash, cr as isMarkedNonRetryable, ct as coerceCfnBoolean, d as updatePartialReason, dn as getDefaultStateBucketName, dr as markNonRetryable, dt as readConfigString, en as validateContainerRepoName, er as StackHasActiveImportsError, et as IntrinsicFunctionResolver, f as UNSPECIFIED_SKIP_REASON, fn as getLegacyStateBucketName, ft as replayWarn, g as IMPLICIT_DELETE_DEPENDENCIES, gn as resolveSkipPrefix, gt as STATE_SOURCED_CROSS_GENERATION_RULES, h as maskingRetryLogger, hn as resolveCaptureObservedState, ht as requireConfigString, i as DeploymentEventsReader, in as getDockerCmd, it as WAFv2WebACLProvider, j as formatResourceLine, jn as AssemblyReader, jt as describeTypeWithThrottleRetry, k as isStatefulRecreateTargetSync, kn as canonicalizeRegion, kt as DiffCalculator, l as replayRollback, ln as Synthesizer, lr as isRetryableTransientError, lt as configBooleanRefusal, m as withResourceDeadline, mn as resolveAutoAssetStorage, mt as requireConfigObject, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as buildDockerImage, nt as getAccountInfo, o as planFailedOps, on as runDockerStreaming, or as normalizeAwsError, ot as resolveExplicitPhysicalId, p as deleteSkipReason, pn as resolveApp, pt as requireConfigArray, q as ProviderRegistry, qt as stripControlChars, r as DeployEngine, rn as formatDockerLoginError, rt as refStateLookupFromResource, s as planRollback, sn as AssetManifestLoader, sr as withErrorHandling, st as assertRegionMatch, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as buildDenyExternalAccessPolicy, tr as StackTerminationProtectionError, tt as cfnRefValueFromPhysicalId, u as updatePartialMessage, un as synthesisStatusMessage, ur as isThrottlingError, ut as configStringRefusal, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as resolveStateBucketWithDefaultAndSource, vt as TEMPLATE_SOURCED_RULES, w as refusesFinalSnapshot, wn as MIGRATE_TMP_PREFIX, wt as s3BucketDomainName, x as ccRoutedFinalSnapshotError, xn as warnDeprecatedNoPrefixCliFlag, xt as redactSecretsForState, y as PRE_DELETE_SNAPSHOT_TYPES, yn as resolveUseCdkBootstrapAssets, yt as createSecretMasker, z as collectPublishedOutputNames, zt as AssetPublisher } from "./deploy-engine-C2OBi4mp.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-DZAeGqBC.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";
|
|
@@ -40034,8 +40034,7 @@ function buildMfaConfigRequest(physicalId, properties, logger, declaredMfaConfig
|
|
|
40034
40034
|
const enablesMfaFactor = declaresFactor || request.EmailMfaConfiguration !== void 0;
|
|
40035
40035
|
request.MfaConfiguration = declaredMfaConfiguration || (enablesMfaFactor ? "OPTIONAL" : "OFF");
|
|
40036
40036
|
if (enabledMfasBlank) warn(`UserPool ${physicalId}: EnabledMfas is an empty string, which declares no MFA factor and is treated as absent — a mangled Fn::Join or an empty String parameter collapses to this shape. Nothing is enabled from it and MfaConfiguration is ${request.MfaConfiguration}; declare the factor names as a list (e.g. ["${MFA_FACTOR_SOFTWARE_TOKEN}"]) if a factor was intended.`);
|
|
40037
|
-
const anyFactorBlock = request
|
|
40038
|
-
if (request.MfaConfiguration === "OFF" && anyFactorBlock) warn(`UserPool ${physicalId}: MfaConfiguration is pinned to OFF while an MFA factor block is configured. AWS REJECTS that combination ("Invalid MFA configuration given, can't turn off MFA and configure an MFA together"), so this deploy FAILS rather than producing a pool with MFA disabled. Remove MfaConfiguration (or set it to ON / OPTIONAL) to enable the declared factor.`);
|
|
40037
|
+
const anyFactorBlock = hasAnyMfaFactorBlock(request);
|
|
40039
40038
|
const maskDeep = (v, depth = 0) => {
|
|
40040
40039
|
if (typeof v === "string") return maskSecrets(v);
|
|
40041
40040
|
if (depth >= MASK_WALK_MAX_DEPTH) return v;
|
|
@@ -40046,7 +40045,7 @@ function buildMfaConfigRequest(physicalId, properties, logger, declaredMfaConfig
|
|
|
40046
40045
|
const dropped = unrecognizedFactors.map((f) => JSON.stringify(maskDeep(f)) ?? String(f));
|
|
40047
40046
|
if (enabledMfasMalformed) dropped.push(`${JSON.stringify(maskDeep(properties["EnabledMfas"]))} (not a list)`);
|
|
40048
40047
|
if (dropped.length > 0) {
|
|
40049
|
-
const consequence = request.MfaConfiguration === "OFF"
|
|
40048
|
+
const consequence = request.MfaConfiguration === "OFF" ? `MfaConfiguration is OFF, so this pool deploys with MFA DISABLED` : anyFactorBlock ? `MfaConfiguration is ${request.MfaConfiguration} and another factor block IS sent, so these entries are silently ignored rather than failing the call on their own` : `MfaConfiguration is ${request.MfaConfiguration} with no factor enabled, so AWS rejects this call rather than deploying the pool with MFA disabled`;
|
|
40050
40049
|
warn(`UserPool ${physicalId}: EnabledMfas entries ${dropped.join(", ")} do not map to an MFA factor block (known: ${MFA_FACTOR_SMS}, ${MFA_FACTOR_SOFTWARE_TOKEN}, ${MFA_FACTOR_EMAIL_OTP}); no factor is enabled from them. ${consequence}.`);
|
|
40051
40050
|
}
|
|
40052
40051
|
return request;
|
|
@@ -40075,6 +40074,248 @@ function resolveSentMfaConfiguration(properties, declaredMfaConfiguration) {
|
|
|
40075
40074
|
return declaredMfaConfiguration || void 0;
|
|
40076
40075
|
}
|
|
40077
40076
|
/**
|
|
40077
|
+
* "This `SetUserPoolMfaConfig` request carries an MFA FACTOR sub-block."
|
|
40078
|
+
*
|
|
40079
|
+
* ONE definition, shared by `buildMfaConfigRequest`'s dropped-entry warning and
|
|
40080
|
+
* by the pre-flight refusal below, so the message and the refusal cannot
|
|
40081
|
+
* disagree about the same request. It is precisely
|
|
40082
|
+
* `{Sms, SoftwareToken, Email}MfaConfiguration` -- `WebAuthnConfiguration` is
|
|
40083
|
+
* deliberately NOT a member, because WebAuthn is not an MFA factor and rides
|
|
40084
|
+
* alongside `MfaConfiguration: OFF` on every passkey-only pool (issue #1920).
|
|
40085
|
+
*/
|
|
40086
|
+
function hasAnyMfaFactorBlock(request) {
|
|
40087
|
+
return request.SmsMfaConfiguration !== void 0 || request.SoftwareTokenMfaConfiguration !== void 0 || request.EmailMfaConfiguration !== void 0;
|
|
40088
|
+
}
|
|
40089
|
+
/**
|
|
40090
|
+
* The `Policies.SignInPolicy.AllowedFirstAuthFactors` members AWS refuses to
|
|
40091
|
+
* combine with MFA (issue #1975).
|
|
40092
|
+
*
|
|
40093
|
+
* A DENY-list, deliberately, even though the AWS message states an ALLOW-list
|
|
40094
|
+
* ("Only PASSWORD and WEB_AUTHN (if configured) can be enabled as an auth
|
|
40095
|
+
* factor if MFA is enabled"). Written from the allow-list, a member AWS adds
|
|
40096
|
+
* LATER would be refused by cdkd on the day it starts working -- the same
|
|
40097
|
+
* reason the unrecognized-`EnabledMfas` case in `buildMfaConfigRequest` warns
|
|
40098
|
+
* rather than throws, since that set is a hardcoded mirror of an AWS enum. The
|
|
40099
|
+
* cost of the deny-list is the reverse and is the cheaper one: a future
|
|
40100
|
+
* incompatible factor is simply not pre-flighted, which is the pre-#1975
|
|
40101
|
+
* behavior (a loud AWS rejection), not a regression.
|
|
40102
|
+
*
|
|
40103
|
+
* The two members ARE the whole of today's `AuthFactorType` enum outside the
|
|
40104
|
+
* allowed pair (`EMAIL_OTP`, `PASSWORD`, `SMS_OTP`, `WEB_AUTHN` --
|
|
40105
|
+
* `@aws-sdk/client-cognito-identity-provider`), so the deny-list and the
|
|
40106
|
+
* allow-list agree on every value that exists right now.
|
|
40107
|
+
*
|
|
40108
|
+
* BOTH members are MEASURED (us-east-1, 2026-08-19, issue #1975) -- neither is
|
|
40109
|
+
* extrapolated from the other, which is the failure mode this file's own
|
|
40110
|
+
* unrecognized-factor comment warns about:
|
|
40111
|
+
*
|
|
40112
|
+
* [PASSWORD, EMAIL_OTP] + SetUserPoolMfaConfig(ON) -> REJECTED
|
|
40113
|
+
* [PASSWORD, SMS_OTP] + SetUserPoolMfaConfig(ON) -> REJECTED, same message
|
|
40114
|
+
*
|
|
40115
|
+
* The `SMS_OTP` probe needed a precondition worth recording, because without it
|
|
40116
|
+
* the interesting call is never reached: on a pool with NO `SmsConfiguration`,
|
|
40117
|
+
* `CreateUserPool` refuses the factor outright ("SMS_OTP can not be configured
|
|
40118
|
+
* as AuthFactor as user pool is missing valid SMS configuration"), so the probe
|
|
40119
|
+
* had to stand up an SNS-caller IAM role + ExternalId first. That earlier,
|
|
40120
|
+
* different refusal is AWS's own and is NOT something this pre-flight
|
|
40121
|
+
* duplicates.
|
|
40122
|
+
*
|
|
40123
|
+
* Typed `satisfies AuthFactorType[]` rather than left as `string[]`: the values
|
|
40124
|
+
* mirror an SDK enum, so a rename upstream should be a COMPILE error here
|
|
40125
|
+
* rather than a silently-never-matching deny-list.
|
|
40126
|
+
*/
|
|
40127
|
+
const MFA_INCOMPATIBLE_FIRST_AUTH_FACTORS = ["EMAIL_OTP", "SMS_OTP"];
|
|
40128
|
+
/**
|
|
40129
|
+
* `Policies.SignInPolicy.AllowedFirstAuthFactors` as a list of STRINGS, or an
|
|
40130
|
+
* empty list when the template declares nothing usable there.
|
|
40131
|
+
*
|
|
40132
|
+
* Every mis-shape reads as ABSENT rather than as a violation: this feeds a
|
|
40133
|
+
* REFUSAL, so guessing at a container cdkd could not read would block a deploy
|
|
40134
|
+
* over a value it never understood. A genuinely broken `Policies` blob is AWS's
|
|
40135
|
+
* to reject, with its own message.
|
|
40136
|
+
*
|
|
40137
|
+
* The two containers are traversed with `?.` rather than with the
|
|
40138
|
+
* `typeof x === 'object' && !Array.isArray(x)` guard `config-shape.ts` uses,
|
|
40139
|
+
* and that is deliberate rather than sloppy: those guards are load-bearing
|
|
40140
|
+
* THERE because the helper REFUSES a non-object, while here the only outcome is
|
|
40141
|
+
* "no factors", which is exactly what indexing a string / number / array
|
|
40142
|
+
* already yields. The version carrying them was written first and MEASURED
|
|
40143
|
+
* inert -- deleting either clause failed no test and could not be made to,
|
|
40144
|
+
* since no template value indexes to anything at those keys. `?.` keeps the one
|
|
40145
|
+
* behaviour that is real (a declared `null` throws on a bare index) and leaves
|
|
40146
|
+
* nothing unfalsifiable behind.
|
|
40147
|
+
*
|
|
40148
|
+
* The two filters below are NOT the same kind of thing, and saying so matters
|
|
40149
|
+
* because an earlier revision of this comment claimed both were load-bearing and
|
|
40150
|
+
* "each fenced by a test" -- which was false for one of them, and a false fence
|
|
40151
|
+
* claim is what stops the next reader re-checking.
|
|
40152
|
+
*
|
|
40153
|
+
* - `Array.isArray` is a RUNTIME guard and IS fenced: without it a scalar
|
|
40154
|
+
* `AllowedFirstAuthFactors: 'EMAIL_OTP'` is read as a declaration and
|
|
40155
|
+
* refused, and the test for that shape reds when it is dropped.
|
|
40156
|
+
* - The string filter is a TYPE NARROWING and is INERT at runtime. `includes`
|
|
40157
|
+
* compares by SameValueZero, so a non-string member can never equal a
|
|
40158
|
+
* deny-list entry however it is spelled; deleting the filter fails NO test,
|
|
40159
|
+
* and no test could be written that it would fail. It earns its place by
|
|
40160
|
+
* giving the caller a `string[]`, and by keeping this function honest if a
|
|
40161
|
+
* future caller ever COERCES a member instead of comparing it. The
|
|
40162
|
+
* nested-list case in the suite fences that hypothetical `String(member)`
|
|
40163
|
+
* implementation -- i.e. the mistake, not this code.
|
|
40164
|
+
*/
|
|
40165
|
+
function readAllowedFirstAuthFactors(properties) {
|
|
40166
|
+
const factors = (properties["Policies"]?.["SignInPolicy"])?.["AllowedFirstAuthFactors"];
|
|
40167
|
+
if (!Array.isArray(factors)) return [];
|
|
40168
|
+
return factors.filter((factor) => typeof factor === "string");
|
|
40169
|
+
}
|
|
40170
|
+
/**
|
|
40171
|
+
* The PRE-FLIGHT: the reason this user-pool configuration cannot be applied at
|
|
40172
|
+
* all, or `undefined` when nothing is known to refuse it.
|
|
40173
|
+
*
|
|
40174
|
+
* Two rules, both for combinations AWS rejects 100% of the time, and both
|
|
40175
|
+
* raised BEFORE the first AWS call on BOTH the create and the update path. The
|
|
40176
|
+
* ordering is what makes them worth refusing rather than warning about: on the
|
|
40177
|
+
* UPDATE path `UpdateUserPool` lands FIRST and `SetUserPoolMfaConfig` is
|
|
40178
|
+
* refused afterwards, so sending the request leaves a PARTIAL APPLY behind --
|
|
40179
|
+
* with the security-relevant half being the half that did NOT apply (the MFA
|
|
40180
|
+
* configuration), while the half that did is the one loosening authentication.
|
|
40181
|
+
* Nothing unwinds it, and a retry cannot succeed until the user reverse-engineers
|
|
40182
|
+
* an AWS-worded error about a field they did not think they were changing.
|
|
40183
|
+
*
|
|
40184
|
+
* Rule 1 (issue #1977) -- `MfaConfiguration` resolves to OFF while the request
|
|
40185
|
+
* carries an MFA factor block. MEASURED us-east-1 2026-08-19 (issue #1968):
|
|
40186
|
+
*
|
|
40187
|
+
* {ON, SoftwareTokenMfaConfiguration: {Enabled: true}} -> ACCEPTED (control)
|
|
40188
|
+
* {OFF, SoftwareTokenMfaConfiguration: {Enabled: true}} -> rejected
|
|
40189
|
+
* {OFF, SoftwareTokenMfaConfiguration: {Enabled: false}} -> rejected
|
|
40190
|
+
* {OFF, EmailMfaConfiguration: {Message, Subject}} -> rejected
|
|
40191
|
+
*
|
|
40192
|
+
* all with `InvalidParameterException: Invalid MFA configuration given, can't
|
|
40193
|
+
* turn off MFA and configure an MFA together`. The `Enabled: false` arm settles
|
|
40194
|
+
* the KEY: a block that enables NOTHING is still refused, so the rule is about
|
|
40195
|
+
* the block's PRESENCE -- exactly what `hasAnyMfaFactorBlock` tests -- and
|
|
40196
|
+
* since that predicate is precisely the three factor sub-blocks, no accepted
|
|
40197
|
+
* case survives. (Bound on the Email arm: an OPTIONAL control with that block
|
|
40198
|
+
* failed with a DIFFERENT error, "Cannot set EmailMfaConfiguration when user
|
|
40199
|
+
* pool EmailConfiguration contains an EmailSendingAccount of COGNITO_DEFAULT",
|
|
40200
|
+
* so it has no isolated control of its own -- informative in itself, since it
|
|
40201
|
+
* shows the exclusion is evaluated BEFORE the email-sending-account check.)
|
|
40202
|
+
*
|
|
40203
|
+
* Rule 2 (issue #1975) -- the `SetUserPoolMfaConfig` request resolves
|
|
40204
|
+
* `MfaConfiguration` to ON while `Policies.SignInPolicy.AllowedFirstAuthFactors`
|
|
40205
|
+
* allows `EMAIL_OTP` or `SMS_OTP`. AWS refuses with `Only PASSWORD and WEB_AUTHN
|
|
40206
|
+
* (if configured) can be enabled as an auth factor if MFA is enabled`. MEASURED
|
|
40207
|
+
* us-east-1 2026-08-19, both members and both MFA modes:
|
|
40208
|
+
*
|
|
40209
|
+
* {[PASSWORD, EMAIL_OTP], ON} -> rejected
|
|
40210
|
+
* {[PASSWORD, EMAIL_OTP], OPTIONAL} -> ACCEPTED
|
|
40211
|
+
* {[PASSWORD, SMS_OTP], ON} -> rejected (pool WITH a valid SmsConfiguration)
|
|
40212
|
+
* {[PASSWORD, SMS_OTP], OPTIONAL} -> ACCEPTED
|
|
40213
|
+
*
|
|
40214
|
+
* So `=== 'ON'` is MEASURED-CORRECT rather than merely conservative: OPTIONAL is
|
|
40215
|
+
* ACCEPTED, and widening this to `!== 'OFF'` would REFUSE A WORKING DEPLOY. An
|
|
40216
|
+
* earlier revision of this comment called OPTIONAL unmeasured; it is not, and
|
|
40217
|
+
* the measurement is what settles the narrowing rather than a cost argument.
|
|
40218
|
+
*
|
|
40219
|
+
* WHY THE MESSAGE DOES NOT OFFER `WEB_AUTHN` AS THE ESCAPE HATCH, even though
|
|
40220
|
+
* AWS's own error text names it as accepted. MEASURED us-east-1 2026-08-20: a
|
|
40221
|
+
* pool allowing `WEB_AUTHN` as a first auth factor is REJECTED by
|
|
40222
|
+
* `SetUserPoolMfaConfig(ON, SoftwareTokenMfa)` --
|
|
40223
|
+
*
|
|
40224
|
+
* InvalidParameterException: Cannot set WebAuthn factor configuration to
|
|
40225
|
+
* SINGLE_FACTOR if MFA is required and WebAuthn is an allowed first auth factor
|
|
40226
|
+
*
|
|
40227
|
+
* -- with NO WebAuthn block at all, with `UserVerification: preferred`, and with
|
|
40228
|
+
* `required`. The only accepted shape is
|
|
40229
|
+
* `WebAuthnConfiguration.FactorConfiguration = MULTI_FACTOR_WITH_USER_VERIFICATION`,
|
|
40230
|
+
* and the PINNED SDK (`@aws-sdk/client-cognito-identity-provider` 3.1018.0)
|
|
40231
|
+
* does not carry that field -- `WebAuthnConfigurationType` is exactly
|
|
40232
|
+
* `{RelyingPartyId?, UserVerification?}` -- so cdkd cannot reach it today.
|
|
40233
|
+
* Telling the user to switch to `WEB_AUTHN` would therefore be advice that
|
|
40234
|
+
* cannot be followed, which is why the remedy names removing the factor or
|
|
40235
|
+
* lowering `MfaConfiguration` instead.
|
|
40236
|
+
*
|
|
40237
|
+
* That same measurement means `WEB_AUTHN` + ON reproduces this very
|
|
40238
|
+
* partial-apply shape while NOT being on the deny-list. Deliberately left
|
|
40239
|
+
* uncovered: the correct rule there is CONDITIONAL on
|
|
40240
|
+
* `WebAuthnConfiguration.FactorConfiguration`, which the pinned SDK cannot
|
|
40241
|
+
* express, so a flat deny-list entry would be an OVER-REFUSAL of the shape that
|
|
40242
|
+
* becomes valid the moment the SDK gains the field. Tracked as issue #2064.
|
|
40243
|
+
*
|
|
40244
|
+
* SCOPE LIMIT, deliberate and load-bearing: rule 2 fires only when a
|
|
40245
|
+
* `SetUserPoolMfaConfig` request is actually BUILT (`hasMfaConfigProps`), i.e.
|
|
40246
|
+
* the template declares `EnabledMfas` / an email-OTP message or subject /
|
|
40247
|
+
* WebAuthn. With NONE of those, `MfaConfiguration` rides on the SINGLE
|
|
40248
|
+
* `CreateUserPool` / `UpdateUserPool` call and no second call follows -- so
|
|
40249
|
+
* there is no two-call window and structurally NOTHING to partly apply, which
|
|
40250
|
+
* is the entire harm this pre-flight exists to prevent. Refusing there would
|
|
40251
|
+
* ALSO be an over-refusal on a shape AWS accepts: a pool created with
|
|
40252
|
+
* `AllowedFirstAuthFactors: [PASSWORD, EMAIL_OTP]` and no MFA configuration
|
|
40253
|
+
* call at all is ACCEPTED (measured, same session -- the pool came up fine and
|
|
40254
|
+
* only the later `SetUserPoolMfaConfig(ON)` failed). Such a template is left to
|
|
40255
|
+
* AWS, which answers it atomically.
|
|
40256
|
+
*
|
|
40257
|
+
* CLOUDFORMATION PARITY, settled by A/B rather than assumed -- both issues made
|
|
40258
|
+
* this an explicit precondition. CloudFormation hits the SAME rejections and
|
|
40259
|
+
* rolls the stack back:
|
|
40260
|
+
*
|
|
40261
|
+
* {MfaConfiguration: OFF, EnabledMfas: [SOFTWARE_TOKEN_MFA]}
|
|
40262
|
+
* -> ROLLBACK_COMPLETE, "Invalid MFA configuration given, can't turn off
|
|
40263
|
+
* MFA and configure an MFA together"
|
|
40264
|
+
* {MfaConfiguration: ON, EnabledMfas: [SOFTWARE_TOKEN_MFA],
|
|
40265
|
+
* AllowedFirstAuthFactors: [PASSWORD, EMAIL_OTP]} (ESSENTIALS tier)
|
|
40266
|
+
* -> ROLLBACK_COMPLETE, "Only PASSWORD and WEB_AUTHN..."
|
|
40267
|
+
*
|
|
40268
|
+
* So refusing is PARITY-PRESERVING, not a divergence: cdkd refuses the same SET
|
|
40269
|
+
* of templates CloudFormation refuses, only EARLIER (before the first API call
|
|
40270
|
+
* instead of after a partial apply) and in cdkd's own wording. Nothing that
|
|
40271
|
+
* deploys under CloudFormation is blocked here.
|
|
40272
|
+
*
|
|
40273
|
+
* Both rules read the value cdkd would SEND rather than the raw template value,
|
|
40274
|
+
* from ONE `buildMfaConfigRequest` call, so the refusal and the request can
|
|
40275
|
+
* never disagree about what OFF / ON means for a given bag. The build runs with
|
|
40276
|
+
* NO logger, so the pre-flight is silent and `applyMfaConfig`'s own warnings
|
|
40277
|
+
* still fire exactly once.
|
|
40278
|
+
*
|
|
40279
|
+
* WHAT THIS CANNOT SEE, stated because the message says "refuses it before
|
|
40280
|
+
* sending anything" and that reads as a completeness claim: the pre-flight
|
|
40281
|
+
* inspects the TEMPLATE, never the live pool, so two template edits reach the
|
|
40282
|
+
* same partial apply without tripping it -- DELETING the `SignInPolicy` block
|
|
40283
|
+
* while setting `MfaConfiguration: ON`, and OMITTING `MfaConfiguration` while
|
|
40284
|
+
* adding `EMAIL_OTP` to a pool whose live MFA is already ON. Both need a
|
|
40285
|
+
* live-state guard and are tracked in #2051.
|
|
40286
|
+
*
|
|
40287
|
+
* Deliberately UNCONDITIONAL -- no `CreateContext.replayingState` downgrade.
|
|
40288
|
+
* `.claude/rules/providers.md` says a create-path pre-flight refusal MUST
|
|
40289
|
+
* downgrade on a replay, so this is a STATED EXCEPTION rather than an
|
|
40290
|
+
* oversight, and the rule's own reasoning is what licenses it: the downgrade
|
|
40291
|
+
* exists because a refusal against a STATE record leaves a resource
|
|
40292
|
+
* un-rollbackable with no template-side remedy. That presupposes the replay
|
|
40293
|
+
* could otherwise SUCCEED. Here it cannot -- both combinations are rejected by
|
|
40294
|
+
* AWS 100% of the time (measured above, and CloudFormation rolls back on the
|
|
40295
|
+
* same templates), so downgrading would trade a clear cdkd-worded refusal for
|
|
40296
|
+
* the identical failure arriving later from AWS, on the create path with a
|
|
40297
|
+
* pool to roll back and on the update path with a partial apply. A state record
|
|
40298
|
+
* additionally cannot legitimately HOLD either combination: state is written
|
|
40299
|
+
* only after a SUCCESSFUL apply, and neither can be applied. Revisit this if
|
|
40300
|
+
* AWS ever starts accepting one of them.
|
|
40301
|
+
*/
|
|
40302
|
+
function describeUnsupportedMfaCombination(properties, declaredMfaConfiguration) {
|
|
40303
|
+
const request = buildMfaConfigRequest("", properties, void 0, declaredMfaConfiguration);
|
|
40304
|
+
if (request && request.MfaConfiguration === "OFF" && hasAnyMfaFactorBlock(request)) {
|
|
40305
|
+
const blocks = [
|
|
40306
|
+
...request.SmsMfaConfiguration !== void 0 ? ["SmsMfaConfiguration"] : [],
|
|
40307
|
+
...request.SoftwareTokenMfaConfiguration !== void 0 ? ["SoftwareTokenMfaConfiguration"] : [],
|
|
40308
|
+
...request.EmailMfaConfiguration !== void 0 ? ["EmailMfaConfiguration"] : []
|
|
40309
|
+
];
|
|
40310
|
+
return `${MFA_CONFIGURATION_PATH} is OFF while an MFA factor is configured (SetUserPoolMfaConfig would carry ${blocks.join(", ")}, built from EnabledMfas / EmailAuthenticationMessage / EmailAuthenticationSubject). AWS rejects that combination ("Invalid MFA configuration given, can't turn off MFA and configure an MFA together"), so cdkd refuses it before sending anything rather than leaving a partly-applied update behind. Set MfaConfiguration to ON or OPTIONAL (or remove it) to enable the declared factor. (If MFA is genuinely not wanted, remove EnabledMfas / EmailAuthenticationMessage / EmailAuthenticationSubject instead.)`;
|
|
40311
|
+
}
|
|
40312
|
+
if (request && request.MfaConfiguration === "ON") {
|
|
40313
|
+
const denied = MFA_INCOMPATIBLE_FIRST_AUTH_FACTORS;
|
|
40314
|
+
const offending = readAllowedFirstAuthFactors(properties).filter((factor) => denied.includes(factor));
|
|
40315
|
+
if (offending.length > 0) return `${MFA_CONFIGURATION_PATH} is ON while Policies.SignInPolicy.AllowedFirstAuthFactors allows ${offending.join(", ")}. AWS rejects that combination ("Only PASSWORD and WEB_AUTHN (if configured) can be enabled as an auth factor if MFA is enabled"), and on an update the sign-in policy has already been applied by the time it does, so cdkd refuses it before sending anything rather than leaving a partly-applied update behind. Remove ${offending.join(", ")} from Policies.SignInPolicy.AllowedFirstAuthFactors, leaving PASSWORD. (Setting MfaConfiguration to OPTIONAL or OFF also clears the conflict, but weakens MFA.)`;
|
|
40316
|
+
}
|
|
40317
|
+
}
|
|
40318
|
+
/**
|
|
40078
40319
|
* Replace a DECLARED-but-unusable `MfaConfiguration` with the value cdkd
|
|
40079
40320
|
* actually sends, or drop the key when nothing is sent. Returns the input
|
|
40080
40321
|
* object unchanged when nothing applies, so the common case compares
|
|
@@ -40158,7 +40399,7 @@ var CognitoUserPoolProvider = class {
|
|
|
40158
40399
|
"WebAuthnRelyingPartyID",
|
|
40159
40400
|
"WebAuthnUserVerification"
|
|
40160
40401
|
])]]);
|
|
40161
|
-
unhandledByDesign = /* @__PURE__ */ new Map([["AWS::Cognito::UserPool", /* @__PURE__ */ new Map([["WebAuthnFactorConfiguration", "No
|
|
40402
|
+
unhandledByDesign = /* @__PURE__ */ new Map([["AWS::Cognito::UserPool", /* @__PURE__ */ new Map([["WebAuthnFactorConfiguration", "No wire path in the PINNED SDK (@aws-sdk/client-cognito-identity-provider 3.1018.0): WebAuthnConfigurationType is {RelyingPartyId?, UserVerification?} and no CreateUserPool/UpdateUserPool field accepts SINGLE_FACTOR | MULTI_FACTOR_WITH_USER_VERIFICATION. This is an SDK-VERSION limit, NOT an API one -- the live API does honour FactorConfiguration (measured us-east-1 2026-08-20: SetUserPoolMfaConfig(ON) on a pool allowing WEB_AUTHN as a first auth factor is rejected with \"Cannot set WebAuthn factor configuration to SINGLE_FACTOR if MFA is required and WebAuthn is an allowed first auth factor\", i.e. the service reads a field the SDK cannot send). RE-EVALUATE THIS ENTRY ON AN SDK BUMP: if WebAuthnConfigurationType gains FactorConfiguration, the property becomes handleable and this entry must go"]])]]);
|
|
40162
40403
|
/**
|
|
40163
40404
|
* Warn when `MfaConfiguration` is declared as a BLANK string (issue #1925
|
|
40164
40405
|
* item 2, review round 2).
|
|
@@ -40187,6 +40428,26 @@ var CognitoUserPoolProvider = class {
|
|
|
40187
40428
|
this.logger.warn("AWS::Cognito::UserPool MfaConfiguration is an empty string, which declares no MFA mode and is treated as absent -- a collapsed Fn::Join or an empty String parameter produces this shape. The pool deploys with the default MFA configuration instead; declare ON / OPTIONAL / OFF explicitly, or omit the property, to say which was meant.");
|
|
40188
40429
|
}
|
|
40189
40430
|
/**
|
|
40431
|
+
* Raise {@link describeUnsupportedMfaCombination}'s verdict as a typed
|
|
40432
|
+
* refusal, or return silently when there is nothing to refuse.
|
|
40433
|
+
*
|
|
40434
|
+
* A `ProvisioningError` so both call sites behave the way each already does
|
|
40435
|
+
* with the sibling `MfaConfiguration` shape refusal: on the create path it
|
|
40436
|
+
* surfaces as the provider's own error rather than an AWS one, and on the
|
|
40437
|
+
* update path `update()`'s catch re-throws an already-wrapped
|
|
40438
|
+
* `ProvisioningError` unchanged, so it is not double-wrapped. Both call sites
|
|
40439
|
+
* are OUTSIDE their method's try, so the throw travels untouched either way.
|
|
40440
|
+
*
|
|
40441
|
+
* `target` is the pool NAME on create (there is no physical id yet) and the
|
|
40442
|
+
* physical id on update, matching what each path passes to its other
|
|
40443
|
+
* `ProvisioningError`s.
|
|
40444
|
+
*/
|
|
40445
|
+
assertMfaCombinationApplicable(logicalId, resourceType, target, properties, declaredMfaConfiguration) {
|
|
40446
|
+
const reason = describeUnsupportedMfaCombination(properties, declaredMfaConfiguration);
|
|
40447
|
+
if (reason === void 0) return;
|
|
40448
|
+
throw new ProvisioningError(reason, resourceType, logicalId, target);
|
|
40449
|
+
}
|
|
40450
|
+
/**
|
|
40190
40451
|
* The DIFF-side half of the `MfaConfiguration` substitution record.
|
|
40191
40452
|
*
|
|
40192
40453
|
* Applied by `DiffCalculator` to BOTH comparison sides, so a template that
|
|
@@ -40276,6 +40537,7 @@ var CognitoUserPoolProvider = class {
|
|
|
40276
40537
|
} catch (error) {
|
|
40277
40538
|
throw new ProvisioningError(error instanceof Error ? error.message : String(error), resourceType, logicalId, poolName, error instanceof Error ? error : void 0);
|
|
40278
40539
|
}
|
|
40540
|
+
this.assertMfaCombinationApplicable(logicalId, resourceType, poolName, properties, mfaConfiguration);
|
|
40279
40541
|
let createdUserPoolId;
|
|
40280
40542
|
try {
|
|
40281
40543
|
const createParams = { PoolName: poolName };
|
|
@@ -40445,7 +40707,8 @@ var CognitoUserPoolProvider = class {
|
|
|
40445
40707
|
* sub-block in the request AWS REJECTS the call; with none it accepts and
|
|
40446
40708
|
* resets the pool to MFA-disabled. An EXPLICIT OFF beside a block is
|
|
40447
40709
|
* rejected the same way (2026-08-19, issue #1968; the transcript lives at
|
|
40448
|
-
*
|
|
40710
|
+
* `describeUnsupportedMfaCombination`, which since issue #1977 REFUSES that
|
|
40711
|
+
* combination before any call rather than warning about it).
|
|
40449
40712
|
*
|
|
40450
40713
|
* Nothing here licenses a claim about a field on neither list, or about one
|
|
40451
40714
|
* API from the other's section. Measure it.
|
|
@@ -40523,6 +40786,7 @@ var CognitoUserPoolProvider = class {
|
|
|
40523
40786
|
this.logger.debug(`Updating Cognito User Pool ${logicalId}: ${physicalId}`);
|
|
40524
40787
|
const mfaConfiguration = readDeclaredMfaConfiguration(properties["MfaConfiguration"], { onUnusable: (message) => this.logger.warn(message) });
|
|
40525
40788
|
this.warnOnBlankMfaConfiguration(properties["MfaConfiguration"]);
|
|
40789
|
+
this.assertMfaCombinationApplicable(logicalId, resourceType, physicalId, properties, mfaConfiguration);
|
|
40526
40790
|
const liveMfa = mfaConfiguration === "" && hasMfaConfigProps(properties) ? await this.readLiveMfaConfiguration(physicalId) : void 0;
|
|
40527
40791
|
try {
|
|
40528
40792
|
const updateParams = { UserPoolId: physicalId };
|
|
@@ -82898,7 +83162,7 @@ function createMigrateCommand() {
|
|
|
82898
83162
|
*/
|
|
82899
83163
|
function buildProgram() {
|
|
82900
83164
|
const program = new Command();
|
|
82901
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.
|
|
83165
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.14");
|
|
82902
83166
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
82903
83167
|
const { profile } = actionCommand.optsWithGlobals();
|
|
82904
83168
|
if (profile !== void 0) process.env["AWS_PROFILE"] = profile;
|