@go-to-k/cdkd 0.296.31 → 0.298.0
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-Ca7cV9tM.js → asg-provider-B1xRE8do.js} +5 -5
- package/dist/{asg-provider-Ca7cV9tM.js.map → asg-provider-B1xRE8do.js.map} +1 -1
- package/dist/{aws-failure-text-BaWeCWRz.js → aws-failure-text-DtvlUugx.js} +2 -2
- package/dist/{aws-failure-text-BaWeCWRz.js.map → aws-failure-text-DtvlUugx.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-5FFXg6ih.js → deploy-engine-CJTG3tft.js} +1944 -469
- package/dist/deploy-engine-CJTG3tft.js.map +1 -0
- package/dist/{iam-policy-targets-Cz2tPxXk.js → iam-policy-targets-CwKiK9nS.js} +2 -2
- package/dist/{iam-policy-targets-Cz2tPxXk.js.map → iam-policy-targets-CwKiK9nS.js.map} +1 -1
- package/dist/{iam-role-provider-syetbMnw.js → iam-role-provider-qxfS4sDT.js} +24 -4
- package/dist/{iam-role-provider-syetbMnw.js.map → iam-role-provider-qxfS4sDT.js.map} +1 -1
- package/dist/index.d.ts +21 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/{neptune-provider-B1D2CFBs.js → neptune-provider-CU_1O2FR.js} +4 -4
- package/dist/{neptune-provider-B1D2CFBs.js.map → neptune-provider-CU_1O2FR.js.map} +1 -1
- package/dist/{program-Db1eBDeq.js → program-BivXyHmd.js} +584 -83
- package/dist/program-BivXyHmd.js.map +1 -0
- package/dist/{provider-classes-B7Z4-Zsc.js → provider-classes-1EHrZ847.js} +73 -23
- package/dist/provider-classes-1EHrZ847.js.map +1 -0
- package/dist/{rds-provider-B4sFJ8YW.js → rds-provider-J40R0ysf.js} +6 -6
- package/dist/{rds-provider-B4sFJ8YW.js.map → rds-provider-J40R0ysf.js.map} +1 -1
- package/dist/{version-D0cK9V1A.js → version-D96I6uiO.js} +2 -2
- package/dist/{version-D0cK9V1A.js.map → version-D96I6uiO.js.map} +1 -1
- package/package.json +3 -1
- package/dist/deploy-engine-5FFXg6ih.js.map +0 -1
- package/dist/program-Db1eBDeq.js.map +0 -1
- package/dist/provider-classes-B7Z4-Zsc.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { a as runWithStackAwsClients, i as resetAwsClients, o as setAwsClients, t as AwsClients } from "./aws-clients-CnmtbrxD.js";
|
|
2
|
-
import { A as UNRENDERABLE, B as stringifyJsonPayload, D as SAFE_MSG_ALTERED_CHAR, F as displayStackName, I as isPasteableIdent, M as displayAwsMessage, N as displayIdent, O as SECRET_REF_MAX_CODE_POINTS, P as displaySafe, R as plainIdentOr, T as withStackName,
|
|
3
|
-
import { $n as isAmbiguousOutcomeError, $t as credentialFingerprint, Bn as withheldTargetClause, D as VALUE_NOT_SHOWN, Dn as TIMEOUT_FLAG_RESOURCE_TYPE, E as assertRegionMatch, En as withErrorHandling, Ft as buildLockContentionMessage, G as runDeleteAttempt, Hn as setPasteableVerbFlags, Ht as CUSTOM_RESOURCE_RESPONSE_PREFIX, In as plainOrDescribed, It as forceQuitRecoveryClause, Jt as setPasteableAwsProfile, Kt as producerCoordinateKey, Ln as quotedOrDescribed, Lt as formatLockExpiry, Nn as isInertUnquoted, Nt as UNREPRODUCIBLE_LOCK_CLAUSE, P as remedyLogicalId, Pn as pasteableCommand, Pt as buildForceUnlockCommand, Qt as clientDefaultsFor, Rn as shellBoundedDisplay, Rt as formatLockOperation, Sn as SynthesisError, T as RESOURCE_NOT_FOUND, Tn as normalizeAwsError, Ut as DEFAULT_STATE_PREFIX, Vn as setPasteableRunFlags, Wt as injectiveKey, Xt as ambientClientDefaults, Yt as withPasteableAwsProfile, Z as isAwsCliLiteral, Zt as ambientCredentialConfig, _n as ResourceTimeoutError, ar as isMarkedNonRetryable, bn as StackTerminationProtectionError, cn as IntrinsicResolutionRefusalError, en as AccountIdUnavailableError, ft as logicalIdShown, gn as ProvisioningError, hn as PartialFailureError, in as CrossAccountSecretRefusalError, it as isInterruptedWaitError, jn as commandHole, kn as SHELL_ACTIVE_WHY, ln as LocalInvokeBuildError$1, mn as NestedStackChildDirectDestroyError, mt as resourceTypeShown, n as RESOLVED_PREVIOUS_PRINCIPAL_KEYS, nn as CdkdError, nr as isTransientServerError, nt as endCommandInterruptScope, on as DeployCancelledError, or as isThrottlingError, pn as MalformedProducerRecordRefusalError, qt as producerRecordKey, rr as retryClassificationText, rt as interruptWatchListenerCount, s as readRecordedPrincipals, sn as DynamicReferenceRegionAmbiguousError, sr as markNonRetryable, t as IAM_PRINCIPAL_NAME, tr as isRetryableTransientError, tt as beginCommandInterruptScope, un as LocalStartServiceError, vn as ResourceUpdateNotSupportedError, yn as StackHasActiveImportsError, zn as shellQuote, zt as formatLockOwner } from "./iam-policy-targets-
|
|
2
|
+
import { A as UNRENDERABLE, B as stringifyJsonPayload, D as SAFE_MSG_ALTERED_CHAR, F as displayStackName, H as truncateCodePoints, I as isPasteableIdent, M as displayAwsMessage, N as displayIdent, O as SECRET_REF_MAX_CODE_POINTS, P as displaySafe, R as plainIdentOr, T as withStackName, _ as derivesPatternBName, a as getLogger, f as getLiveRenderer, h as PATTERN_B_RESOURCE_TYPES, j as cutMarker, k as STACK_REF_MAX_CODE_POINTS, l as runStackBuffered, m as PATTERN_B_NAME_PROPERTIES, o as isStdoutReservedForPayload, p as PATTERN_B_NAME_OPTIONS, r as safeStringify, s as reserveStdoutForPayload, t as describeAwsFailure, v as explicitNamePropertyFor, w as withSkipPrefix, y as generateResourceName, z as safeMsg } from "./aws-failure-text-DtvlUugx.js";
|
|
3
|
+
import { $n as isAmbiguousOutcomeError, $t as credentialFingerprint, Bn as withheldTargetClause, D as VALUE_NOT_SHOWN, Dn as TIMEOUT_FLAG_RESOURCE_TYPE, E as assertRegionMatch, En as withErrorHandling, Ft as buildLockContentionMessage, G as runDeleteAttempt, Hn as setPasteableVerbFlags, Ht as CUSTOM_RESOURCE_RESPONSE_PREFIX, In as plainOrDescribed, It as forceQuitRecoveryClause, Jt as setPasteableAwsProfile, Kt as producerCoordinateKey, Ln as quotedOrDescribed, Lt as formatLockExpiry, Nn as isInertUnquoted, Nt as UNREPRODUCIBLE_LOCK_CLAUSE, P as remedyLogicalId, Pn as pasteableCommand, Pt as buildForceUnlockCommand, Qt as clientDefaultsFor, Rn as shellBoundedDisplay, Rt as formatLockOperation, Sn as SynthesisError, T as RESOURCE_NOT_FOUND, Tn as normalizeAwsError, Ut as DEFAULT_STATE_PREFIX, Vn as setPasteableRunFlags, Wt as injectiveKey, Xt as ambientClientDefaults, Yt as withPasteableAwsProfile, Z as isAwsCliLiteral, Zt as ambientCredentialConfig, _n as ResourceTimeoutError, ar as isMarkedNonRetryable, bn as StackTerminationProtectionError, cn as IntrinsicResolutionRefusalError, en as AccountIdUnavailableError, ft as logicalIdShown, gn as ProvisioningError, hn as PartialFailureError, in as CrossAccountSecretRefusalError, it as isInterruptedWaitError, jn as commandHole, kn as SHELL_ACTIVE_WHY, ln as LocalInvokeBuildError$1, mn as NestedStackChildDirectDestroyError, mt as resourceTypeShown, n as RESOLVED_PREVIOUS_PRINCIPAL_KEYS, nn as CdkdError, nr as isTransientServerError, nt as endCommandInterruptScope, on as DeployCancelledError, or as isThrottlingError, pn as MalformedProducerRecordRefusalError, qt as producerRecordKey, rr as retryClassificationText, rt as interruptWatchListenerCount, s as readRecordedPrincipals, sn as DynamicReferenceRegionAmbiguousError, sr as markNonRetryable, t as IAM_PRINCIPAL_NAME, tr as isRetryableTransientError, tt as beginCommandInterruptScope, un as LocalStartServiceError, vn as ResourceUpdateNotSupportedError, yn as StackHasActiveImportsError, zn as shellQuote, zt as formatLockOwner } from "./iam-policy-targets-CwKiK9nS.js";
|
|
4
4
|
import { n as awsClientDefaults, r as getAssumedRoleCredentials, u as formatAuthority } from "./aws-client-defaults-D0q0z4dG.js";
|
|
5
|
-
import { $c as processStackMessages, $i as malformedScrubResourceEntriesRefusalMessage, $o as inheritNestedStackParameterAssociations, $r as envCredentialsAreAssumedRole, $s as parseBootstrapMarker, $t as orphanDeleteNeedsIdentity, A as noEchoExactEchoLeavesOf, Aa as repairMalformedResourcePropertiesForReadOnly, Ac as resolveApp, Ai as displayLogicalId, An as maskEventTextWithBoundBags, Ao as valueAtCoordinate, As as hasReadableExportSet, At as isHandledOrphan, Ba as NO_CC_HANDLERS_REASON, Bc as CFN_TEMPLATE_BODY_LIMIT, Bi as malformedLocalResourceEntriesWarning, Bn as ccRoutedFinalSnapshotError, Bo as shareLogOnlyValues, Br as poisonRenderedSpellingsCollidingIn, Bs as isSensitiveAttributeName, Bt as withStackRecords, C as recordRetainedForReadoption, Ca as refuseMalformedResourcesForDestroy, Cc as AssetManifestLoader, Ci as JSON_LISTING_HOLE_VALUE, Cn as collectPublishedOutputNames, Co as maskedLeafCoordinatesOf, Cs as crossPrefixDeniedWarning, Ct as revertedNestedRowIds, D as withResourceDeadline, Da as repairMalformedOrphansForReadOnly, Dc as getDefaultStateBucketName, Di as UNREADABLE_RESOURCES_MAP_ROW, Dn as DEFAULT_RESOURCE_WARN_AFTER_MS, Dr as deleteSkipReason, Ds as acceptedCreateOnlyDropsOf, Dt as withNestedStackContext, E as serviceTokenBlockingReason, Ea as repairMalformedOrphanRecordsForReadOnly, Ec as synthesisStatusMessage, Ei as UNREADABLE_ORPHANS_CONTAINER_ROW, En as DEFAULT_RESOURCE_TIMEOUT_MS, Eo as noEchoOutputsComparison, Er as deleteLeftInPlace, Es as splitImportedOps, F as isProtectionValueActive, Fa as withheldAccountClause, Fc as resolveStateBucketWithDefaultAndSource, Fi as isReadableResourceEntry, Fn as storedSecretNameNeedles, Fo as literalSplitDelimitersOf, Fs as isReadableBag, Ft as replayFailedOperations, Ga as isStatefulRecreateTargetForReplace, Gc as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, Gi as malformedOrphansRefusalMessage, Gn as unsupportedFinalSnapshotError, Go as markSameGenerationBag, Gr as assertFlagRoleArn, Gs as loadPublishableAssetManifest, Gt as isReplacementOrphan, Ha as findReplacedReadersOfRecreateTargets, Hc as MIGRATE_TMP_PREFIX, Hi as malformedOrphanRecordsRefusalMessage, Hn as effectiveDeletionPolicy, Ho as errorCauseChain, Hr as producerRegionsFromState, Hs as WorkGraph, Ht as recordAfterRollbackUpdate, I as perType, Ia as findActionableSilentDrops, Ic as resolveUseCdkBootstrapAssets, Ii as malformedDriftResourcePropertiesWarning, In as extractDeploymentEventError, Io as logOnlyValueCount, Is as orphansAfterRollback, It as replayRollback, Jc as PARTITION_TABLE, Ji as malformedOutputsWarning, Jn as findDestructiveChanges, Jo as DYNAMIC_REFERENCE_TOKEN_SCAN, Jr as isIamRoleArn, Js as BOOTSTRAP_MARKER_PREFIX, Jt as recheckFailedPlan, Ka as isStatefulRecreateTargetSync, Kc as decodeListingKey, Ki as malformedOrphansWarning, Kn as maskingRetryLogger, Ko as redactSecretsForState, Kr as assertSendableRoleArn, Ks as rewriteTemplateAssetReferences, Kt as planFailedOps, L as readProtection, Lc as stateBucketExistenceConfirmed, Li as malformedExportNamesWarning, Ln as ATOMIC_FINAL_SNAPSHOT_TYPES, Lo as printingCorpusOf, Lr as DiffCalculator, Ls as orphansCarriedFrom, M as recordedProtectionEvidence, Ma as unpreviewableOrphanRecords, Mc as resolveCaptureObservedState, Mi as hasReadableOutputs, Mn as secretNamePrintingBag, Mo as carryLogOnlyValues, Ms as hasUnverifiableParameterRefusal, Mt as loadJournaledOrphans, N as recordedProtectionNote, Na as unreadableOrphanRecords, Nc as resolveSkipPrefix, Ni as hasReadableResources, Nn as secretNamedRecordNeedles, No as createUnionSecretMasker, Ns as importableOutputKeys, Nt as makeForeignHolderScan, O as noEchoAttributeNamesOf, Oa as repairMalformedOutputsForReadOnly, Oc as getLegacyStateBucketName, Oi as accountArgs, On as completedReplayEntries, Oo as readbackPathFor, Os as describeRegionValueKind, Ot as deleteJournaledOrphans, P as PROTECTION_PROPERTY_BY_TYPE, Pa as unreadableResourceEntries, Pc as resolveStateBucketWithDefault, Pi as isReadableOrphanRecord, Pn as stateSecretNameNeedles, Po as hasMaskableValues, Ps as importableOutputs, Pt as sameJournaledOrphans, Qc as StageLoadError, Qi as malformedResourcesWarning, Qn as ledgerForStack, Qo as identityKeyFor, Qr as callerEnvCredentials, Qs as isCrossRegionRedirect, Qt as seedsDeleteFirstGuard, Ra as unwrittenCreateOnlyReplacement, Rc as warnDeprecatedNoPrefixCliFlag, Ri as malformedExportSourceWarning, Rn as PRE_DELETE_SNAPSHOT_TYPES, Ro as recordLogOnlyParameterValue, Rr as INTRINSIC_KEYS, Rs as shouldRetainResource, Rt as destroyStackRecordsView, S as keptForReadoption, Sa as refuseMalformedResourcesForDeploy, Sc as stripControlChars, Sn as collectDeclaredOutputNames, So as maskWholeValue, Sr as slowCcOperationTimeoutMs, Ss as applyCrossPrefixScan, T as findServiceTokenRefusals, Ta as refuseMalformedState, Tc as Synthesizer, Ti as STATE_RESOURCES_MALFORMED, Tn as bindingSkippedOutputs, To as noEchoLeavesOf, Tr as deleteIndeterminateGuards, Ts as isNotImplemented, Tt as collectNestedChildUnaddressed, Ua as shownType, Uc as findLargeInlineResources, Ui as malformedOrphanRecordsWarning, Un as isFinalSnapshotError, Uo as maskSecretsInError, Ur as regionLessSecretName, Us as buildAssetRedirectMap, Ut as demoteSupersededOrphans, Va as hasNoCloudControlHandlers, Vc as CFN_TEMPLATE_URL_LIMIT, Vi as malformedLocalResourcesWarning, Vn as createPreDeleteFinalSnapshot, Vo as createSecretMasker, Vr as classifyReplaySecretRegion, Vs as stringifyValue, Vt as removeProtectionTypeList, Wa as MULTI_REGION_RECREATE_BLOCKED_TYPES, Wc as uploadCfnTemplate, Wi as malformedOrphanRowsKeptWarning, Wn as refusesFinalSnapshot, Wo as maskSecretsInText, Wr as applyRoleArnIfSet, Ws as createAssetRedirectResolver, Wt as isJournaledOrphan, Xc as derivePartitionAndUrlSuffix, Xi as malformedResourceEntriesWarning, Xn as RollbackInlinePolicyWriters, Xo as isUncertifiedBaselineMaskPosition, Xr as AWS_CREDENTIAL_ENV_KEYS, Xs as ensureAssetStorage, Xt as replacementNeverSwapped, Yc as canonicalizeRegion, Yi as malformedRenderedContainersWarning, Yn as formatDestructiveChange, Yo as dynamicReferenceTokens, Yr as sendableAssumeRoleCommand, Ys as assertAssetBucketRegion, Yt as recordUnderIdIsNotOwn, Zc as AssemblyReader, Zi as malformedResourcePropertiesWarning, Zo as pathCrossesDottedKey, Zr as applyCallerIdentityCredentials, Zs as getBootstrapMarkerKey, Zt as resolveReplacementOldType, _ as makeCanonicalizePropertiesFn, _a as refuseMalformedResourceEntriesForOrphan, _c as redactedDockerCause, _i as isStalePlaceholderArnAttribute, _n as carriedExportAliasExposure, _o as TemplateParser, _r as readsNoEchoDeleteValues, _s as isLockInfoExpired, _t as displacedPhysicalIdShown, a as findNestedTemplateTreeDefect, aa as refuseMalformedOrphanRecordsForDestroy, ac as resolveDockerContextDirectory, al as absoluteAssemblyPathEscape, as as recordMaskOnlyValuesIn, at as gray, ba as refuseMalformedResourcePropertiesForExport, bc as warnFinchArgvExposure, bi as withSharedDrainBudget, bn as isWholeDynamicReferenceValue, bo as maskAtCoordinates, br as withPrintingSecrets, bs as CrossPrefixReadError, bt as nestedChildStackName$1, c as renderNestedTemplateTreeDefect, ca as refuseMalformedOrphansForOrphan, cc as describeDockerFailure, ci as parameterTypeMayLoseSecretIdentity, cl as renderAssemblyPathEscape, cn as updatePartialReason, cs as recordProvenPublicExpression, ct as yellow, d as conditionInputsFrom, da as refuseMalformedResourceAttributesForOrphan, dc as formatDockerLoginError, di as carriesDynamicReference, dl as resolveBucketRegion, dn as WITHHELD_NAME_DISPLAY, do as describeTypeWithThrottleRetry, dr as CC_BROKEN_REASON, ds as STATE_SOURCED_CROSS_GENERATION_RULES, dt as reachableDivergentParameters, ea as malformedStateRefusalMessage, ec as readBootstrapMarkerBody, el as defineOwnKey, en as findNestedStackTypeChanges, er as withCreateTokenLedger, es as recordNestedStackParameterExpressions, f as parentSuppliedValues, fa as refuseMalformedResourceEntries, fc as getDockerCmd, fi as carriesFetchableDynamicReference, fn as displayTextOrWithheld, fo as withRetry, fr as ProviderRegistry, fs as STATE_SOURCED_READBACK_RULES, ft as resourcesNamingDeclaredParameter, g as mergeNoChangeOutputs, ga as refuseMalformedResourceEntriesForImportSave, gc as redactDockerArgvValues, gi as cfnRefValueFromPhysicalId, gn as secretSafeKeyDisplay, go as DagBuilder, gr as TemplateNoEchoReresolver, gs as LockManager, gt as displacedOpClause, h as keptWholeReasonText, ha as refuseMalformedResourceEntriesForImport, hc as partitionSensitiveEnv, hi as AWS_NO_VALUE, hn as secretBearingStateKeyWarning, hr as wouldReturnToSdkProvider, hs as isSingleDynamicReferenceToken, ht as NESTED_PENDING_PARENT_REASON, i as childTemplateLoader, ia as refuseMalformedOrphanRecords, ic as buildDockerImage, il as ownValue, is as recordMaskOnlyValue, it as cyan, j as noEchoParameterNamesOf, ja as repairMalformedResourcesForReadOnly, jc as resolveAutoAssetStorage, ji as hasReadableOrphans, jn as orphanRecordsPrintingBag, jo as liveMatchesUnresolvedTokenFrame, js as hasReasonlessBaselineRefusal, jt as journaledOrphanLines, k as noEchoComparisonForTemplate, ka as repairMalformedResourceEntriesForReadOnly, kc as loadCdkJson, ki as deployRefusesOrphanRowsReason, kn as journaledOrphanPrintingBag, ko as readsNoEchoSource, kr as isWaitAbandonedError, ks as exportNamesCarriedFrom, kt as dropFailedHint, l as templateIdentity, la as refuseMalformedOutputs, lc as dockerSpawnEnvWithSensitive, li as getAccountInfo, ll as resolveAssemblyPath, ln as DeploymentEventsReader, lo as prefetchCreateOnlyPropertyPaths, ls as wholeStringLeavesOf, lt as computeParameterTaint, m as isSecretBearingReferenceString, ma as refuseMalformedResourceEntriesForDestroy, mc as isMalformedEnvKey, mi as keepsSecretReferenceToken, mn as secretBearing, mr as isCustomResource, ms as WHOLE_DYNAMIC_REFERENCE_PATTERN, mt as planOrphanAdoption, n as IMPLICIT_DELETE_DEPENDENCIES, na as refuseDivergentRecordRegionForDestroy, nc as validateContainerRepoName, nl as hasPlainPrototype, nn as inheritProducerRegions, ns as carriesSecretMask, nt as createReadOnlyAttributeHealerFactory, o as isAbsoluteAssetPath, oa as refuseMalformedOrphans, oc as describeDockerCapturedOutput, oi as coerceParameterTypedValue, ol as describeFileReadFailure, os as recordNoEchoAttributeValues, ot as green, p as readRecordedConditionVerdicts, pa as refuseMalformedResourceEntriesForDeploy, pc as isDockerClientEnvKey, pi as isNamelessDynamicReferenceError, pn as exportAliasCollisionScrubWarning, pr as ccBrokenReason, ps as TEMPLATE_SOURCED_RULES, pt as makeSiblingClaimReader, qa as renderStatefulReason, qc as expectedOwnerParam, qi as malformedOutputsRefusalMessage, qn as constructPathOf, qo as scrubResourceRecord, qr as explicitRoleArnOrThrow, qs as AssetModeResolver, qt as planRollback, r as computeImplicitDeleteEdges, rc as buildDenyExternalAccessPolicy, rl as nullPrototypeRecord, rs as provenPublicValue, rt as bold, s as listNestedTemplateRows, sa as refuseMalformedOrphansForDestroy, sc as describeDockerExecFailure, si as isUnboundTemplateParameter, sl as displayAssemblyPath, sn as updatePartialMessage, ss as recordNoEchoParameterFreshValue, st as red, t as DeployEngine, ta as previewableOrphanRecords, tc as validateAssetBucketName, tl as hasOwnKey, tt as formatResourceLine, u as conditionFingerprint, ua as refuseMalformedOutputsForDestroy, uc as finchSecretArgvRefusal, ui as isImpossibleEmptyStoredAttribute, un as DeploymentEventsStore, uo as templateResourceTypes, us as STATE_SOURCED_BASELINE_RULES, ut as namesAnyDeclaredParameter, va as refuseMalformedResourcePropertiesForDestroy, vc as runDockerForeground, vi as refStateLookupFromResource, vn as exportNameNoEchoParameters, vo as canonicalCoordinates, vr as isCustomResourceType$1, vs as S3StateBackend, vt as dropSettledNestedJournals, w as deferredServiceTokenWarning, wa as refuseMalformedResourcesForExport, wc as getDockerImageBySourceHash, wi as STATE_REGION_DIVERGED, wn as isExportAliasCollision, wo as noEchoCoordinatesOf, wr as UNSPECIFIED_SKIP_REASON, ws as isAccessDenied, wt as withNestedRevertRun, xa as refuseMalformedResourcePropertiesForOrphan, xc as escapeRegExp, xi as parameterInputsFor, xn as noEchoParameterValueSeed, xo as maskReadbackAtCoordinates, xr as CloudControlProvider, xs as CrossPrefixScanCache, xt as recordDisplacedSkips, ya as refuseMalformedResourcePropertiesForDrift, yc as runDockerStreaming, yn as exportNameSecretExposure, yo as isMarkedCoordinate, ys as rebuildClientForBucketRegion, zc as ssmResolvedValueType, zi as malformedLocalOutputsWarning, zn as buildFinalSnapshotIdentifier, zo as recordLogOnlyValue, zr as IntrinsicFunctionResolver, zs as AssetPublisher } from "./deploy-engine-5FFXg6ih.js";
|
|
6
|
-
import { t as getCdkdVersion } from "./version-
|
|
5
|
+
import { $a as isStatefulRecreateTargetForReplace, $c as CFN_TEMPLATE_URL_LIMIT, $i as malformedOrphansRefusalMessage, $n as ledgerForStack, $o as markSameGenerationBag, $r as assertSendableRoleArn, $s as stringifyValue, $t as seedsDeleteFirstGuard, A as noEchoComparisonForTemplate, Aa as refuseMalformedResourcesForDeploy, Ac as runDockerForeground, Ai as declaresNoEcho, An as journaledOrphanPrintingBag, Ao as maskWholeValue, Ar as deleteIndeterminateGuards, As as S3StateBackend, At as dropFailedHint, Ba as unpreviewableOrphanRecords, Bc as getLegacyStateBucketName, Bi as hasReadableOutputs, Bn as PRE_DELETE_SNAPSHOT_TYPES, Bo as carryLogOnlyValues, Bs as describeRegionValueKind, C as recordRetainedForReadoption, Ca as refuseMalformedResourceEntriesForImport, Cc as formatDockerLoginError, Ci as cfnRefValueFromPhysicalId, Cl as resolveBucketRegion, Cn as collectDeclaredOutputNames, Cr as applyCustomResourceResponseExpiration, Cs as STATE_SOURCED_CROSS_GENERATION_RULES, D as withResourceDeadline, Da as refuseMalformedResourcePropertiesForDrift, Dc as partitionSensitiveEnv, Di as withSharedDrainBudget, Dn as DEFAULT_RESOURCE_TIMEOUT_MS, Do as isMarkedCoordinate, Ds as isSingleDynamicReferenceToken, E as serviceTokenBlockingReason, Ea as refuseMalformedResourcePropertiesForDestroy, Ec as isMalformedEnvKey, En as bindingSkippedOutputs, Eo as canonicalCoordinates, Er as slowCcOperationTimeoutMs, Es as WHOLE_DYNAMIC_REFERENCE_PATTERN, Et as collectNestedChildUnaddressed, F as PROTECTION_PROPERTY_BY_TYPE, Fa as repairMalformedOrphansForReadOnly, Fc as AssetManifestLoader, Fi as UNREADABLE_RESOURCES_MAP_ROW, Fn as secretNamedRecordNeedles, Fs as crossPrefixDeniedWarning, Ft as sameJournaledOrphans, Gc as resolveSkipPrefix, Gi as malformedExportNamesWarning, Gn as isFinalSnapshotError, Go as printingCorpusOf, Gr as poisonRenderedSpellingsCollidingIn, Gs as importableOutputKeys, Gt as isJournaledOrphan, Ha as unreadableResourceEntries, Hc as resolveApp, Hi as isReadableOrphanRecord, Hn as ccRoutedFinalSnapshotError, Ho as hasMaskableValues, Hr as DiffCalculator, Hs as hasReadableExportSet, Ht as removeProtectionTypeList, I as isProtectionValueActive, Ia as repairMalformedOutputsForReadOnly, Ic as getDockerImageBySourceHash, Ii as accountArgs, In as stateSecretNameNeedles, Io as readbackPathFor, Is as isAccessDenied, It as replayFailedOperations, Ja as NO_CC_HANDLERS_REASON, Jc as resolveUseCdkBootstrapAssets, Ji as malformedLocalResourceEntriesWarning, Jn as maskingRetryLogger, Jo as shareLogOnlyValues, Jr as regionLessSecretName, Js as orphansAfterRollback, Jt as planRollback, Ka as unwrittenCreateOnlyReplacement, Kc as resolveStateBucketWithDefault, Ki as malformedExportSourceWarning, Kn as refusesFinalSnapshot, Ko as recordLogOnlyParameterValue, Kr as classifyReplaySecretRegion, Ks as importableOutputs, Kt as isReplacementOrphan, L as perType, La as repairMalformedResourceEntriesForReadOnly, Lc as Synthesizer, Li as deployRefusesOrphanRowsReason, Ln as storedSecretNameNeedles, Lo as readsNoEchoSource, Ls as isNotImplemented, Lt as replayRollback, M as noEchoParameterNamesOf, Ma as refuseMalformedResourcesForExport, Mc as warnFinchArgvExposure, Mi as STATE_REGION_DIVERGED, Mn as orphanRecordsPrintingBag, Mo as noEchoCoordinatesOf, Mr as deleteSkipReason, Ms as CrossPrefixReadError, Mt as journaledOrphanLines, N as recordedProtectionEvidence, Na as refuseMalformedState, Nc as escapeRegExp, Ni as STATE_RESOURCES_MALFORMED, Nn as secretNamePrintingBag, No as noEchoLeavesOf, Ns as CrossPrefixScanCache, Nt as loadJournaledOrphans, O as diffSecurity, Oa as refuseMalformedResourcePropertiesForExport, Oc as redactDockerArgvValues, Oi as parameterInputsFor, On as DEFAULT_RESOURCE_WARN_AFTER_MS, Oo as maskAtCoordinates, Or as RollbackInlinePolicyWriters, Os as LockManager, Ot as withNestedStackContext, P as recordedProtectionNote, Pa as repairMalformedOrphanRecordsForReadOnly, Pc as stripControlChars, Pi as UNREADABLE_ORPHANS_CONTAINER_ROW, Pn as secretNamePrintingBags, Po as noEchoOutputsComparison, Pr as isWaitAbandonedError, Ps as applyCrossPrefixScan, Pt as makeForeignHolderScan, Qa as MULTI_REGION_RECREATE_BLOCKED_TYPES, Qc as CFN_TEMPLATE_BODY_LIMIT, Qi as malformedOrphanRowsKeptWarning, Qo as maskSecretsInText, Qr as assertFlagRoleArn, Qs as isSensitiveAttributeName, Qt as resolveReplacementOldType, R as readProtection, Ra as repairMalformedResourcePropertiesForReadOnly, Rc as synthesisStatusMessage, Ri as displayLogicalId, Rn as extractDeploymentEventError, Ro as valueAtCoordinate, Rs as splitImportedOps, S as keptForReadoption, Sa as refuseMalformedResourceEntriesForDestroy, Sc as finchSecretArgvRefusal, Si as AWS_NO_VALUE, Sn as noEchoParameterValueSeed, Sr as CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID, Ss as STATE_SOURCED_BASELINE_RULES, St as recordDisplacedSkips, T as findServiceTokenRefusals, Ta as refuseMalformedResourceEntriesForOrphan, Tc as isDockerClientEnvKey, Ti as refStateLookupFromResource, Tn as isExportAliasCollision, To as TemplateParser, Tr as CloudControlProvider, Ts as TEMPLATE_SOURCED_RULES, Tt as withNestedRevertRun, Ua as withheldAccountClause, Uc as resolveAutoAssetStorage, Ui as isReadableResourceEntry, Un as createPreDeleteFinalSnapshot, Uo as literalSplitDelimitersOf, Ur as INTRINSIC_KEYS, Us as hasReasonlessBaselineRefusal, Ut as recordAfterRollbackUpdate, Va as unreadableOrphanRecords, Vc as loadCdkJson, Vi as hasReadableResources, Vn as buildFinalSnapshotIdentifier, Vo as createUnionSecretMasker, Vs as exportNamesCarriedFrom, Vt as withStackRecords, Wa as findActionableSilentDrops, Wc as resolveCaptureObservedState, Wi as malformedDriftResourcePropertiesWarning, Wn as effectiveDeletionPolicy, Wo as logOnlyValueCount, Wr as IntrinsicFunctionResolver, Ws as hasUnverifiableParameterRefusal, Wt as demoteSupersededOrphans, Xa as findReplacedReadersOfRecreateTargets, Xc as warnDeprecatedNoPrefixCliFlag, Xi as malformedOrphanRecordsRefusalMessage, Xn as findDestructiveChanges, Xo as errorCauseChain, Xr as refuseUnreadableCdkCrossAccountRefs, Xs as shouldRetainResource, Xt as recordUnderIdIsNotOwn, Ya as hasNoCloudControlHandlers, Yc as stateBucketExistenceConfirmed, Yi as malformedLocalResourcesWarning, Yn as constructPathOf, Yo as createSecretMasker, Yr as producerLookupOver, Ys as orphansCarriedFrom, Yt as recheckFailedPlan, Za as shownType, Zc as ssmResolvedValueType, Zi as malformedOrphanRecordsWarning, Zn as formatDestructiveChange, Zo as maskSecretsInError, Zr as applyRoleArnIfSet, Zs as AssetPublisher, Zt as replacementNeverSwapped, _ as makeCanonicalizePropertiesFn, _a as refuseMalformedOutputs, _c as resolveDockerContextDirectory, _i as isImpossibleEmptyStoredAttribute, _l as absoluteAssemblyPathEscape, _n as secretSafeKeyDisplay, _o as prefetchCreateOnlyPropertyPaths, _r as TemplateNoEchoReresolver, _s as recordMaskOnlyValuesIn, _t as displacedOpClause, a as findNestedTemplateTreeDefect, aa as malformedResourcePropertiesWarning, ac as AssetModeResolver, ai as callerEnvCredentials, al as expectedOwnerParam, as as DYNAMIC_REFERENCE_TOKEN_SCAN, at as cyan, ba as refuseMalformedResourceEntries, bc as describeDockerFailure, bi as isNamelessDynamicReferenceError, bl as renderAssemblyPathEscape, bn as exportNameSecretExposure, bo as withRetry, bs as recordProvenPublicExpression, c as renderNestedTemplateTreeDefect, ca as malformedStateRefusalMessage, cc as ensureAssetStorage, cl as derivePartitionAndUrlSuffix, cn as updatePartialMessage, cs as pathCrossesDottedKey, ct as red, d as conditionInputsFrom, dc as parseBootstrapMarker, dl as processStackMessages, dn as DeploymentEventsStore, ds as recordNestedStackParameterExpressions, dt as namesAnyDeclaredParameter, ea as malformedOrphansWarning, ec as WorkGraph, ei as explicitRoleArnOrThrow, el as MIGRATE_TMP_PREFIX, en as orphanDeleteNeedsIdentity, eo as isStatefulRecreateTargetSync, es as redactSecretsForState, f as parentSuppliedValues, fa as refuseMalformedOrphanRecords, fc as readBootstrapMarkerBody, fl as defineOwnKey, fn as WITHHELD_NAME_DISPLAY, fr as CC_BROKEN_REASON, ft as reachableDivergentParameters, g as mergeNoChangeOutputs, ga as refuseMalformedOrphansForOrphan, gc as buildDockerImage, gi as getAccountInfo, gl as ownValue, gn as secretBearingStateKeyWarning, gr as wouldReturnToSdkProvider, gs as recordMaskOnlyValue, gt as NESTED_PENDING_PARENT_REASON, h as keptWholeReasonText, ha as refuseMalformedOrphansForDestroy, hc as buildDenyExternalAccessPolicy, hi as parameterTypeMayLoseSecretIdentity, hl as nullPrototypeRecord, hn as secretBearing, hr as isCustomResource, hs as provenPublicValue, ht as planOrphanAdoption, i as childTemplateLoader, ia as malformedResourceEntriesWarning, ic as rewriteTemplateAssetReferences, ii as applyCallerIdentityCredentials, il as decodeListingKey, is as recordPhysicalNameCopy, it as bold, j as noEchoExactEchoLeavesOf, ja as refuseMalformedResourcesForDestroy, jc as runDockerStreaming, ji as JSON_LISTING_HOLE_VALUE, jn as maskEventTextWithBoundBags, jo as maskedLeafCoordinatesOf, jr as deleteLeftInPlace, js as rebuildClientForBucketRegion, jt as isHandledOrphan, k as noEchoAttributeNamesOf, ka as refuseMalformedResourcePropertiesForOrphan, kc as redactedDockerCause, kn as completedReplayEntries, ko as maskReadbackAtCoordinates, kr as UNSPECIFIED_SKIP_REASON, ks as isLockInfoExpired, kt as deleteJournaledOrphans, l as templateIdentity, la as previewableOrphanRecords, lc as getBootstrapMarkerKey, ll as AssemblyReader, ln as updatePartialReason, ls as identityKeyFor, lt as yellow, m as isSecretBearingReferenceString, ma as refuseMalformedOrphans, mc as validateContainerRepoName, mi as isUnboundTemplateParameter, ml as hasPlainPrototype, mn as exportAliasCollisionScrubWarning, mr as ccBrokenReason, ms as carriesSecretMask, mt as makeSiblingClaimReader, n as IMPLICIT_DELETE_DEPENDENCIES, na as malformedOutputsWarning, nc as createAssetRedirectResolver, ni as sendableAssumeRoleCommand, nl as uploadCfnTemplate, ns as withPhysicalNameCopies, nt as formatResourceLine, o as isAbsoluteAssetPath, oa as malformedResourcesWarning, oc as BOOTSTRAP_MARKER_PREFIX, oi as envCredentialsAreAssumedRole, ol as PARTITION_TABLE, os as dynamicReferenceTokens, ot as gray, p as readRecordedConditionVerdicts, pa as refuseMalformedOrphanRecordsForDestroy, pc as validateAssetBucketName, pi as coerceParameterTypedValue, pl as hasOwnKey, pn as displayTextOrWithheld, pr as ProviderRegistry, ps as splitGetAttStringForm, pt as resourcesNamingDeclaredParameter, qc as resolveStateBucketWithDefaultAndSource, qi as malformedLocalOutputsWarning, qn as unsupportedFinalSnapshotError, qo as recordLogOnlyValue, qr as producerRegionsFromState, qs as isReadableBag, qt as planFailedOps, r as computeImplicitDeleteEdges, ra as malformedRenderedContainersWarning, rc as loadPublishableAssetManifest, ri as AWS_CREDENTIAL_ENV_KEYS, rl as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, rn as inheritProducerRegions, rt as createReadOnlyAttributeHealerFactory, s as listNestedTemplateRows, sa as malformedScrubResourceEntriesRefusalMessage, sc as assertAssetBucketRegion, sl as canonicalizeRegion, ss as isUncertifiedBaselineMaskPosition, st as green, t as DeployEngine, ta as malformedOutputsRefusalMessage, tc as buildAssetRedirectMap, ti as isIamRoleArn, tl as findLargeInlineResources, tn as findNestedStackTypeChanges, to as renderStatefulReason, tr as withCreateTokenLedger, ts as scrubResourceRecord, u as conditionFingerprint, ua as refuseDivergentRecordRegionForDestroy, uc as isCrossRegionRedirect, ul as StageLoadError, un as DeploymentEventsReader, us as inheritNestedStackParameterAssociations, ut as computeParameterTaint, va as refuseMalformedOutputsForDestroy, vc as describeDockerCapturedOutput, vi as carriesDynamicReference, vl as describeFileReadFailure, vn as carriedExportAliasExposure, vo as templateResourceTypes, vr as readsNoEchoDeleteValues, vs as recordNoEchoAttributeValues, vt as displacedPhysicalIdShown, w as deferredServiceTokenWarning, wa as refuseMalformedResourceEntriesForImportSave, wc as getDockerCmd, wi as isStalePlaceholderArnAttribute, wn as collectPublishedOutputNames, wo as DagBuilder, wr as customResourceResponseExpirationWarning, ws as STATE_SOURCED_READBACK_RULES, wt as revertedNestedRowIds, xa as refuseMalformedResourceEntriesForDeploy, xc as dockerSpawnEnvWithSensitive, xi as keepsSecretReferenceToken, xl as resolveAssemblyPath, xn as isWholeDynamicReferenceValue, xr as withPrintingSecrets, xs as wholeStringLeavesOf, xt as nestedChildStackName$1, ya as refuseMalformedResourceAttributesForOrphan, yc as describeDockerExecFailure, yi as carriesFetchableDynamicReference, yl as displayAssemblyPath, yn as exportNameNoEchoParameters, yo as describeTypeWithThrottleRetry, yr as isCustomResourceType$1, ys as recordNoEchoParameterFreshValue, yt as dropSettledNestedJournals, za as repairMalformedResourcesForReadOnly, zc as getDefaultStateBucketName, zi as hasReadableOrphans, zn as ATOMIC_FINAL_SNAPSHOT_TYPES, zo as liveMatchesUnresolvedTokenFrame, zs as acceptedCreateOnlyDropsOf, zt as destroyStackRecordsView } from "./deploy-engine-CJTG3tft.js";
|
|
6
|
+
import { t as getCdkdVersion } from "./version-D96I6uiO.js";
|
|
7
7
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
8
8
|
import { CopyObjectCommand, CreateBucketCommand, DeleteBucketCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, NotFound, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutBucketVersioningCommand, PutObjectCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
9
9
|
import { GetRoleCommand, GetUserCommand } from "@aws-sdk/client-iam";
|
|
@@ -241,7 +241,7 @@ function parsePinCcApiToken(value, previous) {
|
|
|
241
241
|
return [...previous ?? [], token];
|
|
242
242
|
}
|
|
243
243
|
const pinCcApiOption = new Option("--pin-cc-api <logicalId>", "Keep the named resource (by CloudFormation logical id) on the Cloud Control route in this deploy, declining the automatic return to the SDK Provider that a type-level sdk-coverage exemption would otherwise apply to a resource recorded as provisionedBy: cc-api. Repeatable — pass the flag once per resource. Has no effect on a resource already on the SDK path, and does not override an exemption admitted because Cloud Control cannot manage the type.").argParser(parsePinCcApiToken);
|
|
244
|
-
const recreateViaSdkProviderOption = new Option("--recreate-via-sdk-provider <logicalId>", "Destroy + recreate the named resource (by CloudFormation logical id) via cdkd's SDK Provider in this deploy, so a resource currently sticky on provisionedBy: cc-api flips back to provisionedBy: sdk. Used after a
|
|
244
|
+
const recreateViaSdkProviderOption = new Option("--recreate-via-sdk-provider <logicalId>", "Destroy + recreate the named resource (by CloudFormation logical id) via cdkd's SDK Provider in this deploy, so a resource currently sticky on provisionedBy: cc-api flips back to provisionedBy: sdk. Used after a release adds SDK coverage for a type the user originally needed CC for (e.g. Lambda LoggingConfig). Repeatable — pass the flag once per resource. Per-resource opt-in. Stateful resource types refuse unless --force-stateful-recreation is ALSO passed.").argParser(parseRecreateViaSdkProviderToken);
|
|
245
245
|
const forceStatefulRecreationOption = new Option("--force-stateful-recreation", "Confirm a data-losing destroy + recreate of a stateful resource. Required whenever a replacement target is a stateful type on the --recreate-via-cc-api / --recreate-via-sdk-provider pre-flight, with --replace, AND on the paths a plain deploy reaches with no flag: a template immutable-property change, and an in-place update the provisioning layer rejects. Stateful types are databases, filesystems, KMS keys, table / vector storage, source repositories, and more; https://cdkd.dev/cli-deploy-safety/ carries the full list. S3 buckets and log groups are the conditional cases: at pre-flight, a non-empty bucket, or a log group with retention, with log streams, or whose emptiness the probe could not settle; mid-deploy, ANY bucket or log group, because the emptiness probe cannot run there. The two probes differ on failure — the bucket fails open, the log group closed. Destroy + recreate loses ALL data in the resource — no automatic data migration. Full opt-in for CI use: --recreate-via-cc-api '<id>' --force-stateful-recreation --yes.").default(false);
|
|
246
246
|
const replaceOption = new Option("--replace", "Replace (DELETE + CREATE) a resource whose in-place update is rejected because an immutable property changed and AWS exposes no update API for it (e.g. Lambda LayerVersion content, EFS AccessPoint, ECS TaskDefinition, ApiGatewayV2 immutable fields). Without this flag such a change fails the deploy. Stateful types (RDS / DynamoDB / EFS / any S3 bucket / any Logs log group / etc.) ALSO require --force-stateful-recreation since the replacement is a data-losing DELETE + CREATE — mid-deploy neither emptiness probe can run, so both conditional types count as stateful there.").default(false);
|
|
247
247
|
const useCdkBootstrapAssetsOption = new Option("--use-cdk-bootstrap-assets", "Publish assets to the CDK bootstrap bucket/repo named by the asset manifest verbatim, skipping the cdkd asset-storage redirection even when this region is opted in via 'cdkd bootstrap'. For apps deployed via both CloudFormation and cdkd during a migration window. Per-app pin: cdk.json context.cdkd.useCdkBootstrapAssets. Also suppresses the legacy-mode 'cdk gc' notice.").default(false);
|
|
@@ -867,6 +867,11 @@ async function bootstrapCommand(options) {
|
|
|
867
867
|
Policy: JSON.stringify(bucketPolicy)
|
|
868
868
|
}));
|
|
869
869
|
logger.info("✓ Set bucket policy (deny external access)");
|
|
870
|
+
logger.debug("Setting custom-resource response lifecycle rule...");
|
|
871
|
+
const lifecycle = await applyCustomResourceResponseExpiration(stateBucketS3, bucketName, { expectedBucketOwner: accountId });
|
|
872
|
+
if (lifecycle.status === "failed" || lifecycle.status === "refused") logger.warn(customResourceResponseExpirationWarning(bucketName, lifecycle));
|
|
873
|
+
else if (lifecycle.status === "added") logger.info(safeMsg`✓ Set lifecycle rule (expire ${CUSTOM_RESOURCE_RESPONSE_PREFIX}/ responses after ${1} day)`);
|
|
874
|
+
else logger.info(safeMsg`✓ Lifecycle rule ${CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID} already present (left unchanged)`);
|
|
870
875
|
}
|
|
871
876
|
let assetStorage;
|
|
872
877
|
if (options.assets) {
|
|
@@ -921,7 +926,7 @@ async function bootstrapCommand(options) {
|
|
|
921
926
|
}
|
|
922
927
|
}
|
|
923
928
|
function createBootstrapCommand() {
|
|
924
|
-
const cmd = new Command("bootstrap").description("Bootstrap cdkd by creating the S3 state bucket plus cdkd-owned asset storage (asset bucket + container-asset ECR repo) for the region. With --destroy, tear down the region's asset storage instead
|
|
929
|
+
const cmd = new Command("bootstrap").description("Bootstrap cdkd by creating the S3 state bucket plus cdkd-owned asset storage (asset bucket + container-asset ECR repo) for the region. With --destroy, tear down the region's asset storage instead.").option("--state-bucket <bucket>", "Name of S3 bucket to create for state storage (default: cdkd-state-{accountId})").option("--force", "Create: force reconfiguration of an existing bucket. Destroy: delete the asset storage even when deployed stacks still reference it", false).option("--no-assets", "Skip cdkd asset storage (asset bucket / ECR repo / marker) — deploys keep publishing assets to the CDK bootstrap bucket/repo").option("--asset-bucket <name>", "Custom name for the cdkd asset bucket (default: cdkd-assets-{accountId}-{region}). Written into the bootstrap marker; re-bootstrapping a region with a different name is refused").option("--container-repo <name>", "Custom name for the container-asset ECR repository (default: cdkd-container-assets-{accountId}-{region}). Written into the bootstrap marker; re-bootstrapping a region with a different name is refused").option("--destroy", "Tear down the region's cdkd asset storage (empty + delete the asset bucket, force-delete the container-asset ECR repo, then delete the bootstrap marker last). The state bucket is kept unless --include-state-bucket is also passed", false).option("--include-state-bucket", "With --destroy: also delete the S3 state bucket. Refused while any stack state exists or any other region is still opted in to asset storage", false).addOption(new Option("--region <region>", "AWS region to bootstrap, or to tear down with --destroy (defaults to AWS_REGION env, else us-east-1)")).action(withErrorHandling(async (options) => {
|
|
925
930
|
if (options.destroy) {
|
|
926
931
|
if (options.assetBucket !== void 0 || options.containerRepo !== void 0) throw new CdkdError("--asset-bucket / --container-repo cannot be combined with --destroy. The teardown reads the region's asset storage names from the bootstrap marker.", "INVALID_OPTIONS");
|
|
927
932
|
if (!options.assets) throw new CdkdError("--no-assets cannot be combined with --destroy. The teardown scope is the asset storage itself; use --include-state-bucket to also delete the state bucket.", "INVALID_OPTIONS");
|
|
@@ -1506,7 +1511,7 @@ function renderRecreateTargetsErrors(validation) {
|
|
|
1506
1511
|
if (lines.length > 0) lines.push("");
|
|
1507
1512
|
lines.push(`${FLAG_UMBRELLA} named ${validation.missingFromState.length} logical id(s) the template declares but cdkd state has no record of:`);
|
|
1508
1513
|
for (const id of validation.missingFromState) lines.push(` - ${id}`);
|
|
1509
|
-
lines.push(" These are fresh CREATEs on the next deploy — recreate has nothing to destroy first. Remove the flag for these resources; the auto-route via Cloud Control
|
|
1514
|
+
lines.push(" These are fresh CREATEs on the next deploy — recreate has nothing to destroy first. Remove the flag for these resources; the auto-route via Cloud Control handles fresh deploys for silent-drop properties, and SDK Provider is the default for everything else.");
|
|
1510
1515
|
}
|
|
1511
1516
|
if (validation.ambiguousIntent.length > 0) {
|
|
1512
1517
|
if (lines.length > 0) lines.push("");
|
|
@@ -1916,18 +1921,15 @@ function refuseMalformedNestedTemplateTrees(stacks) {
|
|
|
1916
1921
|
const REQUIRE_APPROVAL_VALUES = [
|
|
1917
1922
|
"never",
|
|
1918
1923
|
"any-change",
|
|
1924
|
+
"broadening",
|
|
1919
1925
|
"destructive"
|
|
1920
1926
|
];
|
|
1921
|
-
const requireApprovalOption = new Option("--require-approval <level>", "What changes require manual approval before they are deployed: \"never\" (default), \"any-change\", or \"destructive\" (a change that replaces, deletes or orphans an existing resource
|
|
1922
|
-
function resolveRequireApproval(cliValue,
|
|
1927
|
+
const requireApprovalOption = new Option("--require-approval <level>", "What changes require manual approval before they are deployed: \"never\" (default), \"any-change\", \"broadening\" (a change that broadens IAM permissions or security-group rules), or \"destructive\" (a change that replaces, deletes or orphans an existing resource). Both \"broadening\" and \"destructive\" check nested stacks too. Without a terminal the deploy fails instead of asking, unless --yes is given. Also read from \"requireApproval\" in cdk.json.").choices(REQUIRE_APPROVAL_VALUES);
|
|
1928
|
+
function resolveRequireApproval(cliValue, cdkJson = loadCdkJson()) {
|
|
1923
1929
|
if (cliValue !== void 0) return cliValue;
|
|
1924
1930
|
const configured = cdkJson?.requireApproval;
|
|
1925
1931
|
if (configured === void 0) return "never";
|
|
1926
1932
|
if (REQUIRE_APPROVAL_VALUES.includes(configured)) return configured;
|
|
1927
|
-
if (configured === "broadening") {
|
|
1928
|
-
logger.warn(`cdk.json "requireApproval": "broadening" is ignored: cdkd does not detect security-broadening changes, so no approval is asked. Use "any-change" or "destructive" to have cdkd ask.`);
|
|
1929
|
-
return "never";
|
|
1930
|
-
}
|
|
1931
1933
|
throw new CdkdError(`cdk.json "requireApproval" must be one of ${REQUIRE_APPROVAL_VALUES.join(", ")}, got: ${displayIdent(typeof configured === "string" ? configured : JSON.stringify(configured))}`, "INVALID_REQUIRE_APPROVAL");
|
|
1932
1934
|
}
|
|
1933
1935
|
function createApprovalPrompter(options) {
|
|
@@ -1944,14 +1946,18 @@ function createApprovalPrompter(options) {
|
|
|
1944
1946
|
}
|
|
1945
1947
|
function renderApprovalRequest(request) {
|
|
1946
1948
|
const lines = [""];
|
|
1947
|
-
if (request.
|
|
1949
|
+
if (request.securityChanges !== void 0 && request.securityChanges !== "") {
|
|
1950
|
+
lines.push(request.securityChanges.replace(/\n+$/, ""));
|
|
1951
|
+
lines.push("");
|
|
1952
|
+
}
|
|
1953
|
+
if (request.destructiveChanges.length > 0 && request.level !== "broadening") {
|
|
1948
1954
|
lines.push("Destructive changes:");
|
|
1949
1955
|
for (const change of request.destructiveChanges) lines.push(` ${formatDestructiveChange(change)}`);
|
|
1950
1956
|
lines.push("");
|
|
1951
1957
|
}
|
|
1952
1958
|
const { create, update, delete: del } = request.counts;
|
|
1953
1959
|
lines.push(request.outputsOnly ? `Stack ${displayIdent(request.stackName)}: no resource changes; its Outputs change.` : `Stack ${displayIdent(request.stackName)}: ${create} to create, ${update} to update, ${del} to delete.`);
|
|
1954
|
-
lines.push(request.level === "destructive" ? `Stack includes destructive updates and "--require-approval" is set to 'destructive'.` : `Stack includes updates and "--require-approval" is set to 'any-change'.`);
|
|
1960
|
+
lines.push(request.level === "destructive" ? `Stack includes destructive updates and "--require-approval" is set to 'destructive'.` : request.level === "broadening" ? `Stack includes security-sensitive updates and "--require-approval" is set to 'broadening'.` : `Stack includes updates and "--require-approval" is set to 'any-change'.`);
|
|
1955
1961
|
return `${lines.join("\n")}\n`;
|
|
1956
1962
|
}
|
|
1957
1963
|
|
|
@@ -2370,12 +2376,13 @@ function inferCrossStackStackDeps(stacks, opts) {
|
|
|
2370
2376
|
const result = /* @__PURE__ */ new Map();
|
|
2371
2377
|
for (const stack of stacks) {
|
|
2372
2378
|
const producers = /* @__PURE__ */ new Set();
|
|
2373
|
-
|
|
2379
|
+
collectTemplateCrossStackRefs(stack.template, (kind, value, unconditional) => {
|
|
2374
2380
|
let producer;
|
|
2375
2381
|
if (kind === "ImportValue") {
|
|
2376
2382
|
if (!wantImportValue) return;
|
|
2377
2383
|
if (typeof value === "string") producer = exportOwner.get(value);
|
|
2378
2384
|
} else {
|
|
2385
|
+
if (opts?.onRoleArnReference && unconditional && value && typeof value === "object" && !Array.isArray(value) && Object.hasOwn(value, "RoleArn")) opts.onRoleArnReference(stack.stackName, value);
|
|
2379
2386
|
if (!wantGetStackOutput) return;
|
|
2380
2387
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
2381
2388
|
const sn = value["StackName"];
|
|
@@ -2388,23 +2395,45 @@ function inferCrossStackStackDeps(stacks, opts) {
|
|
|
2388
2395
|
}
|
|
2389
2396
|
return result;
|
|
2390
2397
|
}
|
|
2391
|
-
function
|
|
2398
|
+
function collectTemplateCrossStackRefs(template, onRef) {
|
|
2399
|
+
if (!template || typeof template !== "object" || Array.isArray(template)) {
|
|
2400
|
+
collectCrossStackRefs(template, onRef, false);
|
|
2401
|
+
return;
|
|
2402
|
+
}
|
|
2403
|
+
for (const [section, body] of Object.entries(template)) {
|
|
2404
|
+
if (section !== "Resources" || !body || typeof body !== "object" || Array.isArray(body)) {
|
|
2405
|
+
collectCrossStackRefs(body, onRef, false);
|
|
2406
|
+
continue;
|
|
2407
|
+
}
|
|
2408
|
+
for (const resource of Object.values(body)) {
|
|
2409
|
+
if (!resource || typeof resource !== "object" || Array.isArray(resource)) {
|
|
2410
|
+
collectCrossStackRefs(resource, onRef, false);
|
|
2411
|
+
continue;
|
|
2412
|
+
}
|
|
2413
|
+
const record = resource;
|
|
2414
|
+
const always = !Object.hasOwn(record, "Condition");
|
|
2415
|
+
for (const [key, value] of Object.entries(record)) collectCrossStackRefs(value, onRef, always && key === "Properties");
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
function collectCrossStackRefs(node, onRef, unconditional) {
|
|
2392
2420
|
if (!node || typeof node !== "object") return;
|
|
2393
2421
|
if (Array.isArray(node)) {
|
|
2394
|
-
for (const item of node) collectCrossStackRefs(item, onRef);
|
|
2422
|
+
for (const item of node) collectCrossStackRefs(item, onRef, unconditional);
|
|
2395
2423
|
return;
|
|
2396
2424
|
}
|
|
2397
2425
|
const obj = node;
|
|
2398
|
-
if ("Fn::ImportValue" in obj) onRef("ImportValue", obj["Fn::ImportValue"]);
|
|
2399
|
-
if ("Fn::GetStackOutput" in obj) onRef("GetStackOutput", obj["Fn::GetStackOutput"]);
|
|
2400
|
-
|
|
2426
|
+
if ("Fn::ImportValue" in obj) onRef("ImportValue", obj["Fn::ImportValue"], unconditional);
|
|
2427
|
+
if ("Fn::GetStackOutput" in obj) onRef("GetStackOutput", obj["Fn::GetStackOutput"], unconditional);
|
|
2428
|
+
const below = unconditional && !("Fn::If" in obj);
|
|
2429
|
+
for (const value of Object.values(obj)) collectCrossStackRefs(value, onRef, below);
|
|
2401
2430
|
}
|
|
2402
2431
|
|
|
2403
2432
|
//#endregion
|
|
2404
2433
|
//#region src/provisioning/register-providers.ts
|
|
2405
2434
|
let providerClasses;
|
|
2406
2435
|
function loadProviderClasses() {
|
|
2407
|
-
providerClasses ??= import("./provider-classes-
|
|
2436
|
+
providerClasses ??= import("./provider-classes-1EHrZ847.js");
|
|
2408
2437
|
return providerClasses;
|
|
2409
2438
|
}
|
|
2410
2439
|
function registerAllProviders(registry, classes) {
|
|
@@ -2914,7 +2943,7 @@ async function deployCommand(stacks, options) {
|
|
|
2914
2943
|
validateResourceTimeouts(options);
|
|
2915
2944
|
setResolvedResourceTimeouts(options.resourceTimeout);
|
|
2916
2945
|
applyWaitFlagEnv(options);
|
|
2917
|
-
const requireApproval = resolveRequireApproval(options.requireApproval
|
|
2946
|
+
const requireApproval = resolveRequireApproval(options.requireApproval);
|
|
2918
2947
|
const approveDeployment = requireApproval !== "never" && !options.dryRun ? createApprovalPrompter({ yes: options.yes ?? false }) : void 0;
|
|
2919
2948
|
const rawBaseRegion = rawCliRegion(options.region) ?? "us-east-1";
|
|
2920
2949
|
foldRegionOption(options);
|
|
@@ -3011,7 +3040,12 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
|
|
|
3011
3040
|
const gone = stacksNoLongerSelected(allStacks, stackPatterns, /* @__PURE__ */ new Set());
|
|
3012
3041
|
throw new Error(renderNoStackMatch(stackPatterns, allStacks) + (gone.stacks.length > 0 ? `\n${renderStacksNoLongerSelected(gone.patterns, gone.stacks)}` : ""));
|
|
3013
3042
|
}
|
|
3014
|
-
const
|
|
3043
|
+
const roleArnReferences = [];
|
|
3044
|
+
const inferredCrossStackDeps = inferCrossStackStackDeps(allStacks, { onRoleArnReference: (consumer, args) => roleArnReferences.push({
|
|
3045
|
+
consumer,
|
|
3046
|
+
args
|
|
3047
|
+
}) });
|
|
3048
|
+
const producerLookup = producerLookupOver(allStacks);
|
|
3015
3049
|
const effectiveStackDeps = (stackName, deps) => {
|
|
3016
3050
|
const union = new Set(deps);
|
|
3017
3051
|
for (const producer of inferredCrossStackDeps.get(stackName) ?? []) union.add(producer);
|
|
@@ -3053,6 +3087,13 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
|
|
|
3053
3087
|
ignoreErrors: options.ignoreErrors === true
|
|
3054
3088
|
});
|
|
3055
3089
|
refuseMalformedNestedTemplateTrees(targetStacks);
|
|
3090
|
+
if (roleArnReferences.length > 0) {
|
|
3091
|
+
const stackByName = new Map(allStacks.map((s) => [s.stackName, s]));
|
|
3092
|
+
refuseUnreadableCdkCrossAccountRefs(roleArnReferences, new Set(targetStacks.map((s) => s.stackName)), (name) => ({
|
|
3093
|
+
region: stackByName.get(name)?.region ?? namedCliRegion(options.region),
|
|
3094
|
+
account: stackByName.get(name)?.account
|
|
3095
|
+
}), producerLookup);
|
|
3096
|
+
}
|
|
3056
3097
|
const baseRegion = namedCliRegion(options.region) ?? "us-east-1";
|
|
3057
3098
|
const crossPrefixGuard = new CrossPrefixGuard(preflightStateBackend, { readOnly: options.dryRun === true });
|
|
3058
3099
|
await synthesizer.expandMacrosForStacks(targetStacks, synthOptions);
|
|
@@ -3278,6 +3319,8 @@ Force-quit: stack locks may not be released. If the next run reports a lock, run
|
|
|
3278
3319
|
finalSnapshotClients: stackAwsClients,
|
|
3279
3320
|
...options.strictGetatt && { strictGetAtt: true },
|
|
3280
3321
|
...options.cfnFallback === false && { cfnFallback: false },
|
|
3322
|
+
producerLookup,
|
|
3323
|
+
...stackInfo.account && { consumerAccount: stackInfo.account },
|
|
3281
3324
|
captureObservedState: resolveCaptureObservedState(options.captureObservedState),
|
|
3282
3325
|
...options.resourceWarnAfter?.globalMs !== void 0 && { resourceWarnAfterMs: options.resourceWarnAfter.globalMs },
|
|
3283
3326
|
...options.resourceTimeout?.globalMs !== void 0 && { resourceTimeoutMs: options.resourceTimeout.globalMs },
|
|
@@ -4401,7 +4444,7 @@ function deployRefusesPropertiesReason(logicalIds) {
|
|
|
4401
4444
|
return `${logicalIds.length} resource record(s) hold a 'properties' map that cannot be read. This preview repaired them to empty; 'cdkd deploy' refuses the record instead, so the deploy this previews will not start.`;
|
|
4402
4445
|
}
|
|
4403
4446
|
function nestedStackTypeChangeReason(tc) {
|
|
4404
|
-
return `${displayIdent(tc.logicalId)}: Type changes from ${displayIdent(tc.currentType)} to ${displayIdent(tc.desiredType)}. cdkd does not replace a resource into or out of ${NESTED_STACK_RESOURCE_TYPE}
|
|
4447
|
+
return `${displayIdent(tc.logicalId)}: Type changes from ${displayIdent(tc.currentType)} to ${displayIdent(tc.desiredType)}. cdkd does not replace a resource into or out of ${NESTED_STACK_RESOURCE_TYPE}; give the new resource a different logical id, or remove it in one deploy and add its replacement in the next.`;
|
|
4405
4448
|
}
|
|
4406
4449
|
function findUnwrittenCreateOnlyRefusals(changes, stateResources) {
|
|
4407
4450
|
const reasons = [];
|
|
@@ -4657,10 +4700,14 @@ function maskOutputChangeForDisplay(change, mask, nameCorpus) {
|
|
|
4657
4700
|
return changed ? shown : change;
|
|
4658
4701
|
}
|
|
4659
4702
|
async function computeStackDiff(currentState, template, region, stackName, stateBackend, diffCalculator, options = {}) {
|
|
4660
|
-
const { parameters, canonicalizeProperties, cfnFallback, inheritSecretBearingTemplate, inheritedSecrets, inheritedDerivedNames, attributeHealer, parentUnresolvedParameters, inheritedNoEchoParameters, inheritedNoEchoParametersAnyVerdict } = options;
|
|
4703
|
+
const { parameters, canonicalizeProperties, cfnFallback, producerLookup, consumerAccount, inheritSecretBearingTemplate, inheritedSecrets, inheritedDerivedNames, attributeHealer, parentUnresolvedParameters, inheritedNoEchoParameters, inheritedNoEchoParametersAnyVerdict } = options;
|
|
4661
4704
|
const noEchoParametersOf = (t) => /* @__PURE__ */ new Set([...noEchoParameterNamesOf(t), ...inheritedNoEchoParameters ?? []]);
|
|
4662
4705
|
const inheritedForResolver = inheritedSecrets !== void 0 && hasMaskableValues(inheritedSecrets) ? inheritedSecrets : void 0;
|
|
4663
|
-
const intrinsicResolver = new IntrinsicFunctionResolver(region, {
|
|
4706
|
+
const intrinsicResolver = new IntrinsicFunctionResolver(region, {
|
|
4707
|
+
cfnFallback: cfnFallback ?? true,
|
|
4708
|
+
...producerLookup && { producerLookup },
|
|
4709
|
+
...consumerAccount && { consumerAccount }
|
|
4710
|
+
});
|
|
4664
4711
|
const outputsDigestSource = structuredClone({
|
|
4665
4712
|
...template,
|
|
4666
4713
|
Resources: {}
|
|
@@ -4777,8 +4824,8 @@ async function computeStackDiff(currentState, template, region, stackName, state
|
|
|
4777
4824
|
const diffSecrets = /* @__PURE__ */ new Map();
|
|
4778
4825
|
const splitPieces = /* @__PURE__ */ new Map();
|
|
4779
4826
|
const derivedNames = /* @__PURE__ */ new Map();
|
|
4780
|
-
const splitDelimiters = literalSplitDelimitersOf(template, new Set(Object.entries(template.Parameters ?? {}).filter(([, definition]) => definition
|
|
4781
|
-
for (const [name, definition] of Object.entries(template.Parameters ?? {})) if (definition
|
|
4827
|
+
const splitDelimiters = literalSplitDelimitersOf(template, new Set(Object.entries(template.Parameters ?? {}).filter(([, definition]) => declaresNoEcho(definition)).map(([name]) => name)));
|
|
4828
|
+
for (const [name, definition] of Object.entries(template.Parameters ?? {})) if (declaresNoEcho(definition) && mergedParameters !== void 0 && Object.prototype.hasOwnProperty.call(mergedParameters, name) && !isWholeDynamicReferenceValue(mergedParameters[name])) {
|
|
4782
4829
|
recordLogOnlyParameterValue(diffSecrets, mergedParameters[name]);
|
|
4783
4830
|
recordLogOnlyParameterValue(splitPieces, mergedParameters[name], splitDelimiters);
|
|
4784
4831
|
}
|
|
@@ -4992,6 +5039,13 @@ async function computeStackDiff(currentState, template, region, stackName, state
|
|
|
4992
5039
|
}
|
|
4993
5040
|
return {
|
|
4994
5041
|
changes: shownChanges,
|
|
5042
|
+
securityDiff: () => diffSecurity({
|
|
5043
|
+
stackName,
|
|
5044
|
+
changes: changes.values(),
|
|
5045
|
+
records: stateForDiff.resources,
|
|
5046
|
+
template: effectiveTemplate,
|
|
5047
|
+
secretMask: () => printing.mask
|
|
5048
|
+
}),
|
|
4995
5049
|
outputChanges: shownOutputChanges,
|
|
4996
5050
|
adoptedOrphans,
|
|
4997
5051
|
adoptedRecords,
|
|
@@ -5175,10 +5229,14 @@ function noEchoFedChildParameters(parentStackRow, parentNoEchoParameters, parent
|
|
|
5175
5229
|
})) fed.add(name);
|
|
5176
5230
|
return fed;
|
|
5177
5231
|
}
|
|
5178
|
-
async function resolveChildStackParameters(parentStackRow, parentTemplate, parentState, region, parentStackName, stateBackend, parentParameters, parentConditions, cfnFallback, printingSecrets, attributeHealer, unresolvedKeys, trust, derivedNameSink) {
|
|
5232
|
+
async function resolveChildStackParameters(parentStackRow, parentTemplate, parentState, region, parentStackName, stateBackend, parentParameters, parentConditions, cfnFallback, printingSecrets, attributeHealer, unresolvedKeys, trust, derivedNameSink, producerLookup, consumerAccount) {
|
|
5179
5233
|
const rawParams = parentStackRow.Properties?.["Parameters"];
|
|
5180
5234
|
if (!rawParams || typeof rawParams !== "object" || Array.isArray(rawParams)) return {};
|
|
5181
|
-
const resolver = new IntrinsicFunctionResolver(region, {
|
|
5235
|
+
const resolver = new IntrinsicFunctionResolver(region, {
|
|
5236
|
+
cfnFallback: cfnFallback ?? true,
|
|
5237
|
+
...producerLookup && { producerLookup },
|
|
5238
|
+
...consumerAccount && { consumerAccount }
|
|
5239
|
+
});
|
|
5182
5240
|
const resolved = {};
|
|
5183
5241
|
for (const [name, value] of Object.entries(rawParams)) {
|
|
5184
5242
|
if (trust === void 0 || !rowValueTrusted(value, parentState, parentConditions, trust)) unresolvedKeys?.add(name);
|
|
@@ -5214,7 +5272,7 @@ function recordedTemplateResources(template, state) {
|
|
|
5214
5272
|
return recorded;
|
|
5215
5273
|
}
|
|
5216
5274
|
async function buildDiffTree(args) {
|
|
5217
|
-
const { stackName, displayName, region, template, nestedTemplates, recursive, stateBackend, diffCalculator, parentHasSecretReference, parameters, parentUnresolvedParameters, canonicalizeProperties, assetRedirect, cfnFallback, previewOrphanAdoption, attributeHealerFor, ancestorTemplatePaths, isNestedChild, inheritedSecrets, inheritedDerivedNames, inheritedNoEchoParameters, inheritedNoEchoParametersAnyVerdict, refusalRecovery } = args;
|
|
5275
|
+
const { stackName, displayName, region, template, nestedTemplates, recursive, stateBackend, diffCalculator, parentHasSecretReference, parameters, parentUnresolvedParameters, canonicalizeProperties, assetRedirect, cfnFallback, producerLookup, consumerAccount, previewOrphanAdoption, attributeHealerFor, ancestorTemplatePaths, isNestedChild, inheritedSecrets, inheritedDerivedNames, inheritedNoEchoParameters, inheritedNoEchoParametersAnyVerdict, refusalRecovery } = args;
|
|
5218
5276
|
const attributeHealer = attributeHealerFor?.(stackName, region);
|
|
5219
5277
|
const { state, unreadable, unreadableContainers, deployRefusals } = await loadStateOrEmpty(stackName, region, stateBackend, refusalRecovery);
|
|
5220
5278
|
const createOnlyPrefetch = prefetchCreateOnlyPropertyPaths(templateResourceTypes(recordedTemplateResources(template, state)));
|
|
@@ -5226,6 +5284,8 @@ async function buildDiffTree(args) {
|
|
|
5226
5284
|
...parentUnresolvedParameters && { parentUnresolvedParameters },
|
|
5227
5285
|
...canonicalizeProperties && { canonicalizeProperties },
|
|
5228
5286
|
...cfnFallback !== void 0 && { cfnFallback },
|
|
5287
|
+
...producerLookup && { producerLookup },
|
|
5288
|
+
...consumerAccount && { consumerAccount },
|
|
5229
5289
|
...previewOrphanAdoption && { previewOrphanAdoption },
|
|
5230
5290
|
...inheritedSecrets && { inheritedSecrets },
|
|
5231
5291
|
...inheritedDerivedNames && { inheritedDerivedNames },
|
|
@@ -5240,7 +5300,7 @@ async function buildDiffTree(args) {
|
|
|
5240
5300
|
} finally {
|
|
5241
5301
|
createOnlyPrefetch.cancel();
|
|
5242
5302
|
}
|
|
5243
|
-
const { changes, outputChanges, adoptedOrphans, adoptedRecords, blocking, unreadableOrphans, deployRefusals: adoptedDeployRefusals, effectiveTemplate, printingSecrets, derivedNames: nodeDerivedNames, secretNamedRecords: nodeStateNames, resolvedParameters, conditions, knownConditions, trust } = stackDiff;
|
|
5303
|
+
const { changes, securityDiff, outputChanges, adoptedOrphans, adoptedRecords, blocking, unreadableOrphans, deployRefusals: adoptedDeployRefusals, effectiveTemplate, printingSecrets, derivedNames: nodeDerivedNames, secretNamedRecords: nodeStateNames, resolvedParameters, conditions, knownConditions, trust } = stackDiff;
|
|
5244
5304
|
const stateAfterAdoption = Object.keys(adoptedRecords).length > 0 ? {
|
|
5245
5305
|
...state,
|
|
5246
5306
|
resources: {
|
|
@@ -5253,6 +5313,7 @@ async function buildDiffTree(args) {
|
|
|
5253
5313
|
displayName,
|
|
5254
5314
|
region,
|
|
5255
5315
|
changes,
|
|
5316
|
+
securityDiff,
|
|
5256
5317
|
ccApiRoutes: collectCcApiRoutes(effectiveTemplate, stateAfterAdoption, changes),
|
|
5257
5318
|
outputChanges,
|
|
5258
5319
|
adoptedOrphans,
|
|
@@ -5290,7 +5351,7 @@ async function buildDiffTree(args) {
|
|
|
5290
5351
|
...inheritedNoEchoParametersAnyVerdict ?? []
|
|
5291
5352
|
]), void 0, stateAfterAdoption.resources);
|
|
5292
5353
|
const rowDerivedNames = /* @__PURE__ */ new Map();
|
|
5293
|
-
const childParameters = await resolveChildStackParameters(resource, effectiveTemplate, stateAfterAdoption, region, stackName, stateBackend, resolvedParameters, conditions, cfnFallback, printingSecrets, attributeHealer, childUnresolvedParameters, trust, rowDerivedNames);
|
|
5354
|
+
const childParameters = await resolveChildStackParameters(resource, effectiveTemplate, stateAfterAdoption, region, stackName, stateBackend, resolvedParameters, conditions, cfnFallback, printingSecrets, attributeHealer, childUnresolvedParameters, trust, rowDerivedNames, producerLookup, consumerAccount);
|
|
5294
5355
|
const childDerivedNames = diffPrintingSecrets([
|
|
5295
5356
|
inheritedDerivedNames,
|
|
5296
5357
|
rowDerivedNames,
|
|
@@ -5310,6 +5371,8 @@ async function buildDiffTree(args) {
|
|
|
5310
5371
|
...canonicalizeProperties && { canonicalizeProperties },
|
|
5311
5372
|
...assetRedirect && { assetRedirect },
|
|
5312
5373
|
...cfnFallback !== void 0 && { cfnFallback },
|
|
5374
|
+
...producerLookup && { producerLookup },
|
|
5375
|
+
...consumerAccount && { consumerAccount },
|
|
5313
5376
|
...previewOrphanAdoption && { previewOrphanAdoption },
|
|
5314
5377
|
...attributeHealerFor && { attributeHealerFor },
|
|
5315
5378
|
ancestorTemplatePaths: childAncestorTemplatePaths,
|
|
@@ -5337,7 +5400,7 @@ async function buildDiffTree(args) {
|
|
|
5337
5400
|
async function buildDeletedSubtree(stackName, region, stateBackend, diffCalculator, parentHasSecretReference, inheritedSecrets, refusalRecovery, inheritedDerivedNames) {
|
|
5338
5401
|
const { state, unreadable, unreadableContainers } = await loadStateOrEmpty(stackName, region, stateBackend, refusalRecovery);
|
|
5339
5402
|
const derivedNames = diffPrintingSecrets([inheritedDerivedNames, stateDerivedNames(state.resources ?? {})]);
|
|
5340
|
-
const { changes, outputChanges } = await computeStackDiff(state, EMPTY_TEMPLATE, region, stackName, stateBackend, diffCalculator, {
|
|
5403
|
+
const { changes, securityDiff, outputChanges } = await computeStackDiff(state, EMPTY_TEMPLATE, region, stackName, stateBackend, diffCalculator, {
|
|
5341
5404
|
inheritSecretBearingTemplate: parentHasSecretReference,
|
|
5342
5405
|
inheritedSecrets,
|
|
5343
5406
|
...hasMaskableValues(derivedNames) && { inheritedDerivedNames: derivedNames },
|
|
@@ -5348,6 +5411,7 @@ async function buildDeletedSubtree(stackName, region, stateBackend, diffCalculat
|
|
|
5348
5411
|
displayName: stackName,
|
|
5349
5412
|
region,
|
|
5350
5413
|
changes,
|
|
5414
|
+
securityDiff,
|
|
5351
5415
|
ccApiRoutes: /* @__PURE__ */ new Map(),
|
|
5352
5416
|
adoptedOrphans: [],
|
|
5353
5417
|
blocking: [],
|
|
@@ -5475,7 +5539,7 @@ function diffTreeToJson(node) {
|
|
|
5475
5539
|
children: node.children.map(diffTreeToJson)
|
|
5476
5540
|
};
|
|
5477
5541
|
}
|
|
5478
|
-
function isIntrinsic(value) {
|
|
5542
|
+
function isIntrinsic$1(value) {
|
|
5479
5543
|
if (value === null || value === void 0 || typeof value !== "object" || Array.isArray(value)) return false;
|
|
5480
5544
|
const keys = Object.keys(value);
|
|
5481
5545
|
return keys.length === 1 && INTRINSIC_KEYS.has(keys[0]);
|
|
@@ -5483,12 +5547,12 @@ function isIntrinsic(value) {
|
|
|
5483
5547
|
function stripUnchangedValues(value, other) {
|
|
5484
5548
|
if (value === null || value === void 0 || typeof value !== "object") return value;
|
|
5485
5549
|
if (Array.isArray(value)) return value;
|
|
5486
|
-
if (isIntrinsic(value)) return void 0;
|
|
5487
|
-
if (isIntrinsic(other)) return void 0;
|
|
5550
|
+
if (isIntrinsic$1(value)) return void 0;
|
|
5551
|
+
if (isIntrinsic$1(other)) return void 0;
|
|
5488
5552
|
return value;
|
|
5489
5553
|
}
|
|
5490
5554
|
function isPlainNonIntrinsicObject(value) {
|
|
5491
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && !isIntrinsic(value);
|
|
5555
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && !isIntrinsic$1(value);
|
|
5492
5556
|
}
|
|
5493
5557
|
function stripUnchangedValuePair(oldValue, newValue) {
|
|
5494
5558
|
if (!isPlainNonIntrinsicObject(oldValue) || !isPlainNonIntrinsicObject(newValue)) return [stripUnchangedValues(oldValue, newValue), stripUnchangedValues(newValue, oldValue)];
|
|
@@ -5498,7 +5562,7 @@ function stripUnchangedValuePair(oldValue, newValue) {
|
|
|
5498
5562
|
for (const key of keys) {
|
|
5499
5563
|
const o = oldValue[key];
|
|
5500
5564
|
const n = newValue[key];
|
|
5501
|
-
if (isIntrinsic(o) || isIntrinsic(n)) continue;
|
|
5565
|
+
if (isIntrinsic$1(o) || isIntrinsic$1(n)) continue;
|
|
5502
5566
|
if (JSON.stringify(o) === JSON.stringify(n)) continue;
|
|
5503
5567
|
if (isPlainNonIntrinsicObject(o) && isPlainNonIntrinsicObject(n)) {
|
|
5504
5568
|
const [fo, fn] = stripUnchangedValuePair(o, n);
|
|
@@ -5513,7 +5577,7 @@ function stripUnchangedValuePair(oldValue, newValue) {
|
|
|
5513
5577
|
return [oldResult, newResult];
|
|
5514
5578
|
}
|
|
5515
5579
|
function renderDiffValue(own, filtered, indent, isNewSide) {
|
|
5516
|
-
if (isIntrinsic(own)) {
|
|
5580
|
+
if (isIntrinsic$1(own)) {
|
|
5517
5581
|
const suffix = isNewSide ? " (known after deploy)" : "";
|
|
5518
5582
|
return `${JSON.stringify(own)}${suffix}`;
|
|
5519
5583
|
}
|
|
@@ -5644,9 +5708,20 @@ function renderDiffTree(node, isRoot, logFn) {
|
|
|
5644
5708
|
|
|
5645
5709
|
//#endregion
|
|
5646
5710
|
//#region src/cli/commands/diff.ts
|
|
5711
|
+
function treeNodes(node) {
|
|
5712
|
+
return [node, ...node.children.flatMap(treeNodes)];
|
|
5713
|
+
}
|
|
5714
|
+
function securityDiffOf(node) {
|
|
5715
|
+
if (node.securityDiff === void 0) throw new CdkdError(safeMsg`No security diff for stack ${node.displayName}; its security changes cannot be decided.`, "SECURITY_DIFF_FAILED");
|
|
5716
|
+
return node.securityDiff();
|
|
5717
|
+
}
|
|
5718
|
+
function logTable(rendered, log) {
|
|
5719
|
+
for (const row of rendered.replace(/\n+$/, "").split("\n")) log(safeMsg`${row}`);
|
|
5720
|
+
}
|
|
5647
5721
|
const DIFF_FAIL_ON_VALUES = [
|
|
5648
5722
|
"never",
|
|
5649
5723
|
"any-change",
|
|
5724
|
+
"broadening",
|
|
5650
5725
|
"destructive"
|
|
5651
5726
|
];
|
|
5652
5727
|
function parseFailOn(value, previous) {
|
|
@@ -5677,6 +5752,8 @@ var DeployRefusalPreviewError = class DeployRefusalPreviewError extends CdkdErro
|
|
|
5677
5752
|
};
|
|
5678
5753
|
async function diffCommand(stacks, options) {
|
|
5679
5754
|
const failOn = resolveFailOn(options);
|
|
5755
|
+
const securityOnly = options.securityOnly === true;
|
|
5756
|
+
if (securityOnly && options.json === true) throw new CdkdError("--security-only cannot be used with --json: it prints the security tables only", "INCOMPATIBLE_OPTIONS");
|
|
5680
5757
|
const providerClasses = await loadProviderClasses();
|
|
5681
5758
|
const logger = getLogger();
|
|
5682
5759
|
if (options.json) logger.setLevel("warn");
|
|
@@ -5803,7 +5880,7 @@ async function diffCommand(stacks, options) {
|
|
|
5803
5880
|
}).provider,
|
|
5804
5881
|
inRegion: (healRegion, fn) => runWithStackAwsClients(stackRegionScope(healRegion).clients, fn)
|
|
5805
5882
|
});
|
|
5806
|
-
const recursive = (options.recursive ?? false) || failOn === "destructive";
|
|
5883
|
+
const recursive = (options.recursive ?? false) || failOn === "destructive" || failOn === "broadening" || securityOnly;
|
|
5807
5884
|
const resolveAssetRedirect = createAssetRedirectResolver({
|
|
5808
5885
|
stateBackend,
|
|
5809
5886
|
stsRegion: region,
|
|
@@ -5812,6 +5889,7 @@ async function diffCommand(stacks, options) {
|
|
|
5812
5889
|
suppressLegacyNotice: true
|
|
5813
5890
|
});
|
|
5814
5891
|
const trees = [];
|
|
5892
|
+
const producerLookup = producerLookupOver(allStacks);
|
|
5815
5893
|
for (const stackInfo of targetStacks) {
|
|
5816
5894
|
logger.info(`\nCalculating diff for stack: ${stackInfo.stackName}`);
|
|
5817
5895
|
const stackRegion = stackInfo.region || region;
|
|
@@ -5832,13 +5910,41 @@ async function diffCommand(stacks, options) {
|
|
|
5832
5910
|
canonicalizeProperties,
|
|
5833
5911
|
...assetRedirect && { assetRedirect },
|
|
5834
5912
|
...options.cfnFallback === false && { cfnFallback: false },
|
|
5913
|
+
producerLookup,
|
|
5914
|
+
...stackInfo.account && { consumerAccount: stackInfo.account },
|
|
5835
5915
|
previewOrphanAdoption,
|
|
5836
5916
|
attributeHealerFor,
|
|
5837
5917
|
isNestedChild: false,
|
|
5838
5918
|
refusalRecovery
|
|
5839
5919
|
}));
|
|
5840
5920
|
}
|
|
5841
|
-
|
|
5921
|
+
let securityDifferences = 0;
|
|
5922
|
+
let securityBroadening = false;
|
|
5923
|
+
if (securityOnly) for (const tree of trees) {
|
|
5924
|
+
const nodes = treeNodes(tree);
|
|
5925
|
+
for (const node of nodes) for (const reason of node.blocking) logger.error(safeMsg`Blocking (${node.displayName}): ${reason}`);
|
|
5926
|
+
const results = [];
|
|
5927
|
+
for (const node of nodes) results.push({
|
|
5928
|
+
node,
|
|
5929
|
+
security: await securityDiffOf(node)
|
|
5930
|
+
});
|
|
5931
|
+
if (!results.some(({ security }) => security.broadening)) {
|
|
5932
|
+
logger.info(safeMsg`\n✓ No security-broadening changes for stack ${tree.displayName}`);
|
|
5933
|
+
continue;
|
|
5934
|
+
}
|
|
5935
|
+
securityBroadening = true;
|
|
5936
|
+
securityDifferences += results.filter(({ security }) => security.rendered !== "").length;
|
|
5937
|
+
logger.warn("This deployment will make potentially sensitive changes according to your current security approval level.\nPlease confirm you intend to make the following modifications:\n");
|
|
5938
|
+
for (const { node, security } of results) {
|
|
5939
|
+
logger.info(safeMsg`Stack ${node.displayName}`);
|
|
5940
|
+
if (security.rendered === "") {
|
|
5941
|
+
logger.info("There were no security-related changes (limitations: https://github.com/aws/aws-cdk/issues/1299)");
|
|
5942
|
+
continue;
|
|
5943
|
+
}
|
|
5944
|
+
logTable(security.rendered, (row) => logger.info(row));
|
|
5945
|
+
}
|
|
5946
|
+
}
|
|
5947
|
+
else if (options.json) process.stdout.write(`${stringifyJsonPayload(trees.map(diffTreeToJson))}\n`);
|
|
5842
5948
|
else for (const tree of trees) {
|
|
5843
5949
|
if (!treeIsWorthRendering(tree)) {
|
|
5844
5950
|
logger.info(`\n✓ No changes detected for stack ${tree.stackName}`);
|
|
@@ -5848,7 +5954,7 @@ async function diffCommand(stacks, options) {
|
|
|
5848
5954
|
}
|
|
5849
5955
|
const blockingCount = trees.reduce((n, tree) => n + countBlocking(tree), 0);
|
|
5850
5956
|
if (blockingCount > 0) throw new DeployRefusalPreviewError(blockingCount);
|
|
5851
|
-
if (failOn === "any-change" && trees.some(treeHasChanges)) throw new DiffDetectedError();
|
|
5957
|
+
if (failOn === "any-change" && (securityOnly ? securityDifferences > 0 : trees.some(treeHasChanges))) throw new DiffDetectedError();
|
|
5852
5958
|
if (failOn === "destructive") {
|
|
5853
5959
|
const destructive = trees.flatMap(treeDestructiveChanges);
|
|
5854
5960
|
if (destructive.length > 0) {
|
|
@@ -5857,13 +5963,26 @@ async function diffCommand(stacks, options) {
|
|
|
5857
5963
|
throw new DiffDetectedError();
|
|
5858
5964
|
}
|
|
5859
5965
|
}
|
|
5966
|
+
if (failOn === "broadening" && securityOnly) {
|
|
5967
|
+
if (securityBroadening) throw new DiffDetectedError();
|
|
5968
|
+
} else if (failOn === "broadening") {
|
|
5969
|
+
let broadening = 0;
|
|
5970
|
+
for (const node of trees.flatMap(treeNodes)) {
|
|
5971
|
+
const security = await securityDiffOf(node);
|
|
5972
|
+
if (!security.broadening) continue;
|
|
5973
|
+
broadening++;
|
|
5974
|
+
logger.error(safeMsg`\n❌ Stack ${node.displayName} broadens permissions (--fail-on=broadening):`);
|
|
5975
|
+
logTable(security.rendered, (row) => logger.error(row));
|
|
5976
|
+
}
|
|
5977
|
+
if (broadening > 0) throw new DiffDetectedError();
|
|
5978
|
+
}
|
|
5860
5979
|
} finally {
|
|
5861
5980
|
for (const { clients } of stackRegionScopes.values()) clients.destroy();
|
|
5862
5981
|
awsClients.destroy();
|
|
5863
5982
|
}
|
|
5864
5983
|
}
|
|
5865
5984
|
function createDiffCommand() {
|
|
5866
|
-
const cmd = new Command("diff").description("Show difference between current state and desired state").argument("[stacks...]", "Stack name(s) to diff. Accepts CDK display paths (e.g. 'MyStage/Api') with wildcards ('MyStage/*', '**'), or exact physical CloudFormation names (e.g. 'MyStage-Api').").option("--all", "Diff every top-level stack (top-level only; Stage stacks: '**')", false).option("--recursive", "Recurse into each AWS::CloudFormation::Stack row and diff every nested-stack child against its own deployed state (DFS order). Default is non-recursive, matching cdk diff.", false).option("--fail", "Exit with code 1 when any change is detected (matches cdk diff --fail). Alias for --fail-on=any-change.").option("--no-fail", "Never exit with code 1 for a change. Alias for --fail-on=never.").addOption(new Option("--fail-on <kind>", "Exit with code 1 when the diff contains the given kind of change: \"any-change\" fails on any difference, \"destructive\" only on changes that replace, delete or orphan a resource, \"never\" does not fail (default). \"destructive\" always
|
|
5985
|
+
const cmd = new Command("diff").description("Show difference between current state and desired state").argument("[stacks...]", "Stack name(s) to diff. Accepts CDK display paths (e.g. 'MyStage/Api') with wildcards ('MyStage/*', '**'), or exact physical CloudFormation names (e.g. 'MyStage-Api').").option("--all", "Diff every top-level stack (top-level only; Stage stacks: '**')", false).option("--recursive", "Recurse into each AWS::CloudFormation::Stack row and diff every nested-stack child against its own deployed state (DFS order). Default is non-recursive, matching cdk diff.", false).option("--fail", "Exit with code 1 when any change is detected (matches cdk diff --fail). Alias for --fail-on=any-change.").option("--no-fail", "Never exit with code 1 for a change. Alias for --fail-on=never.").addOption(new Option("--fail-on <kind>", "Exit with code 1 when the diff contains the given kind of change: \"any-change\" fails on any difference, \"broadening\" only on changes that broaden IAM permissions or security-group rules, \"destructive\" only on changes that replace, delete or orphan a resource, \"never\" does not fail (default). \"broadening\" and \"destructive\" always check nested stacks (as --recursive); \"any-change\" does with --recursive. Cannot be used with --fail / --no-fail.").choices(DIFF_FAIL_ON_VALUES).argParser(parseFailOn)).option("--security-only", "Only print the security changes (IAM and security-group) of each stack whose changes broaden permissions, and count only those stacks as differences for --fail-on (matches cdk diff --security-only). Checks nested stacks too. Cannot be used with --json.").option("--json", "Output the diff as JSON (nested tree shape when combined with --recursive)", false).addOption(useCdkBootstrapAssetsOption).addOption(noCfnFallbackOption).action(withErrorHandling(diffCommand));
|
|
5867
5986
|
[
|
|
5868
5987
|
...commonOptions,
|
|
5869
5988
|
...appOptions,
|
|
@@ -8782,9 +8901,10 @@ function stripWalk(value) {
|
|
|
8782
8901
|
|
|
8783
8902
|
//#endregion
|
|
8784
8903
|
//#region src/cli/commands/refused-baseline-remedy.ts
|
|
8904
|
+
const ACCEPT_REFUSED_REMEDY = "Once the deployed template no longer reads a parameter at this resource, cdkd state refresh-observed '<stack>' --accept-refused '<logicalId>' --template '<file>' records a baseline on your assertion that AWS holds no secret the template does not spell as a dynamic reference.";
|
|
8785
8905
|
function refusedBaselineRemedy(record) {
|
|
8786
|
-
if (hasUnverifiableParameterRefusal(record)) return "Deploying a change does NOT clear this refusal: the resource reads a template parameter whose deployed value cdkd could not prove, so only a deploy that replaces the resource, or a re-import while a CloudFormation stack can prove that value, restores a baseline.";
|
|
8787
|
-
if (hasReasonlessBaselineRefusal(record)) return "This refusal was recorded without a reason this cdkd recognizes: a deploy that actually CHANGES this resource restores a baseline unless the resource reads a template parameter, and then only a deploy that replaces the resource, or a re-import while a CloudFormation stack can prove the parameter's deployed value, does.";
|
|
8906
|
+
if (hasUnverifiableParameterRefusal(record)) return "Deploying a change does NOT clear this refusal: the resource reads a template parameter whose deployed value cdkd could not prove, so only a deploy that replaces the resource, or a re-import while a CloudFormation stack can prove that value, restores a baseline. " + ACCEPT_REFUSED_REMEDY;
|
|
8907
|
+
if (hasReasonlessBaselineRefusal(record)) return "This refusal was recorded without a reason this cdkd recognizes: a deploy that actually CHANGES this resource restores a baseline unless the resource reads a template parameter, and then only a deploy that replaces the resource, or a re-import while a CloudFormation stack can prove the parameter's deployed value, does. " + ACCEPT_REFUSED_REMEDY;
|
|
8788
8908
|
}
|
|
8789
8909
|
|
|
8790
8910
|
//#endregion
|
|
@@ -9953,7 +10073,7 @@ async function runAccept(reports, stateBackend, stateConfig, awsClients, options
|
|
|
9953
10073
|
setAtPath(newBaseline, change.path, change.awsValue);
|
|
9954
10074
|
accepted.push(change);
|
|
9955
10075
|
}
|
|
9956
|
-
const redactedBaseline = redactSecretsForState(newBaseline, outcome.secrets, existing.properties ?? {}, hasObserved ? STATE_SOURCED_BASELINE_RULES : STATE_SOURCED_READBACK_RULES);
|
|
10076
|
+
const redactedBaseline = withPhysicalNameCopies(outcome.secrets, otherPhysicalIds(report.state.resources, outcome.logicalId), () => redactSecretsForState(newBaseline, outcome.secrets, existing.properties ?? {}, hasObserved ? STATE_SOURCED_BASELINE_RULES : STATE_SOURCED_READBACK_RULES));
|
|
9957
10077
|
let recordedChanges = 0;
|
|
9958
10078
|
for (const change of accepted) {
|
|
9959
10079
|
if (deepEqualUnordered(getAtPath(redactedBaseline, change.path), change.awsValue)) {
|
|
@@ -10446,6 +10566,7 @@ async function runRevert(reports, regionScope, stateBackend, stateConfig, awsCli
|
|
|
10446
10566
|
provisionedBy: stateResource.provisionedBy
|
|
10447
10567
|
}).provider;
|
|
10448
10568
|
const secrets = /* @__PURE__ */ new Map();
|
|
10569
|
+
for (const id of otherPhysicalIds(report.state.resources, outcome.logicalId)) recordPhysicalNameCopy(secrets, id);
|
|
10449
10570
|
const revertBaseline = stateResource.observedProperties ?? stateResource.properties ?? {};
|
|
10450
10571
|
const unresolvedTokens = /* @__PURE__ */ new Set();
|
|
10451
10572
|
const noteUnresolved = (tokens) => {
|
|
@@ -10750,7 +10871,7 @@ function printRevertPlan(reports, out, recovery) {
|
|
|
10750
10871
|
...accountArgs(recovery)
|
|
10751
10872
|
]) : void 0;
|
|
10752
10873
|
const refreshAccountNote = refresh === void 0 ? "" : withheldAccountClause(recovery, "the command below prints").trimEnd();
|
|
10753
|
-
out.write(" The template does not declare these, so cdkd cannot tell an AWS-authored value from an out-of-band change and will not reset either
|
|
10874
|
+
out.write(" The template does not declare these, so cdkd cannot tell an AWS-authored value from an out-of-band change and will not reset either. " + (refresh === void 0 ? "Re-deploy if you want them reverted too; this record's identity cannot be named safely in a command, so none is offered.\n" : `Populate observedProperties with the command below, or re-deploy, if you want them reverted too.${refreshAccountNote === "" ? "" : ` ${refreshAccountNote}`}\n`));
|
|
10754
10875
|
if (refresh !== void 0) out.write(` Populate with: ${refresh.command}\n`);
|
|
10755
10876
|
}
|
|
10756
10877
|
}
|
|
@@ -10992,6 +11113,11 @@ function maskMarkedNoEchoBaselineWithLeaves(baseline, record, observed) {
|
|
|
10992
11113
|
...widened.length > 0 && { noEchoLeaves: canonicalCoordinates([...marked, ...widened]) }
|
|
10993
11114
|
};
|
|
10994
11115
|
}
|
|
11116
|
+
function otherPhysicalIds(resources, logicalId) {
|
|
11117
|
+
const ids = [];
|
|
11118
|
+
for (const [id, record] of Object.entries(resources ?? {})) if (id !== logicalId && typeof record?.physicalId === "string") ids.push(record.physicalId);
|
|
11119
|
+
return ids;
|
|
11120
|
+
}
|
|
10995
11121
|
|
|
10996
11122
|
//#endregion
|
|
10997
11123
|
//#region src/cli/commands/stack-lock-guard.ts
|
|
@@ -11150,6 +11276,7 @@ function holdsSecretDerivedPrincipalRecord(resource) {
|
|
|
11150
11276
|
|
|
11151
11277
|
//#endregion
|
|
11152
11278
|
//#region src/cli/commands/destroy-runner.ts
|
|
11279
|
+
const NOECHO_PRINTING_BIND_CAP_MS = 1e4;
|
|
11153
11280
|
const NESTED_STACK_TYPE = "AWS::CloudFormation::Stack";
|
|
11154
11281
|
function recordDestroyEvent(recorder, event) {
|
|
11155
11282
|
recorder?.record(maskEventTextWithBoundBags(event));
|
|
@@ -11278,15 +11405,37 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
11278
11405
|
logger.info(`\nResources to be deleted (${resourceCount}):`);
|
|
11279
11406
|
for (const [logicalId, resource] of Object.entries(state.resources)) logger.info(` - ${displaySafe(logicalId)} (${displaySafe(resource.resourceType)})`);
|
|
11280
11407
|
const protectedCount = ctx.removeProtection ? countProtectedResources(state) + countProtectedJournaledOrphans(journaledOrphans, state.region) : 0;
|
|
11408
|
+
let binding;
|
|
11409
|
+
const stackNoEchoValues = () => {
|
|
11410
|
+
if (binding === void 0) {
|
|
11411
|
+
let timer;
|
|
11412
|
+
const capped = new Promise((resolve) => {
|
|
11413
|
+
timer = setTimeout(() => {
|
|
11414
|
+
logger.warn(safeMsg`The stack's NoEcho values were not bound within ${NOECHO_PRINTING_BIND_CAP_MS / 1e3}s, ` + "so a resource name taken from one may print unmasked where state holds it in plaintext (state written before schema v11).");
|
|
11415
|
+
resolve(void 0);
|
|
11416
|
+
}, NOECHO_PRINTING_BIND_CAP_MS);
|
|
11417
|
+
timer.unref?.();
|
|
11418
|
+
});
|
|
11419
|
+
binding = {
|
|
11420
|
+
bound: Promise.resolve().then(() => ctx.noEchoReresolver?.printingNoEchoValues()).catch(() => void 0).finally(() => clearTimeout(timer)),
|
|
11421
|
+
capped
|
|
11422
|
+
};
|
|
11423
|
+
}
|
|
11424
|
+
return Promise.race([binding.bound, binding.capped]);
|
|
11425
|
+
};
|
|
11281
11426
|
const orphansAtDestroy = state.orphans ?? [];
|
|
11282
11427
|
if (orphansAtDestroy.length > 0) {
|
|
11283
11428
|
logger.info(`\n${orphansAtDestroy.length} resource(s) are still in AWS from an earlier failed deploy. cdkd left them there because their DeletionPolicy is Retain (CDK's RemovalPolicy.RETAIN), and has been tracking them so a later deploy of this stack could adopt them back instead of colliding with their names.`);
|
|
11284
11429
|
logger.info("Destroying this stack deletes that record. The resources stay in AWS, may continue to incur charges, and cdkd will no longer know about them:");
|
|
11285
|
-
|
|
11430
|
+
const orphanListing = orphanRecordsPrintingBag(orphansAtDestroy, await stackNoEchoValues());
|
|
11431
|
+
for (const entry of orphansAtDestroy) withPrintingSecrets(orphanListing, () => logger.info(` - ${displaySafe(entry.logicalId)} (${displaySafe(entry.state.resourceType)}) ${displaySafe(entry.state.physicalId)}`));
|
|
11286
11432
|
}
|
|
11287
11433
|
if (journaledOrphans.count > 0) {
|
|
11288
11434
|
logger.info(`\n${journaledOrphans.count} resource(s) were created by a failed deploy and are recorded only in the rollback journal. Each is deleted first as its DeletionPolicy directs (Retain keeps it in AWS, Snapshot takes the final snapshot), unless state or a later deploy may own it, which is warned about instead:`);
|
|
11289
|
-
|
|
11435
|
+
const listing = journaledOrphanPrintingBag(journaledOrphans.segments.flatMap(({ ops }) => ops), state.resources, await stackNoEchoValues());
|
|
11436
|
+
withPrintingSecrets(listing, () => {
|
|
11437
|
+
for (const line of journaledOrphanLines(journaledOrphans, logger)) logger.info(line);
|
|
11438
|
+
});
|
|
11290
11439
|
}
|
|
11291
11440
|
if (!ctx.skipConfirmation) {
|
|
11292
11441
|
if (process.stdin.isTTY !== true) throw new CdkdError(`The destroy confirmation prompt for stack ${displayStackName(stackName)} cannot run in a non-interactive environment. Pass --yes / -y to confirm the destroy (cdkd destroy also accepts -f / --force), or run the command from a real terminal.`, "NON_INTERACTIVE_CONFIRM");
|
|
@@ -11433,9 +11582,11 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
11433
11582
|
secretPrincipalRegions = ctx.resolveSecretDerivedPrincipals !== void 0 && (state.parentStack === void 0 || ctx.resolveSecretDerivedPrincipals.inheritedProducerRegions !== void 0) ? destroyProducerRegions(state, ctx.resolveSecretDerivedPrincipals.inheritedProducerRegions) : void 0;
|
|
11434
11583
|
if (ctx.resolveSecretDerivedPrincipals !== void 0 && secretPrincipalRegions === void 0 && Object.values(state.resources ?? {}).some((r) => holdsSecretDerivedPrincipalRecord(r))) logger.warn(safeMsg`${stackName}: this nested child's secret-derived principal records resolve when destroyed through its parent stack; destroyed on its own they are skipped.`);
|
|
11435
11584
|
renderer.start();
|
|
11585
|
+
stackNoEchoValues();
|
|
11436
11586
|
const journaledUnderLock = await loadJournaledOrphans(ctx.stateBackend, stackName, regionForState, state.orphans, journaledOrphans.unreadable === true ? { warn: () => void 0 } : logger);
|
|
11437
11587
|
if (journaledUnderLock.unreadable === true && journaledOrphans.unreadable !== true) throw new Error(`The rollback journal of stack ${displayStackName(stackName)} (${displaySafe(regionForState, { asciiOnly: true })}) was readable when this run started and cannot be read now (see the warning above). Nothing was deleted; re-run the destroy once it can be read.`);
|
|
11438
11588
|
if (!sameJournaledOrphans(journaledUnderLock, journaledOrphans)) throw new Error(`The rollback journal of stack ${displayStackName(stackName)} (${displaySafe(regionForState, { asciiOnly: true })}) recorded ${journaledOrphans.count} resource(s) a failed deploy created when this run started and ${journaledUnderLock.count} now, not the same ones — another cdkd process wrote to it. Nothing was deleted; re-run the destroy to act on the current journal.`);
|
|
11589
|
+
const noEchoValues = await stackNoEchoValues();
|
|
11439
11590
|
if (journaledUnderLock.count > 0) {
|
|
11440
11591
|
const orphanOutcome = await deleteJournaledOrphans(journaledUnderLock, { ...state.resources }, stackName, {
|
|
11441
11592
|
providerRegistry: destroyProviderRegistry,
|
|
@@ -11451,7 +11602,10 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
11451
11602
|
}),
|
|
11452
11603
|
importedProducerRegions: producerRegionsFromState(state),
|
|
11453
11604
|
...state.parentStack !== void 0 && { producerRegionsIncomplete: true }
|
|
11454
|
-
}, {
|
|
11605
|
+
}, {
|
|
11606
|
+
isInterrupted: () => lock.interrupted,
|
|
11607
|
+
noEchoValues
|
|
11608
|
+
});
|
|
11455
11609
|
result.errorCount += orphanOutcome.failures;
|
|
11456
11610
|
journaledOrphanFailures = orphanOutcome.failures;
|
|
11457
11611
|
result.skippedCount += orphanOutcome.skipped;
|
|
@@ -11512,6 +11666,7 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
11512
11666
|
const graph = dagBuilder.buildGraph(template);
|
|
11513
11667
|
const executionLevels = dagBuilder.getExecutionLevels(graph);
|
|
11514
11668
|
logger.debug(`Dependency graph: ${executionLevels.length} level(s)`);
|
|
11669
|
+
const printingBagOf = secretNamePrintingBags(state.resources, noEchoValues);
|
|
11515
11670
|
for (let levelIndex = executionLevels.length - 1; levelIndex >= 0; levelIndex--) {
|
|
11516
11671
|
if (lock.interrupted) {
|
|
11517
11672
|
logger.debug("Interrupted (draining) — not scheduling further deletion levels");
|
|
@@ -11521,7 +11676,7 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
11521
11676
|
if (!level) continue;
|
|
11522
11677
|
logger.debug(`Deletion level ${executionLevels.length - levelIndex}/${executionLevels.length} (${level.length} resources)`);
|
|
11523
11678
|
const stackRegion = state.region ?? ctx.baseRegion;
|
|
11524
|
-
const deletePromises = level.map((logicalId) => withPrintingSecrets(
|
|
11679
|
+
const deletePromises = level.map((logicalId) => withPrintingSecrets(printingBagOf(logicalId), async () => {
|
|
11525
11680
|
if (lock.interrupted) return;
|
|
11526
11681
|
const resource = state.resources[logicalId];
|
|
11527
11682
|
if (!resource) {
|
|
@@ -12290,7 +12445,7 @@ async function destroyCommand(stackArgs, options) {
|
|
|
12290
12445
|
}
|
|
12291
12446
|
}
|
|
12292
12447
|
function createDestroyCommand() {
|
|
12293
|
-
const cmd = new Command("destroy").description("Destroy all resources in the stack").argument("[stacks...]", "Stack name(s) to destroy. Accepts CDK display paths (e.g. 'MyStage/Api') with wildcards ('MyStage/*', '**'), or exact physical CloudFormation names (e.g. 'MyStage-Api').").option("--all", "Destroy every top-level stack (top-level only; Stage stacks: '**')", false).option("--purge-events", `After a clean destroy, also delete the stack's deployment-event history
|
|
12448
|
+
const cmd = new Command("destroy").description("Destroy all resources in the stack").argument("[stacks...]", "Stack name(s) to destroy. Accepts CDK display paths (e.g. 'MyStage/Api') with wildcards ('MyStage/*', '**'), or exact physical CloudFormation names (e.g. 'MyStage-Api').").option("--all", "Destroy every top-level stack (top-level only; Stage stacks: '**')", false).option("--purge-events", `After a clean destroy, also delete the stack's deployment-event history, purging every earlier version under the stack's deployments/ prefix on a versioned state bucket too unless a warning says otherwise. By default events survive destroy as post-mortem context. Skipped when the destroy fails or is interrupted (those events aid the retry). Equivalent for an already-destroyed stack: cdkd events prune ${commandHole("stack")} --all.`, false).action(withErrorHandling(destroyCommand));
|
|
12294
12449
|
[
|
|
12295
12450
|
...commonOptions,
|
|
12296
12451
|
...appOptions,
|
|
@@ -15270,7 +15425,7 @@ async function cachedTypeSchemaInfo(resourceType, cfnClient, cache) {
|
|
|
15270
15425
|
function typeIsImportUnsupported(entry) {
|
|
15271
15426
|
return entry.importSupport === "unsupported";
|
|
15272
15427
|
}
|
|
15273
|
-
const CFN_IMPORT_REFUSED_DESPITE_REGISTRY = /* @__PURE__ */ new Map([["AWS::AppSync::GraphQLApi", "measured
|
|
15428
|
+
const CFN_IMPORT_REFUSED_DESPITE_REGISTRY = /* @__PURE__ */ new Map([["AWS::AppSync::GraphQLApi", "measured against AWS: the registry schema declares a read handler and FULLY_MUTABLE, yet CreateChangeSet --change-set-type IMPORT rejected the type"]]);
|
|
15274
15429
|
function cfnRefusesImportDespiteRegistry(resourceType) {
|
|
15275
15430
|
return CFN_IMPORT_REFUSED_DESPITE_REGISTRY.get(resourceType);
|
|
15276
15431
|
}
|
|
@@ -16149,7 +16304,7 @@ async function runPerStackImportLoop(args) {
|
|
|
16149
16304
|
if (!options.yes) {
|
|
16150
16305
|
const phase2Note = totalPhase2Creates > 0 ? ` Phase 2 will CREATE ${totalPhase2Creates} non-importable resource(s) across the tree.` : "";
|
|
16151
16306
|
const recreateNote = totalRecreate > 0 ? ` cdkd will also DELETE ${totalRecreate} AWS resource(s) between phases so CFn can re-CREATE them in phase 2 (brief unavailability window — see the plan above for the affected resources, and for any marked as not confirmed to be re-created).` : "";
|
|
16152
|
-
if (!await confirmPrompt$2(`Create ${perStackPlans.length} CloudFormation stack(s) by importing the cdkd nested-stack tree rooted at ${quotedOrNotShown(rootStackName)} (${quotedRegion(rootRegion)}) — leaf-first, per-stack IMPORT loop
|
|
16307
|
+
if (!await confirmPrompt$2(`Create ${perStackPlans.length} CloudFormation stack(s) by importing the cdkd nested-stack tree rooted at ${quotedOrNotShown(rootStackName)} (${quotedRegion(rootRegion)}) — leaf-first, per-stack IMPORT loop.` + phase2Note + recreateNote + (totalRecreate > 0 ? ` All other AWS resources are unchanged.` : ` AWS resources are unchanged.`) + ` cdkd state for every adopted stack will be deleted on success.`)) {
|
|
16153
16308
|
logger.info("Migration cancelled. cdkd state and CloudFormation are unchanged.");
|
|
16154
16309
|
return {
|
|
16155
16310
|
outcome: "cancelled",
|
|
@@ -16537,6 +16692,250 @@ function spacedAccountClause(recovery, where) {
|
|
|
16537
16692
|
return clause === "" ? "" : ` ${clause}`;
|
|
16538
16693
|
}
|
|
16539
16694
|
|
|
16695
|
+
//#endregion
|
|
16696
|
+
//#region src/cli/commands/state-refresh-observed.ts
|
|
16697
|
+
function collectAcceptRefused(value, previous) {
|
|
16698
|
+
if (value === "") throw new InvalidArgumentError("--accept-refused takes one logical id.");
|
|
16699
|
+
return [...previous ?? [], value];
|
|
16700
|
+
}
|
|
16701
|
+
function readAcceptRefusedTemplate(path) {
|
|
16702
|
+
const shown = displayIdent(path, { maxCodePoints: STACK_REF_MAX_CODE_POINTS });
|
|
16703
|
+
let raw;
|
|
16704
|
+
try {
|
|
16705
|
+
raw = readFileSync(path, "utf-8");
|
|
16706
|
+
} catch (err) {
|
|
16707
|
+
throw new Error(`Failed to read the --template file ${shown}: ${fsReadErrorCause(err)}`);
|
|
16708
|
+
}
|
|
16709
|
+
let parsed;
|
|
16710
|
+
try {
|
|
16711
|
+
parsed = parseCfnTemplateWithFormat(raw).template;
|
|
16712
|
+
} catch {
|
|
16713
|
+
parsed = void 0;
|
|
16714
|
+
}
|
|
16715
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`The --template file ${shown} is not a valid CloudFormation template (JSON or YAML).`);
|
|
16716
|
+
return parsed;
|
|
16717
|
+
}
|
|
16718
|
+
function judgeAcceptRefused(record, logicalId, template, stack) {
|
|
16719
|
+
const id = displayIdent(logicalId);
|
|
16720
|
+
if (record === void 0) return {
|
|
16721
|
+
ok: false,
|
|
16722
|
+
reason: `The stack's state record has no resource ${id}.`
|
|
16723
|
+
};
|
|
16724
|
+
if (record.observedBaselineRefused !== true) return {
|
|
16725
|
+
ok: false,
|
|
16726
|
+
reason: `${id} carries no observed-baseline refusal, so there is nothing to accept. Run 'cdkd state refresh-observed' without --accept-refused to refresh it.`
|
|
16727
|
+
};
|
|
16728
|
+
const reason = record.observedBaselineRefusalReason;
|
|
16729
|
+
if (reason === "incomplete-resolution") return {
|
|
16730
|
+
ok: false,
|
|
16731
|
+
reason: `The refusal on ${id} is not over a template parameter, and --accept-refused overrides only that class. A deploy that actually CHANGES the resource restores its baseline.`
|
|
16732
|
+
};
|
|
16733
|
+
const legacy = reason !== "unverifiable-parameter";
|
|
16734
|
+
const verdict = resourcesNamingDeclaredParameter(template);
|
|
16735
|
+
if (verdict.failedClosed !== void 0) return {
|
|
16736
|
+
ok: false,
|
|
16737
|
+
reason: `The template's parameter dependence could not be judged (${verdict.failedClosed}), so the refusal on ${id} cannot be accepted.`
|
|
16738
|
+
};
|
|
16739
|
+
const resources = template["Resources"];
|
|
16740
|
+
const definition = Object.hasOwn(resources, logicalId) ? resources[logicalId] : void 0;
|
|
16741
|
+
if (definition === null || typeof definition !== "object" || Array.isArray(definition)) return {
|
|
16742
|
+
ok: false,
|
|
16743
|
+
reason: `The template defines no resource ${id}. Pass the template this stack was last deployed from (for a nested stack, the child's own template).`
|
|
16744
|
+
};
|
|
16745
|
+
if (definition["Type"] !== record.resourceType) return {
|
|
16746
|
+
ok: false,
|
|
16747
|
+
reason: `The template's ${id} is not the resource type the state record holds, so the template does not describe this resource.`
|
|
16748
|
+
};
|
|
16749
|
+
if (verdict(logicalId)) return {
|
|
16750
|
+
ok: false,
|
|
16751
|
+
reason: `In this template ${id} still depends on a template parameter, and cdkd binds a parameter's Default, which is not what AWS may hold. Make the template spell the value as a dynamic reference (or a literal), deploy it, then run this again.`
|
|
16752
|
+
};
|
|
16753
|
+
const shape = matchesDeployedShape(definition["Properties"] ?? {}, record.properties, stack);
|
|
16754
|
+
if (shape === "unprovable") return {
|
|
16755
|
+
ok: false,
|
|
16756
|
+
reason: `The template defines ${id} with a function cdkd cannot work out from the state records (only Ref, Fn::GetAtt, Fn::Join, Fn::Sub and Fn::Select of what the stack records), so cdkd cannot prove the template was deployed to the resource. A deploy does not change that; replacing the resource clears the refusal.`
|
|
16757
|
+
};
|
|
16758
|
+
if (shape === "differs") return {
|
|
16759
|
+
ok: false,
|
|
16760
|
+
reason: `The state record of ${id} does not hold what this template defines for it, so cdkd cannot prove the template was deployed to the resource. Pass the template it was last deployed from, or deploy this one and run this again. If cdkd records this resource with fewer properties than the template sets (one it does not send), a deploy does not change that, and replacing the resource clears the refusal.`
|
|
16761
|
+
};
|
|
16762
|
+
const hit = parameterDefaultInProperties(template, record.properties);
|
|
16763
|
+
if (hit !== void 0) return {
|
|
16764
|
+
ok: false,
|
|
16765
|
+
reason: `A recorded property of ${id} holds the Default of the template parameter ${displayIdent(hit)}, so the record may still hold the placeholder the refusal distrusted. If the template no longer uses the parameter there, deploy it and run this again. If the value only coincides with that Default, change or remove the parameter's Default and deploy, or replace the resource.`
|
|
16766
|
+
};
|
|
16767
|
+
return {
|
|
16768
|
+
ok: true,
|
|
16769
|
+
legacy
|
|
16770
|
+
};
|
|
16771
|
+
}
|
|
16772
|
+
const ACCOUNT = Symbol("account");
|
|
16773
|
+
const MISSING = Symbol("missing");
|
|
16774
|
+
function matchesDeployedShape(node, recorded, stack) {
|
|
16775
|
+
let differs = false;
|
|
16776
|
+
let unprovable = false;
|
|
16777
|
+
const pending = [[node, recorded]];
|
|
16778
|
+
while (pending.length > 0) {
|
|
16779
|
+
const [t, r] = pending.pop();
|
|
16780
|
+
if (t === null || typeof t !== "object") {
|
|
16781
|
+
if (t !== r) differs = true;
|
|
16782
|
+
} else if (Array.isArray(t)) {
|
|
16783
|
+
if (!Array.isArray(r) || r.length !== t.length) differs = true;
|
|
16784
|
+
else t.forEach((item, i) => pending.push([item, r[i]]));
|
|
16785
|
+
} else if (isIntrinsic(t)) {
|
|
16786
|
+
const parts = evaluate(t, stack);
|
|
16787
|
+
if (parts === void 0) {
|
|
16788
|
+
unprovable = true;
|
|
16789
|
+
continue;
|
|
16790
|
+
}
|
|
16791
|
+
if (parts === MISSING) {
|
|
16792
|
+
differs = true;
|
|
16793
|
+
continue;
|
|
16794
|
+
}
|
|
16795
|
+
const text = typeof r === "string" ? r : typeof r === "number" ? String(r) : void 0;
|
|
16796
|
+
if (text === void 0 || !partsPattern(parts).test(text)) differs = true;
|
|
16797
|
+
} else if (r === null || typeof r !== "object" || Array.isArray(r)) differs = true;
|
|
16798
|
+
else {
|
|
16799
|
+
const tKeys = Object.keys(t).sort();
|
|
16800
|
+
const rKeys = Object.keys(r).sort();
|
|
16801
|
+
if (tKeys.length !== rKeys.length || tKeys.some((k, i) => k !== rKeys[i])) differs = true;
|
|
16802
|
+
for (const k of tKeys) {
|
|
16803
|
+
if (!Object.hasOwn(r, k)) continue;
|
|
16804
|
+
pending.push([t[k], r[k]]);
|
|
16805
|
+
}
|
|
16806
|
+
}
|
|
16807
|
+
}
|
|
16808
|
+
return unprovable ? "unprovable" : differs ? "differs" : "match";
|
|
16809
|
+
}
|
|
16810
|
+
function isIntrinsic(node) {
|
|
16811
|
+
const keys = Object.keys(node);
|
|
16812
|
+
return keys.length === 1 && (keys[0] === "Ref" || keys[0].startsWith("Fn::"));
|
|
16813
|
+
}
|
|
16814
|
+
function partsPattern(parts) {
|
|
16815
|
+
const body = parts.map((p) => p === ACCOUNT ? "[0-9]{12}" : p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("");
|
|
16816
|
+
return new RegExp(`^${body}$`);
|
|
16817
|
+
}
|
|
16818
|
+
function evaluate(node, stack) {
|
|
16819
|
+
if (typeof node === "string") return [node];
|
|
16820
|
+
if (typeof node === "number" && Number.isFinite(node)) return [String(node)];
|
|
16821
|
+
if (node === null || typeof node !== "object" || Array.isArray(node) || !isIntrinsic(node)) return;
|
|
16822
|
+
const [fn, arg] = Object.entries(node)[0];
|
|
16823
|
+
switch (fn) {
|
|
16824
|
+
case "Ref": return typeof arg === "string" ? reference(arg, stack) : void 0;
|
|
16825
|
+
case "Fn::GetAtt": {
|
|
16826
|
+
const pair = typeof arg === "string" ? arg.includes(".") ? [arg.slice(0, arg.indexOf(".")), arg.slice(arg.indexOf(".") + 1)] : void 0 : arg;
|
|
16827
|
+
if (!Array.isArray(pair) || pair.length !== 2) return void 0;
|
|
16828
|
+
const [target, attribute] = pair;
|
|
16829
|
+
return typeof target === "string" && typeof attribute === "string" ? attributeOf(target, attribute, stack) : void 0;
|
|
16830
|
+
}
|
|
16831
|
+
case "Fn::Join": {
|
|
16832
|
+
if (!Array.isArray(arg) || arg.length !== 2) return void 0;
|
|
16833
|
+
const [delimiter, list] = arg;
|
|
16834
|
+
if (typeof delimiter !== "string" || !Array.isArray(list)) return void 0;
|
|
16835
|
+
const out = [];
|
|
16836
|
+
let missing = false;
|
|
16837
|
+
for (let i = 0; i < list.length; i++) {
|
|
16838
|
+
const parts = evaluate(list[i], stack);
|
|
16839
|
+
if (parts === void 0) return void 0;
|
|
16840
|
+
if (i > 0 && delimiter !== "") out.push(delimiter);
|
|
16841
|
+
if (parts === MISSING) missing = true;
|
|
16842
|
+
else out.push(...parts);
|
|
16843
|
+
}
|
|
16844
|
+
return missing ? MISSING : out;
|
|
16845
|
+
}
|
|
16846
|
+
case "Fn::Select": {
|
|
16847
|
+
if (!Array.isArray(arg) || arg.length !== 2) return void 0;
|
|
16848
|
+
const [index, list] = arg;
|
|
16849
|
+
const i = typeof index === "number" ? index : typeof index === "string" ? Number(index) : NaN;
|
|
16850
|
+
if (!Number.isInteger(i) || !Array.isArray(list) || i < 0 || i >= list.length) return;
|
|
16851
|
+
return evaluate(list[i], stack);
|
|
16852
|
+
}
|
|
16853
|
+
case "Fn::Sub": {
|
|
16854
|
+
const [text, vars] = Array.isArray(arg) ? arg : [arg, {}];
|
|
16855
|
+
if (typeof text !== "string" || vars === null || typeof vars !== "object" || Array.isArray(vars)) return;
|
|
16856
|
+
const out = [];
|
|
16857
|
+
let missing = false;
|
|
16858
|
+
let last = 0;
|
|
16859
|
+
for (const m of text.matchAll(/\$\{([^}]*)\}/g)) {
|
|
16860
|
+
out.push(text.slice(last, m.index));
|
|
16861
|
+
last = m.index + m[0].length;
|
|
16862
|
+
const name = m[1];
|
|
16863
|
+
if (name.startsWith("!")) {
|
|
16864
|
+
out.push(`\${${name.slice(1)}}`);
|
|
16865
|
+
continue;
|
|
16866
|
+
}
|
|
16867
|
+
const parts = Object.hasOwn(vars, name) ? evaluate(vars[name], stack) : name.includes(".") ? attributeOf(name.slice(0, name.indexOf(".")), name.slice(name.indexOf(".") + 1), stack) : reference(name, stack);
|
|
16868
|
+
if (parts === void 0) return void 0;
|
|
16869
|
+
if (parts === MISSING) missing = true;
|
|
16870
|
+
else out.push(...parts);
|
|
16871
|
+
}
|
|
16872
|
+
out.push(text.slice(last));
|
|
16873
|
+
return missing ? MISSING : out;
|
|
16874
|
+
}
|
|
16875
|
+
default: return;
|
|
16876
|
+
}
|
|
16877
|
+
}
|
|
16878
|
+
function reference(name, stack) {
|
|
16879
|
+
switch (name) {
|
|
16880
|
+
case "AWS::Region": return [stack.region];
|
|
16881
|
+
case "AWS::Partition": return [derivePartitionAndUrlSuffix(stack.region).partition];
|
|
16882
|
+
case "AWS::URLSuffix": return [derivePartitionAndUrlSuffix(stack.region).urlSuffix];
|
|
16883
|
+
case "AWS::AccountId": return [ACCOUNT];
|
|
16884
|
+
case "AWS::StackName": return [stack.stackName];
|
|
16885
|
+
}
|
|
16886
|
+
if (name.startsWith("AWS::")) return void 0;
|
|
16887
|
+
if (!Object.hasOwn(stack.resources, name)) return MISSING;
|
|
16888
|
+
const physicalId = stack.resources[name]?.physicalId;
|
|
16889
|
+
return typeof physicalId === "string" ? [physicalId] : void 0;
|
|
16890
|
+
}
|
|
16891
|
+
function attributeOf(target, attribute, stack) {
|
|
16892
|
+
if (!Object.hasOwn(stack.resources, target)) return MISSING;
|
|
16893
|
+
const attributes = stack.resources[target]?.attributes;
|
|
16894
|
+
if (attributes === null || typeof attributes !== "object") return MISSING;
|
|
16895
|
+
if (!Object.hasOwn(attributes, attribute)) return MISSING;
|
|
16896
|
+
const value = attributes[attribute];
|
|
16897
|
+
if (typeof value === "string") return [value];
|
|
16898
|
+
if (typeof value === "number" && Number.isFinite(value)) return [String(value)];
|
|
16899
|
+
}
|
|
16900
|
+
const DEFAULT_SUBSTRING_MIN_LENGTH = 4;
|
|
16901
|
+
function parameterDefaultInProperties(template, properties) {
|
|
16902
|
+
const parameters = template["Parameters"];
|
|
16903
|
+
if (parameters === null || typeof parameters !== "object" || Array.isArray(parameters)) return;
|
|
16904
|
+
const needles = /* @__PURE__ */ new Map();
|
|
16905
|
+
for (const [name, decl] of Object.entries(parameters)) {
|
|
16906
|
+
if (decl === null || typeof decl !== "object") continue;
|
|
16907
|
+
const raw = decl["Default"];
|
|
16908
|
+
let text;
|
|
16909
|
+
if (typeof raw === "string") text = raw;
|
|
16910
|
+
else if (typeof raw === "number" && Number.isFinite(raw)) text = String(raw);
|
|
16911
|
+
if (text === void 0 || text === "") continue;
|
|
16912
|
+
if (!needles.has(text)) needles.set(text, name);
|
|
16913
|
+
const type = decl["Type"];
|
|
16914
|
+
if (typeof type === "string" && (type === "CommaDelimitedList" || type.startsWith("List<"))) for (const item of text.split(",")) {
|
|
16915
|
+
const trimmed = item.trim();
|
|
16916
|
+
if (trimmed !== "" && !needles.has(trimmed)) needles.set(trimmed, name);
|
|
16917
|
+
}
|
|
16918
|
+
}
|
|
16919
|
+
if (needles.size === 0) return void 0;
|
|
16920
|
+
const pending = [properties];
|
|
16921
|
+
while (pending.length > 0) {
|
|
16922
|
+
const value = pending.pop();
|
|
16923
|
+
if (typeof value === "string" || typeof value === "number" && Number.isFinite(value)) {
|
|
16924
|
+
const text = String(value);
|
|
16925
|
+
const exact = needles.get(text);
|
|
16926
|
+
if (exact !== void 0) return exact;
|
|
16927
|
+
for (const [needle, name] of needles) if (needle.length >= DEFAULT_SUBSTRING_MIN_LENGTH && text.includes(needle)) return name;
|
|
16928
|
+
} else if (Array.isArray(value)) pending.push(...value);
|
|
16929
|
+
else if (value !== null && typeof value === "object") pending.push(...Object.values(value));
|
|
16930
|
+
}
|
|
16931
|
+
}
|
|
16932
|
+
function acceptRefusedAssertion(logicalId, resourceType, stackRef, legacy) {
|
|
16933
|
+
return `Accepting the refused observed baseline of ${displayIdent(logicalId)} (${displayIdent(resourceType)}) in ${stackRef}. ` + (legacy ? "The refusal was recorded without a reason this cdkd recognizes, and is treated as one over a template parameter whose deployed value cdkd could not prove. " : "cdkd refused it because the resource reads a template parameter whose deployed value it could not prove. ") + "By accepting you assert that this template is deployed, and that AWS holds NO secret at any position of this resource that the template does not spell as a dynamic reference ({{resolve:...}}): whatever AWS holds there now is written to state.json as the drift baseline, in plaintext. A deploy does not resend a value the record already holds, so a literal there need not be what AWS holds.";
|
|
16934
|
+
}
|
|
16935
|
+
async function confirmAcceptRefused(assertion) {
|
|
16936
|
+
return confirmOrRefuse(`${assertion}\nAccept it?`, { refusal: "The cdkd state refresh-observed --accept-refused confirmation prompt cannot run in a non-interactive environment. Pass -y / --yes to make the assertion, or run the command from a real terminal." });
|
|
16937
|
+
}
|
|
16938
|
+
|
|
16540
16939
|
//#endregion
|
|
16541
16940
|
//#region src/cli/commands/state.ts
|
|
16542
16941
|
const STATE_READ_FAILED_REASON = "state record could not be read; run `cdkd state show` for the error";
|
|
@@ -17109,7 +17508,7 @@ function treeToShowJson(node) {
|
|
|
17109
17508
|
};
|
|
17110
17509
|
}
|
|
17111
17510
|
function createStateShowCommand() {
|
|
17112
|
-
const cmd = new Command("show").description("Show the full cdkd state record for a stack (metadata, outputs, resources)").argument("<stack>", "Stack name (physical CloudFormation name)").option("--json", "Output the raw state and lock as JSON", false).option("--show-nested", "Recursively show every nested-stack child under the target stack
|
|
17511
|
+
const cmd = new Command("show").description("Show the full cdkd state record for a stack (metadata, outputs, resources)").argument("<stack>", "Stack name (physical CloudFormation name)").option("--json", "Output the raw state and lock as JSON", false).option("--show-nested", "Recursively show every nested-stack child under the target stack", false).addOption(stackRegionOption$1()).action(withErrorHandling(stateShowCommand));
|
|
17113
17512
|
[...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
|
|
17114
17513
|
cmd.addOption(deprecatedRegionOption);
|
|
17115
17514
|
return cmd;
|
|
@@ -17705,6 +18104,17 @@ async function stateRefreshObservedCommand(stackArgs, options) {
|
|
|
17705
18104
|
const providerClasses = await loadProviderClasses();
|
|
17706
18105
|
const logger = getLogger();
|
|
17707
18106
|
if (options.verbose) logger.setLevel("debug");
|
|
18107
|
+
let accept;
|
|
18108
|
+
if (options.acceptRefused !== void 0) {
|
|
18109
|
+
if (options.acceptRefused.length !== 1) throw new Error("--accept-refused takes exactly one logical id per run.");
|
|
18110
|
+
if (options.all || stackArgs.length !== 1) throw new Error("--accept-refused applies to one resource of ONE stack: pass a single stack name, not --all.");
|
|
18111
|
+
if (options.template === void 0) throw new Error("--accept-refused requires --template <file>: the synthesized template this stack was last deployed from.");
|
|
18112
|
+
accept = {
|
|
18113
|
+
logicalId: options.acceptRefused[0],
|
|
18114
|
+
template: readAcceptRefusedTemplate(options.template),
|
|
18115
|
+
yes: options.yes ?? false
|
|
18116
|
+
};
|
|
18117
|
+
} else if (options.template !== void 0) throw new Error("--template is used only with --accept-refused.");
|
|
17708
18118
|
if (!options.all && stackArgs.length === 0) throw new Error(`Stack name is required. Usage: cdkd state refresh-observed ${commandHole("stacks...")} | --all`);
|
|
17709
18119
|
const setup = await setupStateBackend(options);
|
|
17710
18120
|
const stackRegionScopes = /* @__PURE__ */ new Map();
|
|
@@ -17753,7 +18163,7 @@ async function stateRefreshObservedCommand(stackArgs, options) {
|
|
|
17753
18163
|
refuseMalformedState(loaded.state, target.stackName, target.region, lockRecovery);
|
|
17754
18164
|
refuseMalformedResourceEntries(loaded.state, target.stackName, target.region, lockRecovery);
|
|
17755
18165
|
}
|
|
17756
|
-
if (!options.yes && !options.dryRun) {
|
|
18166
|
+
if (!options.yes && !options.dryRun && accept === void 0) {
|
|
17757
18167
|
const targetList = targets.map(describedStackRef).join(", ");
|
|
17758
18168
|
if (targets.some(refIsDescribed)) logger.info(STATE_LIST_POINTER);
|
|
17759
18169
|
if (!await confirmRefresh(`Refresh observedProperties for ${targets.length} stack(s) (${targetList})?`)) {
|
|
@@ -17784,7 +18194,8 @@ async function stateRefreshObservedCommand(stackArgs, options) {
|
|
|
17784
18194
|
const counts = await runWithStackAwsClients(scope.clients, () => refreshObservedForStack(target.stackName, targetRegion, setup.stateBackend, setup.lockManager, scope.registry, {
|
|
17785
18195
|
dryRun: options.dryRun ?? false,
|
|
17786
18196
|
logger,
|
|
17787
|
-
lockRecovery
|
|
18197
|
+
lockRecovery,
|
|
18198
|
+
...accept && { accept }
|
|
17788
18199
|
}));
|
|
17789
18200
|
totalRefreshed += counts.refreshed;
|
|
17790
18201
|
totalUnsupported += counts.unsupported;
|
|
@@ -17827,7 +18238,7 @@ async function warnOnLiveForeignLock(lockManager, stackName, region, logger) {
|
|
|
17827
18238
|
} catch {}
|
|
17828
18239
|
}
|
|
17829
18240
|
async function refreshObservedForStack(stackName, region, stateBackend, lockManager, providerRegistry, opts) {
|
|
17830
|
-
const { logger, lockRecovery } = opts;
|
|
18241
|
+
const { logger, lockRecovery, accept } = opts;
|
|
17831
18242
|
const ref = formatStackRefSafe({
|
|
17832
18243
|
stackName,
|
|
17833
18244
|
region
|
|
@@ -17837,7 +18248,33 @@ async function refreshObservedForStack(stackName, region, stateBackend, lockMana
|
|
|
17837
18248
|
const { state, etag, migrationPending } = result;
|
|
17838
18249
|
refuseMalformedState(state, stackName, region, lockRecovery);
|
|
17839
18250
|
refuseMalformedResourceEntries(state, stackName, region, lockRecovery);
|
|
17840
|
-
|
|
18251
|
+
let entries = Object.entries(state.resources);
|
|
18252
|
+
const acceptId = accept?.logicalId;
|
|
18253
|
+
if (accept !== void 0) {
|
|
18254
|
+
const record = Object.hasOwn(state.resources, accept.logicalId) ? state.resources[accept.logicalId] : void 0;
|
|
18255
|
+
const verdict = judgeAcceptRefused(record, accept.logicalId, accept.template, {
|
|
18256
|
+
stackName,
|
|
18257
|
+
region,
|
|
18258
|
+
resources: state.resources
|
|
18259
|
+
});
|
|
18260
|
+
if (!verdict.ok) throw new Error(safeMsg`${ref}: ${verdict.reason}`);
|
|
18261
|
+
entries = [[accept.logicalId, record]];
|
|
18262
|
+
if (!opts.dryRun) {
|
|
18263
|
+
const assertion = acceptRefusedAssertion(accept.logicalId, record.resourceType, ref, verdict.legacy);
|
|
18264
|
+
if (accept.yes) logger.warn(safeMsg`${assertion} (asserted with --yes)`);
|
|
18265
|
+
else if (!await confirmAcceptRefused(assertion)) {
|
|
18266
|
+
logger.info("Aborted.");
|
|
18267
|
+
return {
|
|
18268
|
+
refreshed: 0,
|
|
18269
|
+
unsupported: 0,
|
|
18270
|
+
failed: 0,
|
|
18271
|
+
notFound: 0,
|
|
18272
|
+
refusedBaseline: 0,
|
|
18273
|
+
refusedSticky: 0
|
|
18274
|
+
};
|
|
18275
|
+
}
|
|
18276
|
+
}
|
|
18277
|
+
}
|
|
17841
18278
|
if (entries.length === 0) {
|
|
17842
18279
|
logger.info(safeMsg`✓ ${ref}: no resources in state, skipping`);
|
|
17843
18280
|
return {
|
|
@@ -17854,8 +18291,8 @@ async function refreshObservedForStack(stackName, region, stateBackend, lockMana
|
|
|
17854
18291
|
let wouldUnsupported = 0;
|
|
17855
18292
|
let wouldRefuse = 0;
|
|
17856
18293
|
let wouldRefuseSticky = 0;
|
|
17857
|
-
for (const [, resource] of entries) {
|
|
17858
|
-
if (resource.observedBaselineRefused === true) {
|
|
18294
|
+
for (const [logicalId, resource] of entries) {
|
|
18295
|
+
if (resource.observedBaselineRefused === true && logicalId !== acceptId) {
|
|
17859
18296
|
wouldRefuse++;
|
|
17860
18297
|
if (refusedBaselineRemedy(resource) !== void 0) wouldRefuseSticky++;
|
|
17861
18298
|
continue;
|
|
@@ -17873,6 +18310,7 @@ async function refreshObservedForStack(stackName, region, stateBackend, lockMana
|
|
|
17873
18310
|
if (provider.readCurrentState) wouldRefresh++;
|
|
17874
18311
|
else wouldUnsupported++;
|
|
17875
18312
|
}
|
|
18313
|
+
if (accept !== void 0 && wouldRefresh === 0) throw new Error(safeMsg`${ref}: cdkd cannot read ${displayIdent(accept.logicalId)} back from AWS, so no ` + `baseline can be captured and its refusal stands.`);
|
|
17876
18314
|
logger.info(safeMsg`Plan ${ref}: ${wouldRefresh} resource(s) would be refreshed, ${wouldUnsupported} unsupported` + (wouldRefuse > 0 ? safeMsg`, ${wouldRefuse} refused (import baseline refusal)` : ""));
|
|
17877
18315
|
return {
|
|
17878
18316
|
refreshed: wouldRefresh,
|
|
@@ -17900,7 +18338,7 @@ async function refreshObservedForStack(stackName, region, stateBackend, lockMana
|
|
|
17900
18338
|
const publicSsmProver = new PublicSsmProver(region, () => driftProducerRegionEvidence(state, stackName, region, stateBackend), logger);
|
|
17901
18339
|
await withStackName(stackName, async () => {
|
|
17902
18340
|
const tasks = entries.map(async ([logicalId, resource]) => {
|
|
17903
|
-
if (resource.observedBaselineRefused === true) {
|
|
18341
|
+
if (resource.observedBaselineRefused === true && logicalId !== acceptId) {
|
|
17904
18342
|
refusedBaseline++;
|
|
17905
18343
|
if (refusedBaselineRemedy(resource) !== void 0) refusedSticky++;
|
|
17906
18344
|
return;
|
|
@@ -17935,6 +18373,10 @@ async function refreshObservedForStack(stackName, region, stateBackend, lockMana
|
|
|
17935
18373
|
return;
|
|
17936
18374
|
}
|
|
17937
18375
|
resource.observedProperties = redactSecretsForState(maskReadbackAtCoordinates(observed, resource.properties ?? {}, [...maskedLeafCoordinatesOf(resource.properties ?? {}), ...noEchoLeavesOf(resource) ?? []]), await publicSsmProver.proofBagFor(resource.properties ?? {}), resource.properties ?? {}, STATE_SOURCED_BASELINE_RULES);
|
|
18376
|
+
if (logicalId === acceptId) {
|
|
18377
|
+
delete resource.observedBaselineRefused;
|
|
18378
|
+
delete resource.observedBaselineRefusalReason;
|
|
18379
|
+
}
|
|
17938
18380
|
refreshed++;
|
|
17939
18381
|
} catch (err) {
|
|
17940
18382
|
failed++;
|
|
@@ -17943,12 +18385,24 @@ async function refreshObservedForStack(stackName, region, stateBackend, lockMana
|
|
|
17943
18385
|
});
|
|
17944
18386
|
await Promise.all(tasks);
|
|
17945
18387
|
});
|
|
18388
|
+
if (accept !== void 0 && refreshed === 0) {
|
|
18389
|
+
if (unsupported > 0) throw new Error(safeMsg`${ref}: cdkd cannot read ${displayIdent(accept.logicalId)} back from AWS, so no ` + `baseline was captured and its refusal stands.`);
|
|
18390
|
+
return {
|
|
18391
|
+
refreshed,
|
|
18392
|
+
unsupported,
|
|
18393
|
+
failed,
|
|
18394
|
+
notFound,
|
|
18395
|
+
refusedBaseline,
|
|
18396
|
+
refusedSticky
|
|
18397
|
+
};
|
|
18398
|
+
}
|
|
17946
18399
|
state.lastModified = Date.now();
|
|
17947
18400
|
if (refreshed > 0) delete state.skippedOutputs;
|
|
17948
18401
|
const saveOptions = { expectedEtag: etag };
|
|
17949
18402
|
if (migrationPending) saveOptions.migrateLegacy = true;
|
|
17950
18403
|
await stateBackend.saveState(stackName, region, state, saveOptions);
|
|
17951
18404
|
logger.info(safeMsg`✓ ${ref}: ` + safeMsg`${refreshed} refreshed, ${unsupported} unsupported, ${failed} failed` + (notFound > 0 ? safeMsg`, ${notFound} not found in AWS` : "") + (refusedBaseline > 0 ? safeMsg`, ${refusedBaseline} refused (import baseline refusal)` : ""));
|
|
18405
|
+
if (accept !== void 0) logger.info(safeMsg`Accepted: the observed-baseline refusal on ${displayIdent(accept.logicalId)} was cleared ` + `and a baseline was captured.`);
|
|
17952
18406
|
return {
|
|
17953
18407
|
refreshed,
|
|
17954
18408
|
unsupported,
|
|
@@ -17973,7 +18427,7 @@ async function confirmRefresh(prompt) {
|
|
|
17973
18427
|
return confirmOrRefuse(prompt, { refusal: "The cdkd state refresh-observed confirmation prompt cannot run in a non-interactive environment. Pass -y / --yes to confirm the refresh, or run the command from a real terminal." });
|
|
17974
18428
|
}
|
|
17975
18429
|
function createStateRefreshObservedCommand() {
|
|
17976
|
-
const cmd = new Command("refresh-observed").description("Refresh observedProperties for every resource in a stack by calling provider.readCurrentState — populates the drift baseline for stacks deployed before state schema v3, without redeploying. Run cdkd scrub first on state written by a pre-GHSA binary: the readback is redacted by POSITION against the record, so a record whose own properties still hold plaintext has nothing to redact from.").argument("[stacks...]", "Stack name(s) to refresh (physical CloudFormation names)").option("--all", "Refresh every stack in the state bucket", false).option("--dry-run", "Print the per-stack refresh count without writing state", false).addOption(stackRegionOption$1()).action(withErrorHandling(stateRefreshObservedCommand));
|
|
18430
|
+
const cmd = new Command("refresh-observed").description("Refresh observedProperties for every resource in a stack by calling provider.readCurrentState — populates the drift baseline for stacks deployed before state schema v3, without redeploying. Run cdkd scrub first on state written by a pre-GHSA binary: the readback is redacted by POSITION against the record, so a record whose own properties still hold plaintext has nothing to redact from.").argument("[stacks...]", "Stack name(s) to refresh (physical CloudFormation names)").option("--all", "Refresh every stack in the state bucket", false).option("--dry-run", "Print the per-stack refresh count without writing state", false).option("--accept-refused <logicalId>", "Clear the observed-baseline refusal on ONE resource and capture its baseline, asserting that AWS holds no secret the template does not spell as a dynamic reference. Requires --template and a single stack; prompts unless -y / --yes", collectAcceptRefused).option("--template <file>", "With --accept-refused: the synthesized template (JSON or YAML) this stack was last deployed from").addOption(stackRegionOption$1()).action(withErrorHandling(stateRefreshObservedCommand));
|
|
17977
18431
|
[...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
|
|
17978
18432
|
cmd.addOption(deprecatedRegionOption);
|
|
17979
18433
|
return cmd;
|
|
@@ -18668,7 +19122,7 @@ async function eventsCommand(stackName, options) {
|
|
|
18668
19122
|
async function resolveEventsRegion(reader, stackName, explicitRegion) {
|
|
18669
19123
|
if (explicitRegion) return canonicalizeRegion(explicitRegion);
|
|
18670
19124
|
const regions = await reader.listRegions(stackName);
|
|
18671
|
-
if (regions.length === 0) throw new CdkdError(`No deployment-event history found for stack ${displayStackName(stackName)}. Events are recorded by cdkd's deploy and destroy commands
|
|
19125
|
+
if (regions.length === 0) throw new CdkdError(`No deployment-event history found for stack ${displayStackName(stackName)}. Events are recorded by cdkd's deploy and destroy commands; a stack deployed by an older cdkd version has none.\nIf its history was deleted earlier, the prune subcommand with --all and --stack-region still purges the earlier versions left on a versioned state bucket, unless a warning says otherwise.`, "EVENTS_NOT_FOUND");
|
|
18672
19126
|
if (regions.length > 1) {
|
|
18673
19127
|
const named = regions.filter((r) => isPasteableIdent(r));
|
|
18674
19128
|
const unnamed = regions.length - named.length;
|
|
@@ -18814,7 +19268,7 @@ function colorizeEventType(eventType) {
|
|
|
18814
19268
|
return cyan(token);
|
|
18815
19269
|
}
|
|
18816
19270
|
function createEventsCommand() {
|
|
18817
|
-
const cmd = new Command("events").description("Read back structured deployment events (cdkd's DescribeStackEvents equivalent
|
|
19271
|
+
const cmd = new Command("events").description("Read back structured deployment events (cdkd's DescribeStackEvents equivalent)").argument("<stack>", "Stack name (physical CloudFormation name)").option("--run <runId>", "Read a single run's full event stream instead of the run listing").option("--stack-region <region>", "Disambiguate a stack with event history in multiple regions", parseStackRegion).option("--json", "Output as JSON", false).option("--format <format>", "Output format ('json' is equivalent to --json)").action(withErrorHandling((stack, options) => {
|
|
18818
19272
|
return eventsCommand(stack, {
|
|
18819
19273
|
...options,
|
|
18820
19274
|
json: options.json === true || options.format === "json"
|
|
@@ -20334,10 +20788,53 @@ function noEchoAttributeNamesCarried(prior, attributes) {
|
|
|
20334
20788
|
const kept = prior.filter((name) => typeof name === "string" && hasOwnKey(attributes, name) && carriesSecretMask(attributes[name]));
|
|
20335
20789
|
return kept.length > 0 ? { noEchoAttributeNames: kept } : {};
|
|
20336
20790
|
}
|
|
20791
|
+
const READS_EVERY_KEY = Symbol("reads every key");
|
|
20792
|
+
function templateGetAttReads(template) {
|
|
20793
|
+
const reads = /* @__PURE__ */ new Map();
|
|
20794
|
+
const addRead = (logicalId, attribute) => {
|
|
20795
|
+
let attributes = reads.get(logicalId);
|
|
20796
|
+
if (!attributes) {
|
|
20797
|
+
attributes = /* @__PURE__ */ new Set();
|
|
20798
|
+
reads.set(logicalId, attributes);
|
|
20799
|
+
}
|
|
20800
|
+
if (typeof attribute === "string") {
|
|
20801
|
+
const segments = attribute.split(".");
|
|
20802
|
+
for (let i = 1; i <= segments.length; i++) attributes.add(segments.slice(0, i).join("."));
|
|
20803
|
+
} else attributes.add(READS_EVERY_KEY);
|
|
20804
|
+
};
|
|
20805
|
+
const walk = (value) => {
|
|
20806
|
+
if (Array.isArray(value)) {
|
|
20807
|
+
for (const item of value) walk(item);
|
|
20808
|
+
return;
|
|
20809
|
+
}
|
|
20810
|
+
if (value === null || typeof value !== "object") return;
|
|
20811
|
+
for (const [key, inner] of Object.entries(value)) {
|
|
20812
|
+
if (key === "Fn::GetAtt") {
|
|
20813
|
+
if (Array.isArray(inner) && typeof inner[0] === "string") addRead(inner[0], inner[1]);
|
|
20814
|
+
else if (typeof inner === "string") {
|
|
20815
|
+
const split = splitGetAttStringForm(inner);
|
|
20816
|
+
if (split) addRead(split.logicalId, split.attributeName);
|
|
20817
|
+
}
|
|
20818
|
+
} else if (key === "Fn::Sub") {
|
|
20819
|
+
const text = Array.isArray(inner) ? inner[0] : inner;
|
|
20820
|
+
if (typeof text === "string") for (const match of text.matchAll(/\$\{([^}]*)\}/g)) {
|
|
20821
|
+
const ref = match[1] ?? "";
|
|
20822
|
+
if (ref.startsWith("!")) continue;
|
|
20823
|
+
const split = splitGetAttStringForm(ref);
|
|
20824
|
+
if (split) addRead(split.logicalId, split.attributeName);
|
|
20825
|
+
}
|
|
20826
|
+
}
|
|
20827
|
+
walk(inner);
|
|
20828
|
+
}
|
|
20829
|
+
};
|
|
20830
|
+
walk(template);
|
|
20831
|
+
return reads;
|
|
20832
|
+
}
|
|
20337
20833
|
function buildStackState(stackName, region, rows, templateParser, template, existingState, selectiveMode) {
|
|
20338
20834
|
const resources = selectiveMode && existingState ? { ...existingState.resources } : {};
|
|
20339
20835
|
const parameterNames = new Set(Object.keys(template.Parameters ?? {}));
|
|
20340
20836
|
let namesParameter;
|
|
20837
|
+
const getAttReads = templateGetAttReads(template);
|
|
20341
20838
|
for (const row of rows) {
|
|
20342
20839
|
if (row.outcome !== "imported" || !row.physicalId) continue;
|
|
20343
20840
|
const tmplResource = template.Resources[row.logicalId];
|
|
@@ -20349,10 +20846,14 @@ function buildStackState(stackName, region, rows, templateParser, template, exis
|
|
|
20349
20846
|
const { stillMaskedKeys, keptRecordedKeys } = reimported;
|
|
20350
20847
|
const attributes = withDeclaredNoEchoMasked(reimported.attributes, prior && prior.physicalId === row.physicalId ? prior.noEchoAttributeNames : void 0);
|
|
20351
20848
|
if (keptRecordedKeys.length > 0) getLogger().info(safeMsg`${displayIdent(row.logicalId)}: this import recorded ` + safeMsg`${keptRecordedKeys.map((key) => displayIdent(key)).join(", ")} only as the ` + "redaction mask, so the previously recorded value is kept; a deploy that updates the resource rewrites it.");
|
|
20352
|
-
|
|
20353
|
-
|
|
20354
|
-
|
|
20355
|
-
|
|
20849
|
+
const readAttributes = getAttReads.get(row.logicalId);
|
|
20850
|
+
const refusedKeys = stillMaskedKeys.filter((key) => readAttributes?.has(key) === true || readAttributes?.has(READS_EVERY_KEY) === true);
|
|
20851
|
+
const unreadKeys = stillMaskedKeys.filter((key) => !refusedKeys.includes(key));
|
|
20852
|
+
if (unreadKeys.length > 0) getLogger().debug(safeMsg`${displayIdent(row.logicalId)}: the redaction mask stays recorded under ` + safeMsg`${unreadKeys.map((key) => displayIdent(key)).join(", ")}; this template reads none of them.`);
|
|
20853
|
+
if (refusedKeys.length > 0) {
|
|
20854
|
+
const keys = refusedKeys.map((key) => displayIdent(key)).join(", ");
|
|
20855
|
+
const pronoun = refusedKeys.length === 1 ? "it" : "them";
|
|
20856
|
+
getLogger().warn(safeMsg`${displayIdent(row.logicalId)}: this import produced no value to replace the redaction ` + safeMsg`mask recorded under ${keys}, so the mask is kept and an Fn::GetAtt reading ${pronoun} ` + "in this template is still refused at deploy. It is kept rather than cleared because an attribute missing from state resolves to the physical id instead of failing.");
|
|
20356
20857
|
}
|
|
20357
20858
|
resources[row.logicalId] = {
|
|
20358
20859
|
physicalId: row.physicalId,
|
|
@@ -21214,7 +21715,7 @@ function cannotLeaveUnbound(profile) {
|
|
|
21214
21715
|
return !(profile || process.env["AWS_PROFILE"]);
|
|
21215
21716
|
}
|
|
21216
21717
|
function cfnProviderRefusal(drift) {
|
|
21217
|
-
return `--from-cfn-stack cannot run under --role-arn with this cdk-local version: it has ${drift.join(", ")}, so cdkd cannot make it read the stack with your own credentials instead of the role's. Pass --profile <name> (your own profile), or use the cdk-local version this cdkd release ships with
|
|
21718
|
+
return `--from-cfn-stack cannot run under --role-arn with this cdk-local version: it has ${drift.join(", ")}, so cdkd cannot make it read the stack with your own credentials instead of the role's. Pass --profile <name> (your own profile), or use the cdk-local version this cdkd release ships with.`;
|
|
21218
21719
|
}
|
|
21219
21720
|
const CFN_PROVIDER_CLIENT_GETTERS = [
|
|
21220
21721
|
"getClient",
|
|
@@ -21364,7 +21865,7 @@ function engineRoleExposureWarning(commandName, channels, fromCfnStackChannel, i
|
|
|
21364
21865
|
const envProfileSet = !!input.envProfile;
|
|
21365
21866
|
const open = envProfileSet ? all.filter((c) => c.flagOnly) : all;
|
|
21366
21867
|
if (open.length === 0) return void 0;
|
|
21367
|
-
return `cdkd local ${commandName}: --role-arn ${envProfileSet ? "is set, and the exported AWS_PROFILE does not cover what follows (only the --profile flag does)" : "is set and no profile is selected"}, so the local emulation engine resolves these AS THE ROLE and hands them to your local code: ${open.map((c) => c.what).join("; ")}. Pass --profile <name> with your own profile to keep them on your identity, or do not pass a role whose permissions you would not give the code in the container
|
|
21868
|
+
return `cdkd local ${commandName}: --role-arn ${envProfileSet ? "is set, and the exported AWS_PROFILE does not cover what follows (only the --profile flag does)" : "is set and no profile is selected"}, so the local emulation engine resolves these AS THE ROLE and hands them to your local code: ${open.map((c) => c.what).join("; ")}. Pass --profile <name> with your own profile to keep them on your identity, or do not pass a role whose permissions you would not give the code in the container.`;
|
|
21368
21869
|
}
|
|
21369
21870
|
|
|
21370
21871
|
//#endregion
|
|
@@ -24956,7 +25457,7 @@ function resolveMtlsConfig(options) {
|
|
|
24956
25457
|
});
|
|
24957
25458
|
}
|
|
24958
25459
|
function createLocalStartApiCommand() {
|
|
24959
|
-
const startApi = new Command("start-api").description("Run a long-running local HTTP server that maps API Gateway routes (REST v1, HTTP API, Function URL) to Lambda invocations against the AWS Lambda Runtime Interface Emulator (Docker required). Supports Lambda TOKEN/REQUEST authorizers, Cognito User Pool / HTTP v2 JWT authorizers, and AWS_IAM auth (REST v1 `AuthorizationType: AWS_IAM` and Function URL `AuthType: AWS_IAM` — SigV4 signature verification only; IAM policy evaluation is NOT emulated; see https://cdkd.dev/local-start-api/#aws-iam-authorization). When JWKS is unreachable, JWT authorizers fall back to pass-through (every token accepted) with a warn line — local dev fallback. VPC-config Lambdas run locally and surface a warn line at startup; their containers do NOT get attached to the deployed VPC subnets, so calls to private RDS / ElastiCache will fail.").argument("[target]", "Optional API filter. Accepts the bare CDK logical id ('MyHttpApi'; single-stack apps only), stack-qualified logical id ('MyStack:MyHttpApi'), full CDK Construct path ('MyStack/MyHttpApi/Resource'), or an ancestor Construct path that prefix-matches ('MyStack/MyHttpApi'). When omitted, every discovered API gets its own server. Mirrors `cdkd local invoke` / `cdkd local run-task` target syntax.").addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--stack <name>", "Stack to start (single-stack apps auto-detect)")).addOption(new Option("--warm", "Pre-start one container per Lambda at server boot").default(false)).addOption(new Option("--per-lambda-concurrency <n>", "Pool size cap per Lambda (default 2, max 4)").default("2")).addOption(new Option("--no-pull", "Skip docker pull (cached image)")).addOption(new Option("--container-host <host>", "IP the host uses to bind/probe the RIE port (must be a numeric IP — `docker run -p <ip>:<port>:8080` rejects hostnames). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--debug-port-base <port>", "Reserve a contiguous --debug-port range (one per Lambda)")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--assume-role <arn-or-pair>", "Assume the Lambda's execution role and forward STS-issued temp creds. Two forms: (1) `--assume-role <arn>` sets a single global default ARN used for every routed Lambda; (2) `--assume-role <LogicalId>=<arn>` (repeatable) is a per-Lambda override (wins over the global default and over --assume-role-auto for the named Lambda). Pair with --assume-role-auto to auto-resolve every other Lambda. Precedence: per-Lambda > (--assume-role-auto OR global default) > unset (developer creds passed through).").argParser((raw, prev) => parseAssumeRoleToken(raw, prev))).addOption(new Option("--assume-role-auto", "Auto-resolve EACH routed Lambda's own execution role per-Lambda (literal ARN / Fn::GetAtt against template / --from-cfn-stack state). Slower boot — one STS call per Lambda — but the right shape when each Lambda's deployed role differs. Mutually exclusive with `--assume-role <arn>` (global default); errors at boot. Compatible with `--assume-role <LogicalId>=<arn>` per-Lambda overrides — the map wins for named Lambdas, auto-resolve handles the rest.").default(false)).addOption(new Option("--watch", "Hot-reload: watch the CDK app source tree and re-synth + re-discover routes on a source edit (cdk.out / node_modules / .git excluded; honors cdk.json watch.include / watch.exclude). Off by default; the server keeps the previous version serving when synth fails mid-reload.").default(false)).addOption(new Option("--stage <name>", "Select an API Gateway Stage by its 'StageName'. Default: the first Stage attached to each API. Drives BOTH event.stageVariables and requestContext.stage, for REST v1 and HTTP API v2 alike: when a route's API has a matching templated Stage, the selected StageName is threaded into requestContext.stage. An HTTP API v2 route reports '$default' only when its API carries no AWS::ApiGatewayV2::Stage in the template — that is v2's auto-deployed stage, not a limit on what this flag can select (AWS's CreateStage accepts named stages on v2 too). An API with no Stage matching the selected name is warned about at start-up and its routes get stageVariables: null.")).addOption(new Option("--api <id>", "DEPRECATED — use the positional <target> argument instead. Same accepted forms (bare logical id, stack-qualified, Construct path, ancestor prefix). Will be removed in a future major release.")).addOption(new Option("--layer-role-arn <arn>", "Role to sts:AssumeRole before calling lambda:GetLayerVersion on every literal-ARN entry in Properties.Layers
|
|
25460
|
+
const startApi = new Command("start-api").description("Run a long-running local HTTP server that maps API Gateway routes (REST v1, HTTP API, Function URL) to Lambda invocations against the AWS Lambda Runtime Interface Emulator (Docker required). Supports Lambda TOKEN/REQUEST authorizers, Cognito User Pool / HTTP v2 JWT authorizers, and AWS_IAM auth (REST v1 `AuthorizationType: AWS_IAM` and Function URL `AuthType: AWS_IAM` — SigV4 signature verification only; IAM policy evaluation is NOT emulated; see https://cdkd.dev/local-start-api/#aws-iam-authorization). When JWKS is unreachable, JWT authorizers fall back to pass-through (every token accepted) with a warn line — local dev fallback. VPC-config Lambdas run locally and surface a warn line at startup; their containers do NOT get attached to the deployed VPC subnets, so calls to private RDS / ElastiCache will fail.").argument("[target]", "Optional API filter. Accepts the bare CDK logical id ('MyHttpApi'; single-stack apps only), stack-qualified logical id ('MyStack:MyHttpApi'), full CDK Construct path ('MyStack/MyHttpApi/Resource'), or an ancestor Construct path that prefix-matches ('MyStack/MyHttpApi'). When omitted, every discovered API gets its own server. Mirrors `cdkd local invoke` / `cdkd local run-task` target syntax.").addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--stack <name>", "Stack to start (single-stack apps auto-detect)")).addOption(new Option("--warm", "Pre-start one container per Lambda at server boot").default(false)).addOption(new Option("--per-lambda-concurrency <n>", "Pool size cap per Lambda (default 2, max 4)").default("2")).addOption(new Option("--no-pull", "Skip docker pull (cached image)")).addOption(new Option("--container-host <host>", "IP the host uses to bind/probe the RIE port (must be a numeric IP — `docker run -p <ip>:<port>:8080` rejects hostnames). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--debug-port-base <port>", "Reserve a contiguous --debug-port range (one per Lambda)")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--assume-role <arn-or-pair>", "Assume the Lambda's execution role and forward STS-issued temp creds. Two forms: (1) `--assume-role <arn>` sets a single global default ARN used for every routed Lambda; (2) `--assume-role <LogicalId>=<arn>` (repeatable) is a per-Lambda override (wins over the global default and over --assume-role-auto for the named Lambda). Pair with --assume-role-auto to auto-resolve every other Lambda. Precedence: per-Lambda > (--assume-role-auto OR global default) > unset (developer creds passed through).").argParser((raw, prev) => parseAssumeRoleToken(raw, prev))).addOption(new Option("--assume-role-auto", "Auto-resolve EACH routed Lambda's own execution role per-Lambda (literal ARN / Fn::GetAtt against template / --from-cfn-stack state). Slower boot — one STS call per Lambda — but the right shape when each Lambda's deployed role differs. Mutually exclusive with `--assume-role <arn>` (global default); errors at boot. Compatible with `--assume-role <LogicalId>=<arn>` per-Lambda overrides — the map wins for named Lambdas, auto-resolve handles the rest.").default(false)).addOption(new Option("--watch", "Hot-reload: watch the CDK app source tree and re-synth + re-discover routes on a source edit (cdk.out / node_modules / .git excluded; honors cdk.json watch.include / watch.exclude). Off by default; the server keeps the previous version serving when synth fails mid-reload.").default(false)).addOption(new Option("--stage <name>", "Select an API Gateway Stage by its 'StageName'. Default: the first Stage attached to each API. Drives BOTH event.stageVariables and requestContext.stage, for REST v1 and HTTP API v2 alike: when a route's API has a matching templated Stage, the selected StageName is threaded into requestContext.stage. An HTTP API v2 route reports '$default' only when its API carries no AWS::ApiGatewayV2::Stage in the template — that is v2's auto-deployed stage, not a limit on what this flag can select (AWS's CreateStage accepts named stages on v2 too). An API with no Stage matching the selected name is warned about at start-up and its routes get stageVariables: null.")).addOption(new Option("--api <id>", "DEPRECATED — use the positional <target> argument instead. Same accepted forms (bare logical id, stack-qualified, Construct path, ancestor prefix). Will be removed in a future major release.")).addOption(new Option("--layer-role-arn <arn>", "Role to sts:AssumeRole before calling lambda:GetLayerVersion on every literal-ARN entry in Properties.Layers. Use only when the dev credentials cannot read the layer — typically cross-account layers. AWS-published public layers (e.g. Lambda Powertools) are readable from every account and need no role.")).addOption(new Option("--from-state", "Read cdkd S3 state for every routed stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::Join (and AWS pseudo parameters) in Lambda env vars with the deployed physical IDs / attributes. Off by default — pre-PR warn-and-drop semantics are preserved. Turn on for stacks already deployed via cdkd deploy. Mirrors `cdkd local invoke --from-state` / `cdkd local run-task --from-state`. Re-runs against fresh state on every hot-reload firing (--watch).").default(false)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in Lambda env vars with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the cdkd stack name per routed stack; pass an explicit value when a single CFn stack should serve every routed stack. Mutually exclusive with --from-state. Fn::GetAtt is warn-and-dropped in v1 (CFn ListStackResources does not return per-attribute values).")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-state when the same stack name has state in multiple regions, and with --from-cfn-stack as the CFn client region (cdkd does not have a separate --cfn-stack-region flag).").argParser(parseStackRegion)).addOption(new Option("--mtls-truststore <path>", "PEM-encoded CA bundle for client-certificate verification (mutual TLS). When set, the local server switches from HTTP to HTTPS and the TLS handshake rejects clients whose certificate doesn't chain to one of these CAs. Verified certs are surfaced on the Lambda event under requestContext.identity.clientCert (REST v1) / requestContext.authentication.clientCert (HTTP API v2). Must be set together with --mtls-cert + --mtls-key; partial flag sets are rejected. Generate a CA + server + client cert for local dev: openssl req -x509 -newkey rsa:2048 -nodes -keyout ca-key.pem -out ca.pem -subj \"/CN=cdkd-local-ca\" -days 365; openssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-csr.pem -subj \"/CN=localhost\"; openssl x509 -req -in server-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365; openssl req -newkey rsa:2048 -nodes -keyout client-key.pem -out client-csr.pem -subj \"/CN=client\"; openssl x509 -req -in client-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365; curl --cacert ca.pem --cert client-cert.pem --key client-key.pem https://localhost:<port>/...")).addOption(new Option("--mtls-cert <path>", "PEM-encoded server certificate for mutual TLS. Self-signed is fine for local dev. Must be set together with --mtls-truststore + --mtls-key.")).addOption(new Option("--mtls-key <path>", "PEM-encoded server private key matching --mtls-cert. Must be set together with --mtls-truststore + --mtls-cert.")).addOption(new Option("--strict-sigv4", "Opt-in: enforce strict AWS_IAM SigV4 verification. When set, requests whose signature cannot be cryptographically verified (foreign access-key-id, OR no local AWS credentials configured) are denied. DEFAULT off — warn-and-pass with a placeholder principalId, matching cdk-local's `cdkl start-api`. Enable this when you want local parity with the deployed API Gateway's signature enforcement.").default(false)).action(withErrorHandling(localStartApiCommand));
|
|
24960
25461
|
[
|
|
24961
25462
|
...commonOptions,
|
|
24962
25463
|
...appOptions,
|
|
@@ -26242,7 +26743,7 @@ function buildRunEcsTaskOptions(options, channels, extra = {}) {
|
|
|
26242
26743
|
return runOpts;
|
|
26243
26744
|
}
|
|
26244
26745
|
function createLocalRunTaskCommand() {
|
|
26245
|
-
const cmd = new Command("run-task").description("Run an AWS::ECS::TaskDefinition locally — pulls/builds images, sets up a per-task docker network with the AWS-published metadata-endpoints sidecar, and starts every container in dependsOn order. Target accepts a CDK display path (MyStack/MyService/TaskDef) or stack-qualified logical ID (MyStack:MyServiceTaskDefXYZ1234). Single-stack apps may omit the stack prefix.").argument("<target>", "CDK display path or stack-qualified logical ID of the AWS::ECS::TaskDefinition to run").addOption(new Option("--cluster <name>", "Cluster name surfaced to ECS_CONTAINER_METADATA_URI_V4 and used as the docker network prefix").default("cdkd-local")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"ContainerName\":{\"KEY\":\"VALUE\"}, \"Parameters\":{}})")).addOption(new Option("--container-host <ip>", "Host IP to bind published container ports to. Must be a numeric IP (Docker rejects hostnames here)").default("127.0.0.1")).addOption(new Option("--assume-task-role [arn]", "Assume the task definition's TaskRoleArn (or the supplied ARN) and forward STS-issued temp credentials via the metadata sidecar so containers run with the deployed function role. Bare flag uses the template's TaskRoleArn; pass an explicit ARN to override.")).addOption(new Option("--no-pull", "Skip docker pull for every container image and the metadata sidecar")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries
|
|
26746
|
+
const cmd = new Command("run-task").description("Run an AWS::ECS::TaskDefinition locally — pulls/builds images, sets up a per-task docker network with the AWS-published metadata-endpoints sidecar, and starts every container in dependsOn order. Target accepts a CDK display path (MyStack/MyService/TaskDef) or stack-qualified logical ID (MyStack:MyServiceTaskDefXYZ1234). Single-stack apps may omit the stack prefix.").argument("<target>", "CDK display path or stack-qualified logical ID of the AWS::ECS::TaskDefinition to run").addOption(new Option("--cluster <name>", "Cluster name surfaced to ECS_CONTAINER_METADATA_URI_V4 and used as the docker network prefix").default("cdkd-local")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"ContainerName\":{\"KEY\":\"VALUE\"}, \"Parameters\":{}})")).addOption(new Option("--container-host <ip>", "Host IP to bind published container ports to. Must be a numeric IP (Docker rejects hostnames here)").default("127.0.0.1")).addOption(new Option("--assume-task-role [arn]", "Assume the task definition's TaskRoleArn (or the supplied ARN) and forward STS-issued temp credentials via the metadata sidecar so containers run with the deployed function role. Bare flag uses the template's TaskRoleArn; pass an explicit ARN to override.")).addOption(new Option("--no-pull", "Skip docker pull for every container image and the metadata sidecar")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries. Issues sts:AssumeRole via the default credential chain and uses the temporary credentials for ecr:GetAuthorizationToken + docker pull. Required when the caller does not have direct cross-account access to the target repository. A same-account pull in ANY region does not need this flag: the ECR client is built for the image URI's own region, so crossing a region costs nothing extra.")).addOption(new Option("--platform <platform>", "Force docker --platform (linux/amd64 or linux/arm64). Default: inferred from task RuntimePlatform.CpuArchitecture")).addOption(new Option("--keep-running", "Don't docker rm -f the user containers on task exit (network + sidecar are still torn down). Use when you want to docker exec into a stopped container for post-mortems.").default(false)).addOption(new Option("--detach", "Start the containers in the background and exit (skip log streaming + auto teardown). Useful in CI smoke tests; caller manages container lifecycle.").default(false)).addOption(new Option("--from-state", "Read cdkd S3 state for the target stack and substitute Fn::Sub / Fn::GetAtt references to same-stack AWS::ECR::Repository resources with the deployed URI. Off by default — only the AWS pseudo-parameter tier (${AWS::AccountId} / ${AWS::Region}) is resolved without this flag.").default(false)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in container env vars / secrets / image URIs with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the cdkd stack name; pass an explicit value when the CFn stack name differs. Mutually exclusive with --from-state. Fn::GetAtt is warn-and-dropped in v1 (CFn ListStackResources does not return per-attribute values).")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-state when the same stack name has state in multiple regions, and with --from-cfn-stack as the CFn client region (cdkd does not have a separate --cfn-stack-region flag).").argParser(parseStackRegion)).action(withErrorHandling(localRunTaskCommand));
|
|
26246
26747
|
[
|
|
26247
26748
|
...commonOptions,
|
|
26248
26749
|
...appOptions,
|
|
@@ -26270,7 +26771,7 @@ function serviceStrategy() {
|
|
|
26270
26771
|
};
|
|
26271
26772
|
}
|
|
26272
26773
|
function createLocalStartServiceCommand() {
|
|
26273
|
-
const cmd = new Command("start-service").description("Run one or more AWS::ECS::Service resources locally as a long-running emulator. Spins up DesiredCount task replicas per service (clamped by --max-tasks) using the same per-task docker network + metadata sidecar pattern as `cdkd local run-task`, then keeps each replica running and restarts it on exit per --restart-policy. ^C tears every replica + sidecar + network down. Each <target> accepts a CDK display path (MyStack/MyService) or stack-qualified logical ID (MyStack:MyServiceXYZ); single-stack apps may omit the stack prefix. When two or more <target>s are supplied, every service is booted into a shared Cloud Map / Service Connect registry so peer services discover each other via docker --add-host overlay
|
|
26774
|
+
const cmd = new Command("start-service").description("Run one or more AWS::ECS::Service resources locally as a long-running emulator. Spins up DesiredCount task replicas per service (clamped by --max-tasks) using the same per-task docker network + metadata sidecar pattern as `cdkd local run-task`, then keeps each replica running and restarts it on exit per --restart-policy. ^C tears every replica + sidecar + network down. Each <target> accepts a CDK display path (MyStack/MyService) or stack-qualified logical ID (MyStack:MyServiceXYZ); single-stack apps may omit the stack prefix. When two or more <target>s are supplied, every service is booted into a shared Cloud Map / Service Connect registry so peer services discover each other via docker --add-host overlay. Omit <targets> in an interactive terminal to multi-select the ECS services from a list.").argument("[targets...]", "One or more CDK display paths or stack-qualified logical IDs of the AWS::ECS::Service resources to run (omit to multi-select interactively in a TTY)").addOption(new Option("--from-state", "Read cdkd's S3 state for the target stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::ImportValue / Fn::GetStackOutput intrinsics in container images, environment variables, secrets, role ARNs, and volumes. Mutually exclusive with --from-cfn-stack.").default(false)).addOption(new Option("--state-bucket <bucket>", "S3 bucket for --from-state. Falls back to CDKD_STATE_BUCKET env or cdk.json context.cdkd.stateBucket.")).addOption(new Option("--state-prefix <prefix>", "S3 key prefix for --from-state state files.").default("cdkd")).action(withErrorHandling(async (targets, options) => {
|
|
26274
26775
|
await runEcsServiceEmulator(targets, options, serviceStrategy(), cdkdExtraStateProviders);
|
|
26275
26776
|
}));
|
|
26276
26777
|
addStartServiceSpecificOptions(cmd);
|
|
@@ -27458,7 +27959,7 @@ function readEnvOverridesFile$1(filePath) {
|
|
|
27458
27959
|
return parsed;
|
|
27459
27960
|
}
|
|
27460
27961
|
function createLocalInvokeAgentCoreCommand() {
|
|
27461
|
-
const cmd = new Command("invoke-agentcore").description("Run a Bedrock AgentCore Runtime container locally and invoke it once over its protocol contract: HTTP (POST /invocations + GET /ping on 8080) or MCP (POST /mcp Streamable HTTP on 8000). Resolves the AWS::BedrockAgentCore::Runtime, pulls/builds its container, injects env vars + AWS credentials, and prints the response. For an MCP runtime, runs the session handshake then sends one JSON-RPC request (tools/list by default, or the method/params from --event). Target accepts a CDK display path (MyStack/MyAgent) or stack-qualified logical ID (MyStack:MyAgentRuntime1234). Single-stack apps may omit the stack prefix. Omit <target> in an interactive terminal to pick from a list. Supports the container artifact and the CodeConfiguration managed-runtime artifact (fromCodeAsset, built from source) on the HTTP + MCP protocols; the agent calls real AWS for managed services.").argument("[target]", "CDK display path or stack-qualified logical ID of the AgentCore Runtime to invoke (omit to pick interactively in a TTY)").addOption(new Option("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option("--event-stdin", "Read event JSON from stdin").default(false)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}})")).addOption(new Option("--session-id <id>", "AgentCore runtime session id header value (default: a random UUID)")).addOption(new Option("--ws", "Stream over the HTTP-protocol agent's bidirectional /ws WebSocket endpoint (on 8080) instead of POST /invocations: send --event as the first frame and print every received frame to stdout until the agent closes. When stdin is a TTY, auto-enters a REPL — each typed line is sent as a follow-up text frame until Ctrl-D / agent close; pipe from /dev/null to force one-shot in a TTY. Ignored for an MCP runtime.").default(false)).addOption(new Option("--watch", "Re-synth and reload the agent container on CDK source changes
|
|
27962
|
+
const cmd = new Command("invoke-agentcore").description("Run a Bedrock AgentCore Runtime container locally and invoke it once over its protocol contract: HTTP (POST /invocations + GET /ping on 8080) or MCP (POST /mcp Streamable HTTP on 8000). Resolves the AWS::BedrockAgentCore::Runtime, pulls/builds its container, injects env vars + AWS credentials, and prints the response. For an MCP runtime, runs the session handshake then sends one JSON-RPC request (tools/list by default, or the method/params from --event). Target accepts a CDK display path (MyStack/MyAgent) or stack-qualified logical ID (MyStack:MyAgentRuntime1234). Single-stack apps may omit the stack prefix. Omit <target> in an interactive terminal to pick from a list. Supports the container artifact and the CodeConfiguration managed-runtime artifact (fromCodeAsset, built from source) on the HTTP + MCP protocols; the agent calls real AWS for managed services.").argument("[target]", "CDK display path or stack-qualified logical ID of the AgentCore Runtime to invoke (omit to pick interactively in a TTY)").addOption(new Option("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option("--event-stdin", "Read event JSON from stdin").default(false)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}})")).addOption(new Option("--session-id <id>", "AgentCore runtime session id header value (default: a random UUID)")).addOption(new Option("--ws", "Stream over the HTTP-protocol agent's bidirectional /ws WebSocket endpoint (on 8080) instead of POST /invocations: send --event as the first frame and print every received frame to stdout until the agent closes. When stdin is a TTY, auto-enters a REPL — each typed line is sent as a follow-up text frame until Ctrl-D / agent close; pipe from /dev/null to force one-shot in a TTY. Ignored for an MCP runtime.").default(false)).addOption(new Option("--watch", "Re-synth and reload the agent container on CDK source changes. Supported on the HTTP / AGUI protocols, both the --ws session AND the default one-shot POST /invocations (the reload re-runs the single shot). An interpreted-language source edit inside a CodeConfiguration source tree takes a soft-reload fast path (docker cp + docker restart, no rebuild); Dockerfile / compiled-source / asset-hash-changed / ambiguous edits force a full rebuild. For MCP / A2A runtimes --watch is a no-op WARN and the single shot proceeds.").default(false)).addOption(new Option("--bearer-token <jwt>", "Bearer JWT to present when the runtime declares a customJwtAuthorizer. Verified against the runtime OIDC discovery URL (signature / issuer / expiry / audience) before the container starts, then forwarded to /invocations as Authorization: Bearer <jwt>.")).addOption(new Option("--no-verify-auth", "Skip inbound JWT verification even when the runtime declares a customJwtAuthorizer (local-dev escape hatch). A --bearer-token, if given, is still forwarded.")).addOption(new Option("--sigv4", "Sign the /invocations POST with AWS SigV4 (service bedrock-agentcore) using the resolved credentials, matching the cloud default when the runtime declares no customJwtAuthorizer. Opt-in: default unsigned. Mutually exclusive with --bearer-token; ignored on a JWT-protected runtime.").default(false)).addOption(new Option("--platform <platform>", "docker --platform for the agent container (linux/amd64 or linux/arm64)").choices(["linux/amd64", "linux/arm64"]).default("linux/arm64")).addOption(new Option("--no-pull", "Skip docker pull (use cached image) — no-op for the local-build path")).addOption(new Option("--no-build", "Skip docker build on the local-asset path (use the previously-built tag). No-op for the ECR / registry pull paths.")).addOption(new Option("--container-host <host>", "Host to bind the agent port to").default("127.0.0.1")).addOption(new Option("--timeout <ms>", "Per-request timeout in milliseconds. Applied to POST /invocations, POST /mcp, and the /ws open-to-close window. Raise this for long-running agent calls that exceed the default.").default(12e4).argParser(parseTimeoutMs)).addOption(new Option("--assume-role [arn]", "Assume the runtime's execution role and forward STS-issued temp credentials to the container so the agent runs with the deployed role. Three forms: (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) uses the runtime's RoleArn when it is a literal ARN; (3) `--no-assume-role` opts out. Off by default — the developer's shell credentials are forwarded unchanged.")).addOption(new Option("--no-assume-role", "Explicitly opt out of assuming the runtime's execution role: forward your ambient AWS credentials (or the --profile overlay) unchanged even when --from-state / --from-cfn-stack is set.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries. A same-account pull in ANY region does not need this flag: the ECR client is built for the image URI's own region, so crossing a region costs nothing extra.")).addOption(new Option("--from-state", "Load cdkd's S3 state for the target stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::ImportValue in env vars with the deployed physical IDs / cross-stack exports. Mutually exclusive with --from-cfn-stack.").default(false)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in env vars with the deployed physical IDs / exports. For CDK apps deployed via the upstream CDK CLI. Bare form uses the resolved stack name; pass an explicit value when the CFn stack name differs. Mutually exclusive with --from-state.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.").argParser(parseStackRegion)).action(withErrorHandling(async (target, options) => {
|
|
27462
27963
|
await localInvokeAgentCoreCommand(target, options);
|
|
27463
27964
|
}));
|
|
27464
27965
|
[
|
|
@@ -27516,7 +28017,7 @@ function warnUnresolvedLambdaTargetEnv(strategy, options) {
|
|
|
27516
28017
|
const ecsNote = resolved.boots.length > 0 ? "The ECS service targets behind this ALB DO honor --from-state. " : "";
|
|
27517
28018
|
return {
|
|
27518
28019
|
...resolved,
|
|
27519
|
-
warnings: [...resolved.warnings, `--from-state does not reach the container environment of this ALB's Lambda target group(s): ${lambdaIds.map((id) => plainOrDescribed(id, "logical id")).join(", ")}. Their Environment.Variables keep any Ref / Fn::GetAtt / Fn::Sub / Fn::ImportValue intrinsics unresolved, and each is then dropped with its own warning. ` + ecsNote + "The only state source the Lambda path reads is --from-cfn-stack '<name>', which REPLACES --from-state (the two are mutually exclusive) and reaches both target kinds on a CloudFormation-deployed stack; otherwise override the affected variables with --env-vars.
|
|
28020
|
+
warnings: [...resolved.warnings, `--from-state does not reach the container environment of this ALB's Lambda target group(s): ${lambdaIds.map((id) => plainOrDescribed(id, "logical id")).join(", ")}. Their Environment.Variables keep any Ref / Fn::GetAtt / Fn::Sub / Fn::ImportValue intrinsics unresolved, and each is then dropped with its own warning. ` + ecsNote + "The only state source the Lambda path reads is --from-cfn-stack '<name>', which REPLACES --from-state (the two are mutually exclusive) and reaches both target kinds on a CloudFormation-deployed stack; otherwise override the affected variables with --env-vars."]
|
|
27520
28021
|
};
|
|
27521
28022
|
}
|
|
27522
28023
|
};
|
|
@@ -27525,7 +28026,7 @@ function buildAlbEmulatorStrategy(options) {
|
|
|
27525
28026
|
return warnUnresolvedLambdaTargetEnv(albStrategy(options), options);
|
|
27526
28027
|
}
|
|
27527
28028
|
function createLocalStartAlbCommand() {
|
|
27528
|
-
const cmd = new Command("start-alb").description("Run an Application Load Balancer locally: name the ALB, and cdk-local boots the ECS service(s) behind its listeners and stands up a local front-door on each listener port that round-robins across the running replicas and routes its listener rules across the backing services — a stable host endpoint, like behind a real load balancer. The symmetric ALB counterpart of `start-api`. Each <target> accepts a CDK display path (MyStack/MyAlb) or stack-qualified logical ID; single-stack apps may omit the stack prefix. Supports HTTP and HTTPS listeners — by default a cloud-HTTPS listener is served over plain HTTP locally (with X-Forwarded-Proto: https preserved). Pass --tls (or --tls-cert / --tls-key) to terminate TLS locally with a self-signed or user-supplied cert. All six ALB rule-condition fields are honored (path-pattern / host-header / http-header / http-request-method / query-string / source-ip); forward (single and weighted), redirect, and fixed-response actions; and ECS or Lambda targets (a Lambda target group is invoked locally via the Lambda RIE). authenticate-cognito / authenticate-oidc actions enforce a local Bearer-JWT check (or AWSELBAuthSessionCookie pass-through) against the same JWKS / OIDC discovery URL the deployed ALB would; use --bearer-token '<jwt>' to inject a default token or --no-verify-auth to disable the guard. Omit <targets> in an interactive terminal to multi-select the load balancers from a list.").argument("[targets...]", "One or more CDK display paths or stack-qualified logical IDs of the AWS::ElasticLoadBalancingV2::LoadBalancer resources to run (omit to multi-select interactively in a TTY)").addOption(new Option("--from-state", "Read cdkd's S3 state for the target stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::ImportValue / Fn::GetStackOutput intrinsics in container images, environment variables, secrets, role ARNs, and volumes of the ECS services behind the ALB. Does NOT reach a Lambda target group's container environment (
|
|
28029
|
+
const cmd = new Command("start-alb").description("Run an Application Load Balancer locally: name the ALB, and cdk-local boots the ECS service(s) behind its listeners and stands up a local front-door on each listener port that round-robins across the running replicas and routes its listener rules across the backing services — a stable host endpoint, like behind a real load balancer. The symmetric ALB counterpart of `start-api`. Each <target> accepts a CDK display path (MyStack/MyAlb) or stack-qualified logical ID; single-stack apps may omit the stack prefix. Supports HTTP and HTTPS listeners — by default a cloud-HTTPS listener is served over plain HTTP locally (with X-Forwarded-Proto: https preserved). Pass --tls (or --tls-cert / --tls-key) to terminate TLS locally with a self-signed or user-supplied cert. All six ALB rule-condition fields are honored (path-pattern / host-header / http-header / http-request-method / query-string / source-ip); forward (single and weighted), redirect, and fixed-response actions; and ECS or Lambda targets (a Lambda target group is invoked locally via the Lambda RIE). authenticate-cognito / authenticate-oidc actions enforce a local Bearer-JWT check (or AWSELBAuthSessionCookie pass-through) against the same JWKS / OIDC discovery URL the deployed ALB would; use --bearer-token '<jwt>' to inject a default token or --no-verify-auth to disable the guard. Omit <targets> in an interactive terminal to multi-select the load balancers from a list.").argument("[targets...]", "One or more CDK display paths or stack-qualified logical IDs of the AWS::ElasticLoadBalancingV2::LoadBalancer resources to run (omit to multi-select interactively in a TTY)").addOption(new Option("--from-state", "Read cdkd's S3 state for the target stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::ImportValue / Fn::GetStackOutput intrinsics in container images, environment variables, secrets, role ARNs, and volumes of the ECS services behind the ALB. Does NOT reach a Lambda target group's container environment (a boot warning names the affected functions) — use --from-cfn-stack for those. Mutually exclusive with --from-cfn-stack.").default(false)).addOption(new Option("--state-bucket <bucket>", "S3 bucket for --from-state. Falls back to CDKD_STATE_BUCKET env or cdk.json context.cdkd.stateBucket.")).addOption(new Option("--state-prefix <prefix>", "S3 key prefix for --from-state state files.").default("cdkd")).action(withErrorHandling(async (targets, options) => {
|
|
27529
28030
|
await runEcsServiceEmulator(targets, options, buildAlbEmulatorStrategy(options), cdkdExtraStateProviders);
|
|
27530
28031
|
}));
|
|
27531
28032
|
addAlbSpecificOptions(cmd);
|
|
@@ -27545,7 +28046,7 @@ function createLocalStartCloudFrontCommand$1() {
|
|
|
27545
28046
|
embedConfig: getEmbedConfig(),
|
|
27546
28047
|
extraStateProviders: cdkdExtraStateProviders
|
|
27547
28048
|
});
|
|
27548
|
-
cmd.addOption(new Option("--from-state", "[not supported on start-cloudfront] Read cdkd's S3 state for the target stack. Refused at startup: the CloudFront emulator consults a state source only under --from-cfn-stack
|
|
28049
|
+
cmd.addOption(new Option("--from-state", "[not supported on start-cloudfront] Read cdkd's S3 state for the target stack. Refused at startup: the CloudFront emulator consults a state source only under --from-cfn-stack. Use --from-cfn-stack instead.").default(false));
|
|
27549
28050
|
cmd.addOption(new Option("--state-bucket <bucket>", "[not supported on start-cloudfront] S3 bucket for --from-state. Refused at startup with --from-state."));
|
|
27550
28051
|
cmd.addOption(new Option("--state-prefix <prefix>", "[not supported on start-cloudfront] S3 key prefix for --from-state state files. Refused at startup with --from-state.").default("cdkd"));
|
|
27551
28052
|
cmd.addOption(new Option("--no-assume-role", "Explicitly opt out of assuming the deployed execution role: forward your ambient AWS credentials (or the --profile overlay) unchanged, and suppress the \"re-run with --assume-role\" hint that omitting the flag prints when deployed state is loaded."));
|
|
@@ -27561,7 +28062,7 @@ function refuseUnwiredCdkdStateFlags(cmd) {
|
|
|
27561
28062
|
if (options.stateBucket !== void 0) passed.push("--state-bucket");
|
|
27562
28063
|
if (actionCommand.getOptionValueSource("statePrefix") === "cli") passed.push("--state-prefix");
|
|
27563
28064
|
if (passed.length === 0) return;
|
|
27564
|
-
actionCommand.error(`error: ${passed.join(" / ")} ${passed.length === 1 ? "is" : "are"} not supported by \`cdkd local start-cloudfront\`. The CloudFront emulator resolves its deployed-S3 origins, its cf.kvs() bindings and its Function URL / Lambda@Edge containers' environment through cdk-local, which consults a state source only under --from-cfn-stack. DROP the flag(s) above, then use --from-cfn-stack '<name>' for a CloudFormation-deployed stack, or --origin '<originId>'='<dir>' to serve an origin from a local directory. Adding --from-cfn-stack while leaving these on hits this same refusal
|
|
28065
|
+
actionCommand.error(`error: ${passed.join(" / ")} ${passed.length === 1 ? "is" : "are"} not supported by \`cdkd local start-cloudfront\`. The CloudFront emulator resolves its deployed-S3 origins, its cf.kvs() bindings and its Function URL / Lambda@Edge containers' environment through cdk-local, which consults a state source only under --from-cfn-stack. DROP the flag(s) above, then use --from-cfn-stack '<name>' for a CloudFormation-deployed stack, or --origin '<originId>'='<dir>' to serve an origin from a local directory. Adding --from-cfn-stack while leaving these on hits this same refusal.`, { code: "cdkd.startCloudFrontStateFlagUnsupported" });
|
|
27565
28066
|
});
|
|
27566
28067
|
}
|
|
27567
28068
|
|
|
@@ -28215,7 +28716,7 @@ function pickReferencedLogicalId(intrinsic) {
|
|
|
28215
28716
|
function createLocalCommand() {
|
|
28216
28717
|
setEmbedConfig(CDKD_EMBED_CONFIG);
|
|
28217
28718
|
const local = new Command("local").description("Local execution of Lambda functions (RIE) and ECS task definitions (Docker required)");
|
|
28218
|
-
const invoke = new Command("invoke").description("Run a Lambda function locally in a Docker container (RIE-backed). Target accepts a CDK display path (MyStack/MyApi/Handler) or stack-qualified logical ID (MyStack:MyApiHandler1234ABCD). Single-stack apps may omit the stack prefix.").argument("<target>", "CDK display path or stack-qualified logical ID of the Lambda to invoke").addOption(new Option("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option("--event-stdin", "Read event JSON from stdin").default(false)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}})")).addOption(new Option("--no-pull", "Skip docker pull (use cached image) — no-op for IMAGE local-build path; `docker build` does not pull base layers by default")).addOption(new Option("--no-build", "Skip docker build on the IMAGE local-build path (use the previously-built tag). Requires the deterministic tag to already be in the local registry; errors with an actionable message when missing. No-op for ZIP Lambdas and the IMAGE ECR-pull path. Compatible with --no-pull.")).addOption(new Option("--debug-port <port>", "Node --inspect-brk port (default: off)")).addOption(new Option("--container-host <host>", "Host to bind the RIE port to").default("127.0.0.1")).addOption(new Option("--assume-role [arn]", "Assume the Lambda's deployed execution role and forward STS-issued temp credentials to the container so the handler runs with the deployed function's narrow permissions (closes the \"developer admin / function narrow\" skew). Three forms: (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) auto-resolves the function's execution role ARN from cdkd state (requires --from-state); (3) `--no-assume-role` explicitly opts out (forces dev creds even with --from-state). Off by default — when omitted, the developer's shell credentials are forwarded unchanged (SAM-compatible default). STS failures degrade to a warn + dev-creds fallback.")).addOption(new Option("--no-assume-role", "Explicitly opt out of assuming the deployed execution role: forward your ambient AWS credentials (or the --profile overlay) even when --from-state is set, and suppress the \"run with --assume-role\" hint. Distinct from omitting the flag, which still prints that hint.")).addOption(new Option("--layer-role-arn <arn>", "Role to sts:AssumeRole before calling lambda:GetLayerVersion on every literal-ARN entry in Properties.Layers
|
|
28719
|
+
const invoke = new Command("invoke").description("Run a Lambda function locally in a Docker container (RIE-backed). Target accepts a CDK display path (MyStack/MyApi/Handler) or stack-qualified logical ID (MyStack:MyApiHandler1234ABCD). Single-stack apps may omit the stack prefix.").argument("<target>", "CDK display path or stack-qualified logical ID of the Lambda to invoke").addOption(new Option("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option("--event-stdin", "Read event JSON from stdin").default(false)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}})")).addOption(new Option("--no-pull", "Skip docker pull (use cached image) — no-op for IMAGE local-build path; `docker build` does not pull base layers by default")).addOption(new Option("--no-build", "Skip docker build on the IMAGE local-build path (use the previously-built tag). Requires the deterministic tag to already be in the local registry; errors with an actionable message when missing. No-op for ZIP Lambdas and the IMAGE ECR-pull path. Compatible with --no-pull.")).addOption(new Option("--debug-port <port>", "Node --inspect-brk port (default: off)")).addOption(new Option("--container-host <host>", "Host to bind the RIE port to").default("127.0.0.1")).addOption(new Option("--assume-role [arn]", "Assume the Lambda's deployed execution role and forward STS-issued temp credentials to the container so the handler runs with the deployed function's narrow permissions (closes the \"developer admin / function narrow\" skew). Three forms: (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) auto-resolves the function's execution role ARN from cdkd state (requires --from-state); (3) `--no-assume-role` explicitly opts out (forces dev creds even with --from-state). Off by default — when omitted, the developer's shell credentials are forwarded unchanged (SAM-compatible default). STS failures degrade to a warn + dev-creds fallback.")).addOption(new Option("--no-assume-role", "Explicitly opt out of assuming the deployed execution role: forward your ambient AWS credentials (or the --profile overlay) even when --from-state is set, and suppress the \"run with --assume-role\" hint. Distinct from omitting the flag, which still prints that hint.")).addOption(new Option("--layer-role-arn <arn>", "Role to sts:AssumeRole before calling lambda:GetLayerVersion on every literal-ARN entry in Properties.Layers. Use only when the dev credentials cannot read the layer — typically cross-account layers. AWS-published public layers (e.g. Lambda Powertools) are readable from every account and need no role.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries. Issues sts:AssumeRole via the default credential chain and uses the temporary credentials for ecr:GetAuthorizationToken + docker pull. Required when the caller does not have direct cross-account access to the target repository. A same-account pull in ANY region does not need this flag: the ECR client is built for the image URI's own region, so crossing a region costs nothing extra.")).addOption(new Option("--from-state", "Read cdkd S3 state for the target stack and substitute Ref / Fn::GetAtt / Fn::Sub in env vars with the deployed physical IDs / attributes. Off by default — keep PR 1 warn-and-drop semantics; turn on for stacks already deployed via cdkd deploy.").default(false)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in env vars with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the cdkd stack name; pass an explicit value when CFn stack name differs. Mutually exclusive with --from-state. Fn::GetAtt is warn-and-dropped in v1 (CFn ListStackResources does not return per-attribute values).")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-state when the same stack name has state in multiple regions, and with --from-cfn-stack as the CFn client region (cdkd does not have a separate --cfn-stack-region flag).").argParser(parseStackRegion)).action(withErrorHandling(localInvokeCommand));
|
|
28219
28720
|
[
|
|
28220
28721
|
...commonOptions,
|
|
28221
28722
|
...appOptions,
|
|
@@ -28289,4 +28790,4 @@ function collectVerbFlags(program) {
|
|
|
28289
28790
|
|
|
28290
28791
|
//#endregion
|
|
28291
28792
|
export { canonicalizeIpProtocolValue as a, buildProgram, resolveSecretDerivedPrincipals as i, runDestroyForStack as n, resolvedResourceTimeoutMs as o, isResolvableSecretPrincipalList as r, canonicalizeIpv4Cidr as t };
|
|
28292
|
-
//# sourceMappingURL=program-
|
|
28793
|
+
//# sourceMappingURL=program-BivXyHmd.js.map
|