@go-to-k/cdkd 0.290.9 → 0.290.10
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-BTsQjH_E.js → asg-provider-BNyUZrYL.js} +2 -2
- package/dist/{asg-provider-BTsQjH_E.js.map → asg-provider-BNyUZrYL.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-B3yP0pHa.js → deploy-engine-B6t-R3eP.js} +3 -3
- package/dist/{deploy-engine-B3yP0pHa.js.map → deploy-engine-B6t-R3eP.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/{program-BslZXdJR.js → program-DUCNL9hK.js} +315 -223
- package/dist/{program-BslZXdJR.js.map → program-DUCNL9hK.js.map} +1 -1
- package/dist/{version-wXpog0Ci.js → version-BwiXzVQd.js} +2 -2
- package/dist/{version-wXpog0Ci.js.map → version-BwiXzVQd.js.map} +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $r as setAwsClients, Cr as Synthesizer, Dn as LockManager, Jr as clearBucketRegionCache, Kr as AssemblyReader, On as S3StateBackend, Qr as resetAwsClients, Si as normalizeAwsError, Un as AssetPublisher, Xr as AwsClients, Yr as resolveBucketRegion, Zr as getAwsClients, bi as formatError, cn as DagBuilder, ei as AssetError, gt as CloudControlProvider, ii as DependencyError, ln as TemplateParser, ni as ConfigError, nn as DiffCalculator, ot as ProviderRegistry, pi as ProvisioningError, r as DeployEngine, rt as IAMRoleProvider, ti as CdkdError, ui as LockError, vi as StateError, xi as isCdkdError, yi as SynthesisError } from "./deploy-engine-
|
|
1
|
+
import { $r as setAwsClients, Cr as Synthesizer, Dn as LockManager, Jr as clearBucketRegionCache, Kr as AssemblyReader, On as S3StateBackend, Qr as resetAwsClients, Si as normalizeAwsError, Un as AssetPublisher, Xr as AwsClients, Yr as resolveBucketRegion, Zr as getAwsClients, bi as formatError, cn as DagBuilder, ei as AssetError, gt as CloudControlProvider, ii as DependencyError, ln as TemplateParser, ni as ConfigError, nn as DiffCalculator, ot as ProviderRegistry, pi as ProvisioningError, r as DeployEngine, rt as IAMRoleProvider, ti as CdkdError, ui as LockError, vi as StateError, xi as isCdkdError, yi as SynthesisError } from "./deploy-engine-B6t-R3eP.js";
|
|
2
2
|
import { a as setLogger, n as getLogger, t as ConsoleLogger } from "./logger-H8n5Qjhq.js";
|
|
3
3
|
|
|
4
4
|
export { AssemblyReader, AssetError, AssetPublisher, AwsClients, CdkdError, CloudControlProvider, ConfigError, ConsoleLogger, DagBuilder, DependencyError, DeployEngine, DiffCalculator, IAMRoleProvider, LockError, LockManager, ProviderRegistry, ProvisioningError, S3StateBackend, StateError, SynthesisError, Synthesizer, TemplateParser, clearBucketRegionCache, formatError, getAwsClients, getLogger, isCdkdError, normalizeAwsError, resetAwsClients, resolveBucketRegion, setAwsClients, setLogger };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { $ as secretBearing, $n as ensureAssetStorage, $r as setAwsClients, $t as s3BucketRegionalDomainName, A as extractDeploymentEventError, Ai as retryClassificationText, An as buildForceUnlockCommand, Ar as resolveSkipPrefix, At as parameterTypeMayLoseSecretIdentity, B as toCfnInteger, Bn as orphansAfterRollback, Br as uploadCfnTemplate, Bt as configIntegerRefusal, C as buildFinalSnapshotIdentifier, Ci as withErrorHandling, Cn as recordMaskOnlyValue, Cr as Synthesizer, Ct as IntrinsicFunctionResolver, D as refusesFinalSnapshot, Di as isTransientServerError, Dn as LockManager, Dr as resolveApp, Dt as getAccountInfo, E as isFinalSnapshotError, Ei as isThrottlingError, En as scrubResourceRecord, Er as getLegacyStateBucketName, Et as coerceParameterTypedValue, F as isStatefulRecreateTargetSync, Fn as CUSTOM_RESOURCE_RESPONSE_PREFIX, Fr as warnDeprecatedNoPrefixCliFlag, Ft as resolveExplicitPhysicalId, G as gray, Gn as WorkGraph, Gr as derivePartitionAndUrlSuffix, Gt as requireConfigObject, H as formatResourceLine, Hn as shouldRetainResource, Hr as expectedOwnerParam, Ht as readConfigString, I as renderStatefulReason, In as DEFAULT_STATE_PREFIX, Ir as CFN_TEMPLATE_BODY_LIMIT, It as assertRegionMatch, J as yellow, Jn as loadPublishableAssetManifest, Jt as producerRegionsFromState, K as green, Kn as buildAssetRedirectMap, Kr as AssemblyReader, Kt as requireConfigString, L as WARM_THROUGHPUT_MEMBERS, Ln as exportNamesCarriedFrom, Lr as CFN_TEMPLATE_URL_LIMIT, Lt as coerceCfnBoolean, M as planOrphanAdoption, Mn as forceQuitRecoveryClause, Mr as resolveStateBucketWithDefaultAndSource, Mt as isSettledInstanceState, N as MULTI_REGION_RECREATE_BLOCKED_TYPES, Nn as formatLockExpiry, Nr as resolveUseCdkBootstrapAssets, Nt as WAFv2WebACLProvider, O as unsupportedFinalSnapshotError, Oi as markNonRetryable, On as S3StateBackend, Or as resolveAutoAssetStorage, Ot as isImpossibleEmptyStoredAttribute, P as isStatefulRecreateTargetForReplace, Pn as shellQuote, Pr as stateBucketExistenceConfirmed, Pt as normalizeAwsTagsToCfn, Q as isExportAliasCollision, Qn as assertAssetBucketRegion, Qr as resetAwsClients, Qt as s3BucketDualStackDomainName, R as coerceWarmThroughput$1, Rn as importableOutputKeys, Rr as MIGRATE_TMP_PREFIX, Rt as coerceCfnInteger, S as PRE_DELETE_SNAPSHOT_TYPES, Si as normalizeAwsError, Sn as maskSecretsInText, Sr as getDockerImageBySourceHash, St as isTerminationProtectionPropagationError, T as createPreDeleteFinalSnapshot, Ti as isRetryableTransientError, Tn as redactSecretsForState, Tr as getDefaultStateBucketName, Tt as cfnRefValueFromPhysicalId, U as bold, Un as AssetPublisher, Ur as PARTITION_TABLE, Ut as replayWarn, V as toFiniteNumber, Vn as orphansCarriedFrom, Vr as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, Vt as configStringRefusal, W as cyan, Wn as stringifyValue, Wr as canonicalizeRegion, Wt as requireConfigArray, X as collectPublishedOutputNames, Xn as AssetModeResolver, Xr as AwsClients, Xt as s3BucketArn, Y as collectDeclaredOutputNames, Yn as rewriteTemplateAssetReferences, Yr as resolveBucketRegion, Yt as withSharedDrainBudget, Z as exportAliasCollisionScrubWarning, Zn as BOOTSTRAP_MARKER_PREFIX, Zr as getAwsClients, Zt as s3BucketDomainName, _ as isSecretBearingReferenceString, _i as StackTerminationProtectionError, _n as errorCauseChain, _r as runDockerForeground, _t as slowCcOperationTimeoutMs, a as DeploymentEventsStore, ai as DeployCancelledError, an as findSilentDropProperties, ar as validateContainerRepoName, at as clearOnUpdateRemoval, b as bindingSkippedOutputs, bn as markSameGenerationBag, br as stripControlChars, bt as deleteSkipReason, c as replayFailedOperations, ci as LocalInvokeBuildError$1, cn as DagBuilder, cr as buildDockerImage, ct as createMaskedRetryLogger, d as updatePartialReason, di as NestedStackChildDirectDestroyError, dn as STATE_SOURCED_CROSS_GENERATION_RULES, dr as describeDockerFailure, dt as beginCommandInterruptScope, en as s3BucketWebsiteUrl, er as getBootstrapMarkerKey, et as secretBearingStateKeyWarning, f as withResourceDeadline, fi as PartialFailureError, fn as STATE_SOURCED_READBACK_RULES, fr as dockerSpawnEnvWithSensitive, ft as endCommandInterruptScope, g as bagHoldsSecretExpression, gi as StackHasActiveImportsError, gn as dynamicReferenceTokens, gr as redactDockerArgvValues, gt as CloudControlProvider, h as computeImplicitDeleteEdges, hi as ResourceUpdateNotSupportedError, hn as createSecretMasker, hr as partitionSensitiveEnv, ht as startInterruptWatch, i as DeploymentEventsReader, in as findActionableSilentDrops, ir as validateAssetBucketName, it as collectInlinePolicyNamesManagedBySiblings, j as makeSiblingClaimReader, jn as buildLockContentionMessage, jr as resolveStateBucketWithDefault, jt as refStateLookupFromResource, k as makeCanonicalizePropertiesFn, ki as markRedactedCause, kn as rebuildClientForBucketRegion, kr as resolveCaptureObservedState, kt as isUnboundTemplateParameter, l as replayRollback, li as LocalStartServiceError, ln as TemplateParser, lr as describeDockerCapturedOutput, lt as maskDeep, m as IMPLICIT_DELETE_DEPENDENCIES, mi as ResourceTimeoutError, mn as carriesSecretMask, mr as getDockerCmd, mt as isInterruptedWaitError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as DiffCalculator, nr as parseBootstrapMarker, nt as getCurrentResourceSecrets, o as planFailedOps, oi as DynamicReferenceRegionAmbiguousError, on as describeTypeWithThrottleRetry, or as buildDenyExternalAccessPolicy, ot as ProviderRegistry, p as maskingRetryLogger, pi as ProvisioningError, pn as TEMPLATE_SOURCED_RULES, pr as formatDockerLoginError, pt as interruptWatchListenerCount, q as red, qn as createAssetRedirectResolver, qr as processStackMessages, qt as classifyReplaySecretRegion, r as DeployEngine, ri as CrossAccountSecretRefusalError, rn as INTRINSIC_KEYS, rr as readBootstrapMarkerBody, rt as IAMRoleProvider, s as planRollback, si as IntrinsicResolutionRefusalError, sn as withRetry, sr as describeAwsFailure, st as wouldReturnToSdkProvider, t as DEFAULT_RESOURCE_TIMEOUT_MS, ti as CdkdError, tn as applyRoleArnIfSet, tr as isCrossRegionRedirect, tt as secretSafeKeyDisplay, u as updatePartialMessage, un as STATE_SOURCED_BASELINE_RULES, ur as describeDockerExecFailure, ut as maskerOrIdentity, v as keptWholeReasonText, vn as identityKeyFor, vr as runDockerStreaming, vt as UNSPECIFIED_SKIP_REASON, w as ccRoutedFinalSnapshotError, wi as isMarkedNonRetryable, wn as recoverMaskedOutput, wr as synthesisStatusMessage, wt as carriesDynamicReference, x as ATOMIC_FINAL_SNAPSHOT_TYPES, xn as maskSecretsInError, xr as AssetManifestLoader, xt as disableInstanceApiTermination, y as mergeNoChangeOutputs, yn as isSingleDynamicReferenceToken, yr as escapeRegExp, yt as deleteIndeterminateGuards, z as isWarmThroughputDecrease, zn as importableOutputs, zr as findLargeInlineResources, zt as configBooleanRefusal } from "./deploy-engine-
|
|
1
|
+
import { $ as secretBearing, $n as ensureAssetStorage, $r as setAwsClients, $t as s3BucketRegionalDomainName, A as extractDeploymentEventError, Ai as retryClassificationText, An as buildForceUnlockCommand, Ar as resolveSkipPrefix, At as parameterTypeMayLoseSecretIdentity, B as toCfnInteger, Bn as orphansAfterRollback, Br as uploadCfnTemplate, Bt as configIntegerRefusal, C as buildFinalSnapshotIdentifier, Ci as withErrorHandling, Cn as recordMaskOnlyValue, Cr as Synthesizer, Ct as IntrinsicFunctionResolver, D as refusesFinalSnapshot, Di as isTransientServerError, Dn as LockManager, Dr as resolveApp, Dt as getAccountInfo, E as isFinalSnapshotError, Ei as isThrottlingError, En as scrubResourceRecord, Er as getLegacyStateBucketName, Et as coerceParameterTypedValue, F as isStatefulRecreateTargetSync, Fn as CUSTOM_RESOURCE_RESPONSE_PREFIX, Fr as warnDeprecatedNoPrefixCliFlag, Ft as resolveExplicitPhysicalId, G as gray, Gn as WorkGraph, Gr as derivePartitionAndUrlSuffix, Gt as requireConfigObject, H as formatResourceLine, Hn as shouldRetainResource, Hr as expectedOwnerParam, Ht as readConfigString, I as renderStatefulReason, In as DEFAULT_STATE_PREFIX, Ir as CFN_TEMPLATE_BODY_LIMIT, It as assertRegionMatch, J as yellow, Jn as loadPublishableAssetManifest, Jt as producerRegionsFromState, K as green, Kn as buildAssetRedirectMap, Kr as AssemblyReader, Kt as requireConfigString, L as WARM_THROUGHPUT_MEMBERS, Ln as exportNamesCarriedFrom, Lr as CFN_TEMPLATE_URL_LIMIT, Lt as coerceCfnBoolean, M as planOrphanAdoption, Mn as forceQuitRecoveryClause, Mr as resolveStateBucketWithDefaultAndSource, Mt as isSettledInstanceState, N as MULTI_REGION_RECREATE_BLOCKED_TYPES, Nn as formatLockExpiry, Nr as resolveUseCdkBootstrapAssets, Nt as WAFv2WebACLProvider, O as unsupportedFinalSnapshotError, Oi as markNonRetryable, On as S3StateBackend, Or as resolveAutoAssetStorage, Ot as isImpossibleEmptyStoredAttribute, P as isStatefulRecreateTargetForReplace, Pn as shellQuote, Pr as stateBucketExistenceConfirmed, Pt as normalizeAwsTagsToCfn, Q as isExportAliasCollision, Qn as assertAssetBucketRegion, Qr as resetAwsClients, Qt as s3BucketDualStackDomainName, R as coerceWarmThroughput$1, Rn as importableOutputKeys, Rr as MIGRATE_TMP_PREFIX, Rt as coerceCfnInteger, S as PRE_DELETE_SNAPSHOT_TYPES, Si as normalizeAwsError, Sn as maskSecretsInText, Sr as getDockerImageBySourceHash, St as isTerminationProtectionPropagationError, T as createPreDeleteFinalSnapshot, Ti as isRetryableTransientError, Tn as redactSecretsForState, Tr as getDefaultStateBucketName, Tt as cfnRefValueFromPhysicalId, U as bold, Un as AssetPublisher, Ur as PARTITION_TABLE, Ut as replayWarn, V as toFiniteNumber, Vn as orphansCarriedFrom, Vr as CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION, Vt as configStringRefusal, W as cyan, Wn as stringifyValue, Wr as canonicalizeRegion, Wt as requireConfigArray, X as collectPublishedOutputNames, Xn as AssetModeResolver, Xr as AwsClients, Xt as s3BucketArn, Y as collectDeclaredOutputNames, Yn as rewriteTemplateAssetReferences, Yr as resolveBucketRegion, Yt as withSharedDrainBudget, Z as exportAliasCollisionScrubWarning, Zn as BOOTSTRAP_MARKER_PREFIX, Zr as getAwsClients, Zt as s3BucketDomainName, _ as isSecretBearingReferenceString, _i as StackTerminationProtectionError, _n as errorCauseChain, _r as runDockerForeground, _t as slowCcOperationTimeoutMs, a as DeploymentEventsStore, ai as DeployCancelledError, an as findSilentDropProperties, ar as validateContainerRepoName, at as clearOnUpdateRemoval, b as bindingSkippedOutputs, bn as markSameGenerationBag, br as stripControlChars, bt as deleteSkipReason, c as replayFailedOperations, ci as LocalInvokeBuildError$1, cn as DagBuilder, cr as buildDockerImage, ct as createMaskedRetryLogger, d as updatePartialReason, di as NestedStackChildDirectDestroyError, dn as STATE_SOURCED_CROSS_GENERATION_RULES, dr as describeDockerFailure, dt as beginCommandInterruptScope, en as s3BucketWebsiteUrl, er as getBootstrapMarkerKey, et as secretBearingStateKeyWarning, f as withResourceDeadline, fi as PartialFailureError, fn as STATE_SOURCED_READBACK_RULES, fr as dockerSpawnEnvWithSensitive, ft as endCommandInterruptScope, g as bagHoldsSecretExpression, gi as StackHasActiveImportsError, gn as dynamicReferenceTokens, gr as redactDockerArgvValues, gt as CloudControlProvider, h as computeImplicitDeleteEdges, hi as ResourceUpdateNotSupportedError, hn as createSecretMasker, hr as partitionSensitiveEnv, ht as startInterruptWatch, i as DeploymentEventsReader, in as findActionableSilentDrops, ir as validateAssetBucketName, it as collectInlinePolicyNamesManagedBySiblings, j as makeSiblingClaimReader, jn as buildLockContentionMessage, jr as resolveStateBucketWithDefault, jt as refStateLookupFromResource, k as makeCanonicalizePropertiesFn, ki as markRedactedCause, kn as rebuildClientForBucketRegion, kr as resolveCaptureObservedState, kt as isUnboundTemplateParameter, l as replayRollback, li as LocalStartServiceError, ln as TemplateParser, lr as describeDockerCapturedOutput, lt as maskDeep, m as IMPLICIT_DELETE_DEPENDENCIES, mi as ResourceTimeoutError, mn as carriesSecretMask, mr as getDockerCmd, mt as isInterruptedWaitError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as DiffCalculator, nr as parseBootstrapMarker, nt as getCurrentResourceSecrets, o as planFailedOps, oi as DynamicReferenceRegionAmbiguousError, on as describeTypeWithThrottleRetry, or as buildDenyExternalAccessPolicy, ot as ProviderRegistry, p as maskingRetryLogger, pi as ProvisioningError, pn as TEMPLATE_SOURCED_RULES, pr as formatDockerLoginError, pt as interruptWatchListenerCount, q as red, qn as createAssetRedirectResolver, qr as processStackMessages, qt as classifyReplaySecretRegion, r as DeployEngine, ri as CrossAccountSecretRefusalError, rn as INTRINSIC_KEYS, rr as readBootstrapMarkerBody, rt as IAMRoleProvider, s as planRollback, si as IntrinsicResolutionRefusalError, sn as withRetry, sr as describeAwsFailure, st as wouldReturnToSdkProvider, t as DEFAULT_RESOURCE_TIMEOUT_MS, ti as CdkdError, tn as applyRoleArnIfSet, tr as isCrossRegionRedirect, tt as secretSafeKeyDisplay, u as updatePartialMessage, un as STATE_SOURCED_BASELINE_RULES, ur as describeDockerExecFailure, ut as maskerOrIdentity, v as keptWholeReasonText, vn as identityKeyFor, vr as runDockerStreaming, vt as UNSPECIFIED_SKIP_REASON, w as ccRoutedFinalSnapshotError, wi as isMarkedNonRetryable, wn as recoverMaskedOutput, wr as synthesisStatusMessage, wt as carriesDynamicReference, x as ATOMIC_FINAL_SNAPSHOT_TYPES, xn as maskSecretsInError, xr as AssetManifestLoader, xt as disableInstanceApiTermination, y as mergeNoChangeOutputs, yn as isSingleDynamicReferenceToken, yr as escapeRegExp, yt as deleteIndeterminateGuards, z as isWarmThroughputDecrease, zn as importableOutputs, zr as findLargeInlineResources, zt as configBooleanRefusal } from "./deploy-engine-B6t-R3eP.js";
|
|
2
2
|
import { C as truncateCodePoints, S as displaySafe, _ as withSkipPrefix, b as UNRENDERABLE, c as PATTERN_B_NAME_OPTIONS, f as explicitNamePropertyFor, h as getCurrentStackName, i as reserveStdoutForPayload, l as PATTERN_B_NAME_PROPERTIES, m as generateResourceNameWithFallback, n as getLogger, o as runStackBuffered, p as generateResourceName, s as getLiveRenderer, u as PATTERN_B_RESOURCE_TYPES, v as withStackName, x as displayIdent, y as STACK_REF_MAX_CODE_POINTS } from "./logger-H8n5Qjhq.js";
|
|
3
3
|
import { t as awsClientDefaults } from "./aws-client-defaults-D-iYiIJ6.js";
|
|
4
|
-
import { t as getCdkdVersion } from "./version-
|
|
5
|
-
import { a as renderDisableCommand, i as protectedReplacementAdvice, r as UNNAMEABLE_ID_CLAUSE, t as ASGProvider } from "./asg-provider-
|
|
4
|
+
import { t as getCdkdVersion } from "./version-BwiXzVQd.js";
|
|
5
|
+
import { a as renderDisableCommand, i as protectedReplacementAdvice, r as UNNAMEABLE_ID_CLAUSE, t as ASGProvider } from "./asg-provider-BNyUZrYL.js";
|
|
6
6
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
7
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
8
8
|
import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, NotFound, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -64007,6 +64007,315 @@ function createDeployCommand() {
|
|
|
64007
64007
|
return cmd;
|
|
64008
64008
|
}
|
|
64009
64009
|
|
|
64010
|
+
//#endregion
|
|
64011
|
+
//#region src/state/malformed-resources-bag.ts
|
|
64012
|
+
/** The error code every malformed-record refusal carries, whatever its class. */
|
|
64013
|
+
const STATE_RESOURCES_MALFORMED = "STATE_RESOURCES_MALFORMED";
|
|
64014
|
+
/**
|
|
64015
|
+
* Answer the ONE question both helpers below key on: can this record's
|
|
64016
|
+
* resource map be read at all?
|
|
64017
|
+
*
|
|
64018
|
+
* Widened past `null` / `undefined` because the message says "no readable
|
|
64019
|
+
* resources map" and a hand-edited record does not stop at those two: a
|
|
64020
|
+
* `[]`, a `5` or a `"ab"` all survive `Object.entries` and yield a bag that is
|
|
64021
|
+
* empty or, for the string, absurd — repaired silently and warned about
|
|
64022
|
+
* nowhere. The predicate is the plain-object test the bag's own type implies.
|
|
64023
|
+
*/
|
|
64024
|
+
function hasReadableResources(state) {
|
|
64025
|
+
return isReadableBag(state.resources);
|
|
64026
|
+
}
|
|
64027
|
+
/**
|
|
64028
|
+
* The plain-object test itself, without the `resources` field bound to it.
|
|
64029
|
+
*
|
|
64030
|
+
* Exported because {@link hasReadableResources} is not the only caller any
|
|
64031
|
+
* more. Spelling the same test a second time at any of them is what this export
|
|
64032
|
+
* exists to prevent: the copies could then drift, and the one that drifted
|
|
64033
|
+
* would fabricate again while looking guarded.
|
|
64034
|
+
*
|
|
64035
|
+
* The consumers outside this module, DERIVED from
|
|
64036
|
+
* `grep -rn "isReadableBag" src/` rather than from recall — re-run that command
|
|
64037
|
+
* rather than trusting this list, which is the third enumeration in this
|
|
64038
|
+
* module's history to be written by reasoning and come out incomplete:
|
|
64039
|
+
*
|
|
64040
|
+
* - `src/cli/commands/state.ts` (3 call sites, all in `repairRenderedContainers`):
|
|
64041
|
+
* `cdkd state show` and `cdkd state resources` walk FOUR more record
|
|
64042
|
+
* containers with `Object.entries` — `outputs`, `skippedOutputs`, and each
|
|
64043
|
+
* resource's `attributes` and `properties` — and a non-object in any of them
|
|
64044
|
+
* fabricates rows exactly as the `resources` bag did (go-to-k/cdkd#3187).
|
|
64045
|
+
* - `src/analyzer/outputs-diff.ts` (1 call site, in `computeOutputsDiff`):
|
|
64046
|
+
* `cdkd diff` walks the stored `outputs` bag to emit its `REMOVE` rows, and a
|
|
64047
|
+
* string there invented one row per character (go-to-k/cdkd#3189). This one is
|
|
64048
|
+
* CROSS-LAYER — the analyzer sits above the state layer, so the import is
|
|
64049
|
+
* downward and carries no cycle, but it means an edit here reaches a layer the
|
|
64050
|
+
* two `resources`-bag callers do not.
|
|
64051
|
+
*
|
|
64052
|
+
* What it does NOT decide is whether a given container is malformed. That is a
|
|
64053
|
+
* per-container call, because absence means different things: an absent
|
|
64054
|
+
* `resources` bag is a defect ({@link hasReadableResources} says so), while an
|
|
64055
|
+
* absent `skippedOutputs` is the normal pre-#2740 record. Each caller pairs
|
|
64056
|
+
* this predicate with its own absence rule.
|
|
64057
|
+
*/
|
|
64058
|
+
function isReadableBag(container) {
|
|
64059
|
+
return typeof container === "object" && container !== null && !Array.isArray(container);
|
|
64060
|
+
}
|
|
64061
|
+
/**
|
|
64062
|
+
* The shared explanation, in the terms the reader needs: what is wrong, what
|
|
64063
|
+
* to look at, and what NOT to do next.
|
|
64064
|
+
*
|
|
64065
|
+
* Both identifiers are SANITIZED and THEN SHELL-QUOTED, and the command is
|
|
64066
|
+
* emitted LAST and UNWRAPPED — the shape `lock-contention-message.ts` and
|
|
64067
|
+
* `.claude/rules/layout-state-types.md` require of any suggestion a user is
|
|
64068
|
+
* meant to paste, for two separate reasons.
|
|
64069
|
+
*
|
|
64070
|
+
* Sanitizing alone is not enough. `displaySafe(..., { asciiOnly: true })` is a
|
|
64071
|
+
* printable-ASCII allowlist, so it removes the line- and escape-forgery class
|
|
64072
|
+
* but KEEPS `'`, `;`, `|`, `` ` ``, `$` and spaces — and neither name is
|
|
64073
|
+
* trusted here, since a stack name reaches the cross-stack read path from an
|
|
64074
|
+
* `Fn::GetStackOutput` argument or an S3 key. A name spelled
|
|
64075
|
+
* `a'; curl http://x|sh; echo '` would close the quoting and append its own
|
|
64076
|
+
* command to the line this text tells the user to RUN.
|
|
64077
|
+
*
|
|
64078
|
+
* Wrapping the command in `'...'` is not enough either, and is what makes the
|
|
64079
|
+
* two compose badly: `shellQuote` does its own quoting, so an outer wrapper
|
|
64080
|
+
* produces something unpastable. Hence unwrapped and last.
|
|
64081
|
+
*
|
|
64082
|
+
* An identifier that sanitizes to EMPTY becomes `UNRENDERABLE` rather than
|
|
64083
|
+
* nothing — an empty argument makes `--stack-region` swallow the next flag,
|
|
64084
|
+
* turning a remedy into a differently-broken command.
|
|
64085
|
+
*/
|
|
64086
|
+
function safeIdentifier(value) {
|
|
64087
|
+
const safe = displaySafe(value, { asciiOnly: true });
|
|
64088
|
+
if (!safe) return UNRENDERABLE;
|
|
64089
|
+
const { text, truncated } = truncateCodePoints(safe, 128);
|
|
64090
|
+
return truncated ? `${text}...` : text;
|
|
64091
|
+
}
|
|
64092
|
+
function malformedStateDetail(stackName, region) {
|
|
64093
|
+
const stack = safeIdentifier(stackName);
|
|
64094
|
+
const reg = safeIdentifier(region);
|
|
64095
|
+
return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has no readable 'resources' map — the record is malformed or truncated. Do NOT run 'cdkd deploy' or 'cdkd destroy' against it: both read the same map, and an unreadable one is indistinguishable from an empty stack, so deploy would re-CREATE every resource and destroy would delete none of them. Inspect it with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
|
|
64096
|
+
}
|
|
64097
|
+
/**
|
|
64098
|
+
* For a READ-ONLY command: give the record an empty resource bag so the
|
|
64099
|
+
* command can report on it, and say so (issue go-to-k/cdkd#3018).
|
|
64100
|
+
*
|
|
64101
|
+
* `parseStateBody` deliberately does not validate the inner shape, so a
|
|
64102
|
+
* hand-edited or truncated record reaches a command with `resources` absent,
|
|
64103
|
+
* `null`, or some other non-object. Every such command then died on a raw
|
|
64104
|
+
* `TypeError` from the first `Object.keys` / `in` / index read — the exact
|
|
64105
|
+
* wording differs per shape (`Cannot convert undefined or null to object`,
|
|
64106
|
+
* `Cannot use 'in' operator`, `Cannot read properties of null`), and none of
|
|
64107
|
+
* them names a stack, a key or a remedy, from exactly the commands a user
|
|
64108
|
+
* reaches for WHEN the state is broken.
|
|
64109
|
+
*
|
|
64110
|
+
* WHY AT THE LOAD AND NOT AT EACH LOOP. The first cut of #3018 put `?? {}` on
|
|
64111
|
+
* the twelve `Object.entries(state.resources)` loops, which was inert: every
|
|
64112
|
+
* one of those flows dereferences the bag EARLIER — `!(id in state.resources)`,
|
|
64113
|
+
* `hasOwnProperty.call(...)`, `state.resources[logicalId]` — so the abort still
|
|
64114
|
+
* happened one line up and the guards only made it look handled. One call per
|
|
64115
|
+
* load dominates the whole flow behind it, including the helpers that take the
|
|
64116
|
+
* state as a parameter (`orphan-rewriter`, `diff-calculator`,
|
|
64117
|
+
* `collectCcApiRoutes`).
|
|
64118
|
+
*
|
|
64119
|
+
* Mutates in place and returns whether it repaired anything; the caller warns
|
|
64120
|
+
* on `true`. A silent repair is its own defect — an empty resource set is
|
|
64121
|
+
* indistinguishable from a healthy empty stack in every later line of output,
|
|
64122
|
+
* so `No changes detected` over an unreadable record is a clean verdict about
|
|
64123
|
+
* nothing.
|
|
64124
|
+
*
|
|
64125
|
+
* **Only for a command that cannot WRITE state.** Anything that can persist
|
|
64126
|
+
* uses {@link refuseMalformedState} instead; see its note.
|
|
64127
|
+
*/
|
|
64128
|
+
function repairMalformedResourcesForReadOnly(state) {
|
|
64129
|
+
if (hasReadableResources(state)) return false;
|
|
64130
|
+
state.resources = {};
|
|
64131
|
+
return true;
|
|
64132
|
+
}
|
|
64133
|
+
/**
|
|
64134
|
+
* The refusal TEXT, for a command whose own exit-code contract means this
|
|
64135
|
+
* cannot be a plain `CdkdError`.
|
|
64136
|
+
*
|
|
64137
|
+
* `cdkd scrub` is the case: its exit `1` is SPOKEN FOR ("--fail found
|
|
64138
|
+
* plaintext") and every one of its refusals carries `exitCode = 2`, because a
|
|
64139
|
+
* CI gate reading the code alone must be able to tell "scrub looked and found
|
|
64140
|
+
* a leak" from "scrub refused to look" — the two call for opposite responses.
|
|
64141
|
+
* So scrub tests {@link hasReadableResources} and raises its own class around
|
|
64142
|
+
* this text rather than calling {@link refuseMalformedState}.
|
|
64143
|
+
*
|
|
64144
|
+
* The other three refusing commands do NOT share that need, and giving them a
|
|
64145
|
+
* single shared code would be wrong in the other direction: `cdkd rollback`
|
|
64146
|
+
* documents `2` as "PARTIAL — journal kept, idempotent re-run", so a `2` here
|
|
64147
|
+
* would tell an operator to re-run a command that attempted nothing.
|
|
64148
|
+
*/
|
|
64149
|
+
function malformedStateRefusalMessage(stackName, region) {
|
|
64150
|
+
return `${malformedStateDetail(stackName, region)} This command can WRITE state, so it refuses rather than continuing: saving over a record whose resource map could not be read would replace the evidence with a well-formed empty one and lose it permanently. Repair or remove the record first.`;
|
|
64151
|
+
}
|
|
64152
|
+
/**
|
|
64153
|
+
* The warning a view emits when it emptied one or more {@link
|
|
64154
|
+
* RenderedStateContainer}s it could not walk (go-to-k/cdkd#3187).
|
|
64155
|
+
*
|
|
64156
|
+
* Deliberately NOT {@link malformedResourcesWarning}'s text, and the reason is
|
|
64157
|
+
* narrower than it looks. That one tells the reader not to run `cdkd deploy` /
|
|
64158
|
+
* `cdkd destroy` because an unreadable `resources` MAP is indistinguishable
|
|
64159
|
+
* from an empty stack: deploy would re-CREATE everything and destroy would
|
|
64160
|
+
* delete nothing. No container named here can produce that specific confusion —
|
|
64161
|
+
* the resource SET is still readable — so borrowing that sentence would attach
|
|
64162
|
+
* a re-create-the-world warning to a record whose resource list is intact.
|
|
64163
|
+
*
|
|
64164
|
+
* It is NOT that these containers are display-only. `properties` is read by the
|
|
64165
|
+
* deploy change calculation (`src/analyzer/diff-calculator.ts`), which imports
|
|
64166
|
+
* nothing from this module, and a non-object there compares unequal to any
|
|
64167
|
+
* desired object and yields a spurious property-change set — filed as
|
|
64168
|
+
* go-to-k/cdkd#3191. An earlier revision of this comment asserted the
|
|
64169
|
+
* display-only premise, which would have read as licence to drop a guard on
|
|
64170
|
+
* that path (review of go-to-k/cdkd#3190).
|
|
64171
|
+
*
|
|
64172
|
+
* What stays the same is the remedy: `--json` is the mode that shows the
|
|
64173
|
+
* stored value.
|
|
64174
|
+
*
|
|
64175
|
+
* ONE warning per record however many containers it names — a stack whose 500
|
|
64176
|
+
* resources all carry a hand-edited `properties` gets one line, not 500. The
|
|
64177
|
+
* caller FILTERS a fixed order (`RENDERED_CONTAINER_ORDER`), so the text is
|
|
64178
|
+
* stable across records. Not `.sort()` — that order is deliberately not
|
|
64179
|
+
* alphabetical, and its own JSDoc says so.
|
|
64180
|
+
*
|
|
64181
|
+
* Both identifiers are sanitized and then shell-quoted, and the command is
|
|
64182
|
+
* emitted LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s own note
|
|
64183
|
+
* gives.
|
|
64184
|
+
*
|
|
64185
|
+
* The container NAMES take {@link safeIdentifier} too — the SAME helper, so
|
|
64186
|
+
* they cannot drift from it — but NOT `shellQuote`, because they appear in the
|
|
64187
|
+
* PROSE and never inside the command this text tells the reader to run; the
|
|
64188
|
+
* command carries the two identifiers and nothing else.
|
|
64189
|
+
*
|
|
64190
|
+
* Sanitizing them is not dead code written for a case that cannot happen. The
|
|
64191
|
+
* union above is closed at COMPILE time, so without this the guarantee would
|
|
64192
|
+
* live in a comment, and the day a caller derives a name from a record instead
|
|
64193
|
+
* of from a literal an unsanitized element could forge a line, render as empty
|
|
64194
|
+
* quotes naming nothing, or run to kilobytes and push the remedy command off
|
|
64195
|
+
* the reader's screen. `safeIdentifier` closes all three and is the identity on
|
|
64196
|
+
* all four literals, so no user-visible text moves.
|
|
64197
|
+
*
|
|
64198
|
+
* What it does NOT close, stated rather than reassured away: a forged name made
|
|
64199
|
+
* only of printable ASCII still renders verbatim inside its quotes and could
|
|
64200
|
+
* read as prose. That residual is bounded to the PROSE — the command the reader
|
|
64201
|
+
* pastes is built from the two shell-quoted identifiers alone — and closing it
|
|
64202
|
+
* would mean JSON-quoting a name in the one place the text is meant to read as
|
|
64203
|
+
* English (review of go-to-k/cdkd#3190).
|
|
64204
|
+
*/
|
|
64205
|
+
function malformedRenderedContainersWarning(stackName, region, containers) {
|
|
64206
|
+
const stack = safeIdentifier(stackName);
|
|
64207
|
+
const reg = safeIdentifier(region);
|
|
64208
|
+
const names = containers.map((name) => `'${safeIdentifier(name)}'`).join(", ");
|
|
64209
|
+
return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has a non-object ${names} — the record is malformed or truncated. 'Object.entries' walks a string or a list as readily as a map, so rendering one INVENTS a row per character or element. Continuing with it EMPTY: this view shows no rows there, which is not the same as the record holding none. A per-resource container is named once however many resources hold one. See the stored values with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
|
|
64210
|
+
}
|
|
64211
|
+
/** The warning a caller of {@link repairMalformedResourcesForReadOnly} emits. */
|
|
64212
|
+
function malformedResourcesWarning(stackName, region) {
|
|
64213
|
+
return `${malformedStateDetail(stackName, region)} Continuing with an EMPTY resource set: this command's output describes zero resources, which is not the same as the stack having none.`;
|
|
64214
|
+
}
|
|
64215
|
+
/**
|
|
64216
|
+
* The `outputs` half of {@link repairMalformedResourcesForReadOnly}, for a
|
|
64217
|
+
* READ-ONLY command that DIFFS the stored bag rather than rendering it
|
|
64218
|
+
* (go-to-k/cdkd#3189).
|
|
64219
|
+
*
|
|
64220
|
+
* `computeOutputsDiff` enumerates the stored bag twice, the second walk
|
|
64221
|
+
* emitting one `REMOVE` row per stored key today's template no longer declares.
|
|
64222
|
+
* It used to admit the bag on a bare `?? {}`, which covers `null` and
|
|
64223
|
+
* `undefined` only — so a hand-edited or truncated record whose `outputs` holds
|
|
64224
|
+
* a string or a list previewed the REMOVAL of outputs that never existed, one
|
|
64225
|
+
* row per character or element, each carrying a character of the record as its
|
|
64226
|
+
* `old:` side, with `cdkd diff --fail` exiting 1 on them.
|
|
64227
|
+
*
|
|
64228
|
+
* AT THE LOAD, for the reason
|
|
64229
|
+
* {@link repairMalformedResourcesForReadOnly}'s own note records and one more
|
|
64230
|
+
* that is specific to this container: `cdkd diff` dereferences the stored bag
|
|
64231
|
+
* BEFORE the walk that fabricates. `resolveTemplateOutputs` asks
|
|
64232
|
+
* `hasOwnProperty.call(storedOutputs, key)` for go-to-k/cdkd#2740's
|
|
64233
|
+
* skipped-output record and for go-to-k/cdkd#1942's literal `Export.Name`
|
|
64234
|
+
* verdict — which ANSWERS TRUE on a string for `'0'` or `'length'`, and THROWS
|
|
64235
|
+
* outright on `null` (`Cannot convert undefined or null to object`). So a guard
|
|
64236
|
+
* written at `computeOutputsDiff` alone leaves a wrong decision, or a raw
|
|
64237
|
+
* `TypeError`, one call above it.
|
|
64238
|
+
*
|
|
64239
|
+
* ABSENT IS EXEMPT AND `null` IS NOT, which is the one place this diverges from
|
|
64240
|
+
* {@link isReadableBag}'s verdict, and the split is measured rather than
|
|
64241
|
+
* stylistic. Both stored-bag lookups named above gate on
|
|
64242
|
+
* `storedOutputs !== undefined` before the `hasOwnProperty` call, so an ABSENT
|
|
64243
|
+
* bag never reaches one; every other consumer on the diff path carries its own
|
|
64244
|
+
* `?? {}` (`mergeNoChangeOutputs`'s `persisted`, `importableOutputKeys`, this
|
|
64245
|
+
* function's own walk). An absent bag is therefore inert, exactly the condition
|
|
64246
|
+
* under which `state.ts`'s `repairRenderedContainers` exempts it — and warning
|
|
64247
|
+
* would be a false positive on a record cdkd itself supports: `cdkd scrub`
|
|
64248
|
+
* round-trips a record with no `outputs` deliberately, refusing to materialize
|
|
64249
|
+
* `{}` over it, and the deploy's failure-path saves write
|
|
64250
|
+
* `outputs: currentState.outputs`, which `JSON.stringify` drops when it is
|
|
64251
|
+
* undefined. A `null` bag is NOT inert — it passes the `!== undefined` gate and
|
|
64252
|
+
* `hasOwnProperty.call(null, ...)` throws — so it is repaired and warned about
|
|
64253
|
+
* like any other unreadable shape.
|
|
64254
|
+
*
|
|
64255
|
+
* That leaves one clause of go-to-k/cdkd#3189's stated floor overridden on
|
|
64256
|
+
* purpose: it asked that a `null` bag "diff exactly as it does today and say
|
|
64257
|
+
* nothing", and diffing exactly as it does today means THROWING. Recorded on
|
|
64258
|
+
* the issue rather than silently traded.
|
|
64259
|
+
*
|
|
64260
|
+
* Mutates in place and returns whether it repaired anything; the caller warns
|
|
64261
|
+
* on `true` with {@link malformedOutputsWarning}. Read-only commands ONLY, for
|
|
64262
|
+
* the reason {@link refuseMalformedState} gives — a bag laundered into a
|
|
64263
|
+
* well-formed empty one is permanent, and for `outputs` it would also take the
|
|
64264
|
+
* exports index with it on the next write.
|
|
64265
|
+
*/
|
|
64266
|
+
function repairMalformedOutputsForReadOnly(state) {
|
|
64267
|
+
if (state.outputs === void 0 || isReadableBag(state.outputs)) return false;
|
|
64268
|
+
state.outputs = {};
|
|
64269
|
+
return true;
|
|
64270
|
+
}
|
|
64271
|
+
/**
|
|
64272
|
+
* The warning a caller of {@link repairMalformedOutputsForReadOnly} emits.
|
|
64273
|
+
*
|
|
64274
|
+
* Deliberately neither {@link malformedResourcesWarning}'s text nor
|
|
64275
|
+
* {@link malformedRenderedContainersWarning}'s, because the CONSEQUENCE of
|
|
64276
|
+
* continuing empty differs from both. The resources text forbids
|
|
64277
|
+
* `cdkd deploy` / `cdkd destroy` because an unreadable resource MAP is
|
|
64278
|
+
* indistinguishable from an empty stack; the resource set is intact here. The
|
|
64279
|
+
* rendered-containers text says the view "shows no rows there" — true of a
|
|
64280
|
+
* renderer, false of a diff, which does not go quiet on an empty stored bag but
|
|
64281
|
+
* reports every resolved output as an `ADD`. Saying so is the point: an
|
|
64282
|
+
* operator who reads `ADD` rows for outputs the stack already has needs to know
|
|
64283
|
+
* the comparison lost its left-hand side.
|
|
64284
|
+
*
|
|
64285
|
+
* Identifiers are sanitized and then shell-quoted and the command is emitted
|
|
64286
|
+
* LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s note gives.
|
|
64287
|
+
*/
|
|
64288
|
+
function malformedOutputsWarning(stackName, region) {
|
|
64289
|
+
const stack = safeIdentifier(stackName);
|
|
64290
|
+
const reg = safeIdentifier(region);
|
|
64291
|
+
return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has no readable 'outputs' map — the record is malformed or truncated. Where the stored value is a string or a list, 'Object.entries' walks it as readily as a map, so diffing it INVENTS a REMOVE row per character or element carrying the record's own characters; where it is a number, a boolean or null, it yields no comparison at all. Continuing with it EMPTY: every output this diff resolves is reported as an ADD and no stored key is reported as a REMOVE, which is not the same as the record holding none. See the stored value with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
|
|
64292
|
+
}
|
|
64293
|
+
/**
|
|
64294
|
+
* For a command that can WRITE state: refuse the record by name instead of
|
|
64295
|
+
* repairing it.
|
|
64296
|
+
*
|
|
64297
|
+
* Repairing is actively DANGEROUS here, and the PR that introduced this module
|
|
64298
|
+
* shipped that danger for one round before its security review caught it.
|
|
64299
|
+
* `cdkd scrub` gates its `saveState` on `recordsChanged > 0`, which an OUTPUTS
|
|
64300
|
+
* change alone satisfies — so a record holding `"resources": null` and a
|
|
64301
|
+
* plaintext secret in `outputs` would be scrubbed, and then saved back with a
|
|
64302
|
+
* repaired, WELL-FORMED `resources: {}`. The malformed record is the only
|
|
64303
|
+
* signal that anything is wrong; laundering it into a legitimate-looking empty
|
|
64304
|
+
* one is permanent and silent. The next `cdkd deploy` then reads zero resources
|
|
64305
|
+
* and CREATES the whole stack a second time, and the next `cdkd destroy`
|
|
64306
|
+
* deletes nothing and orphans every live resource — and the one-shot warning
|
|
64307
|
+
* that would have said so is long gone, quite possibly for a different
|
|
64308
|
+
* operator. `cdkd import --force` launders it the same way.
|
|
64309
|
+
*
|
|
64310
|
+
* Refusing still satisfies #3018, whose complaint was the BARE `TypeError`:
|
|
64311
|
+
* this names the stack, the region, the defect and the remedy, and exits on a
|
|
64312
|
+
* code rather than on a stack trace.
|
|
64313
|
+
*/
|
|
64314
|
+
function refuseMalformedState(state, stackName, region) {
|
|
64315
|
+
if (hasReadableResources(state)) return;
|
|
64316
|
+
throw new CdkdError(malformedStateRefusalMessage(stackName, region), STATE_RESOURCES_MALFORMED);
|
|
64317
|
+
}
|
|
64318
|
+
|
|
64010
64319
|
//#endregion
|
|
64011
64320
|
//#region src/analyzer/outputs-diff.ts
|
|
64012
64321
|
/**
|
|
@@ -64439,7 +64748,7 @@ async function resolveTemplateOutputs(template, resolveFn, conditions, storedOut
|
|
|
64439
64748
|
*/
|
|
64440
64749
|
function computeOutputsDiff(current, desired, exportNames, secretSourceKeys = /* @__PURE__ */ new Set(), unaccountableScan = {}) {
|
|
64441
64750
|
const changes = [];
|
|
64442
|
-
const currentBag = current
|
|
64751
|
+
const currentBag = current !== void 0 && isReadableBag(current) ? current : {};
|
|
64443
64752
|
const legacyRecord = unaccountableScan.forceLegacyRecord === true || Object.entries(currentBag).some(([name, oldValue]) => {
|
|
64444
64753
|
if (typeof oldValue === "string" && isSecretBearingReferenceString(oldValue)) return false;
|
|
64445
64754
|
return containsSecretDynamicReference(desired[name]) || secretSourceKeys.has(name);
|
|
@@ -65405,224 +65714,6 @@ function isStackNotFoundError(err) {
|
|
|
65405
65714
|
return name === "ValidationError" && /does not exist/i.test(message);
|
|
65406
65715
|
}
|
|
65407
65716
|
|
|
65408
|
-
//#endregion
|
|
65409
|
-
//#region src/state/malformed-resources-bag.ts
|
|
65410
|
-
/** The error code every malformed-record refusal carries, whatever its class. */
|
|
65411
|
-
const STATE_RESOURCES_MALFORMED = "STATE_RESOURCES_MALFORMED";
|
|
65412
|
-
/**
|
|
65413
|
-
* Answer the ONE question both helpers below key on: can this record's
|
|
65414
|
-
* resource map be read at all?
|
|
65415
|
-
*
|
|
65416
|
-
* Widened past `null` / `undefined` because the message says "no readable
|
|
65417
|
-
* resources map" and a hand-edited record does not stop at those two: a
|
|
65418
|
-
* `[]`, a `5` or a `"ab"` all survive `Object.entries` and yield a bag that is
|
|
65419
|
-
* empty or, for the string, absurd — repaired silently and warned about
|
|
65420
|
-
* nowhere. The predicate is the plain-object test the bag's own type implies.
|
|
65421
|
-
*/
|
|
65422
|
-
function hasReadableResources(state) {
|
|
65423
|
-
return isReadableBag(state.resources);
|
|
65424
|
-
}
|
|
65425
|
-
/**
|
|
65426
|
-
* The plain-object test itself, without the `resources` field bound to it.
|
|
65427
|
-
*
|
|
65428
|
-
* Exported because {@link hasReadableResources} is not the only caller any
|
|
65429
|
-
* more: `cdkd state show` and `cdkd state resources` walk FOUR more record
|
|
65430
|
-
* containers with `Object.entries` — `outputs`, `skippedOutputs`, and each
|
|
65431
|
-
* resource's `attributes` and `properties` — and a non-object in any of them
|
|
65432
|
-
* fabricates rows exactly as the `resources` bag did (go-to-k/cdkd#3187).
|
|
65433
|
-
* Spelling the same test a second time there is what this export exists to
|
|
65434
|
-
* prevent: the two could then drift, and the one that drifted would fabricate
|
|
65435
|
-
* again while looking guarded.
|
|
65436
|
-
*
|
|
65437
|
-
* What it does NOT decide is whether a given container is malformed. That is a
|
|
65438
|
-
* per-container call, because absence means different things: an absent
|
|
65439
|
-
* `resources` bag is a defect ({@link hasReadableResources} says so), while an
|
|
65440
|
-
* absent `skippedOutputs` is the normal pre-#2740 record. Each caller pairs
|
|
65441
|
-
* this predicate with its own absence rule.
|
|
65442
|
-
*/
|
|
65443
|
-
function isReadableBag(container) {
|
|
65444
|
-
return typeof container === "object" && container !== null && !Array.isArray(container);
|
|
65445
|
-
}
|
|
65446
|
-
/**
|
|
65447
|
-
* The shared explanation, in the terms the reader needs: what is wrong, what
|
|
65448
|
-
* to look at, and what NOT to do next.
|
|
65449
|
-
*
|
|
65450
|
-
* Both identifiers are SANITIZED and THEN SHELL-QUOTED, and the command is
|
|
65451
|
-
* emitted LAST and UNWRAPPED — the shape `lock-contention-message.ts` and
|
|
65452
|
-
* `.claude/rules/layout-state-types.md` require of any suggestion a user is
|
|
65453
|
-
* meant to paste, for two separate reasons.
|
|
65454
|
-
*
|
|
65455
|
-
* Sanitizing alone is not enough. `displaySafe(..., { asciiOnly: true })` is a
|
|
65456
|
-
* printable-ASCII allowlist, so it removes the line- and escape-forgery class
|
|
65457
|
-
* but KEEPS `'`, `;`, `|`, `` ` ``, `$` and spaces — and neither name is
|
|
65458
|
-
* trusted here, since a stack name reaches the cross-stack read path from an
|
|
65459
|
-
* `Fn::GetStackOutput` argument or an S3 key. A name spelled
|
|
65460
|
-
* `a'; curl http://x|sh; echo '` would close the quoting and append its own
|
|
65461
|
-
* command to the line this text tells the user to RUN.
|
|
65462
|
-
*
|
|
65463
|
-
* Wrapping the command in `'...'` is not enough either, and is what makes the
|
|
65464
|
-
* two compose badly: `shellQuote` does its own quoting, so an outer wrapper
|
|
65465
|
-
* produces something unpastable. Hence unwrapped and last.
|
|
65466
|
-
*
|
|
65467
|
-
* An identifier that sanitizes to EMPTY becomes `UNRENDERABLE` rather than
|
|
65468
|
-
* nothing — an empty argument makes `--stack-region` swallow the next flag,
|
|
65469
|
-
* turning a remedy into a differently-broken command.
|
|
65470
|
-
*/
|
|
65471
|
-
function safeIdentifier(value) {
|
|
65472
|
-
const safe = displaySafe(value, { asciiOnly: true });
|
|
65473
|
-
if (!safe) return UNRENDERABLE;
|
|
65474
|
-
const { text, truncated } = truncateCodePoints(safe, 128);
|
|
65475
|
-
return truncated ? `${text}...` : text;
|
|
65476
|
-
}
|
|
65477
|
-
function malformedStateDetail(stackName, region) {
|
|
65478
|
-
const stack = safeIdentifier(stackName);
|
|
65479
|
-
const reg = safeIdentifier(region);
|
|
65480
|
-
return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has no readable 'resources' map — the record is malformed or truncated. Do NOT run 'cdkd deploy' or 'cdkd destroy' against it: both read the same map, and an unreadable one is indistinguishable from an empty stack, so deploy would re-CREATE every resource and destroy would delete none of them. Inspect it with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
|
|
65481
|
-
}
|
|
65482
|
-
/**
|
|
65483
|
-
* For a READ-ONLY command: give the record an empty resource bag so the
|
|
65484
|
-
* command can report on it, and say so (issue go-to-k/cdkd#3018).
|
|
65485
|
-
*
|
|
65486
|
-
* `parseStateBody` deliberately does not validate the inner shape, so a
|
|
65487
|
-
* hand-edited or truncated record reaches a command with `resources` absent,
|
|
65488
|
-
* `null`, or some other non-object. Every such command then died on a raw
|
|
65489
|
-
* `TypeError` from the first `Object.keys` / `in` / index read — the exact
|
|
65490
|
-
* wording differs per shape (`Cannot convert undefined or null to object`,
|
|
65491
|
-
* `Cannot use 'in' operator`, `Cannot read properties of null`), and none of
|
|
65492
|
-
* them names a stack, a key or a remedy, from exactly the commands a user
|
|
65493
|
-
* reaches for WHEN the state is broken.
|
|
65494
|
-
*
|
|
65495
|
-
* WHY AT THE LOAD AND NOT AT EACH LOOP. The first cut of #3018 put `?? {}` on
|
|
65496
|
-
* the twelve `Object.entries(state.resources)` loops, which was inert: every
|
|
65497
|
-
* one of those flows dereferences the bag EARLIER — `!(id in state.resources)`,
|
|
65498
|
-
* `hasOwnProperty.call(...)`, `state.resources[logicalId]` — so the abort still
|
|
65499
|
-
* happened one line up and the guards only made it look handled. One call per
|
|
65500
|
-
* load dominates the whole flow behind it, including the helpers that take the
|
|
65501
|
-
* state as a parameter (`orphan-rewriter`, `diff-calculator`,
|
|
65502
|
-
* `collectCcApiRoutes`).
|
|
65503
|
-
*
|
|
65504
|
-
* Mutates in place and returns whether it repaired anything; the caller warns
|
|
65505
|
-
* on `true`. A silent repair is its own defect — an empty resource set is
|
|
65506
|
-
* indistinguishable from a healthy empty stack in every later line of output,
|
|
65507
|
-
* so `No changes detected` over an unreadable record is a clean verdict about
|
|
65508
|
-
* nothing.
|
|
65509
|
-
*
|
|
65510
|
-
* **Only for a command that cannot WRITE state.** Anything that can persist
|
|
65511
|
-
* uses {@link refuseMalformedState} instead; see its note.
|
|
65512
|
-
*/
|
|
65513
|
-
function repairMalformedResourcesForReadOnly(state) {
|
|
65514
|
-
if (hasReadableResources(state)) return false;
|
|
65515
|
-
state.resources = {};
|
|
65516
|
-
return true;
|
|
65517
|
-
}
|
|
65518
|
-
/**
|
|
65519
|
-
* The refusal TEXT, for a command whose own exit-code contract means this
|
|
65520
|
-
* cannot be a plain `CdkdError`.
|
|
65521
|
-
*
|
|
65522
|
-
* `cdkd scrub` is the case: its exit `1` is SPOKEN FOR ("--fail found
|
|
65523
|
-
* plaintext") and every one of its refusals carries `exitCode = 2`, because a
|
|
65524
|
-
* CI gate reading the code alone must be able to tell "scrub looked and found
|
|
65525
|
-
* a leak" from "scrub refused to look" — the two call for opposite responses.
|
|
65526
|
-
* So scrub tests {@link hasReadableResources} and raises its own class around
|
|
65527
|
-
* this text rather than calling {@link refuseMalformedState}.
|
|
65528
|
-
*
|
|
65529
|
-
* The other three refusing commands do NOT share that need, and giving them a
|
|
65530
|
-
* single shared code would be wrong in the other direction: `cdkd rollback`
|
|
65531
|
-
* documents `2` as "PARTIAL — journal kept, idempotent re-run", so a `2` here
|
|
65532
|
-
* would tell an operator to re-run a command that attempted nothing.
|
|
65533
|
-
*/
|
|
65534
|
-
function malformedStateRefusalMessage(stackName, region) {
|
|
65535
|
-
return `${malformedStateDetail(stackName, region)} This command can WRITE state, so it refuses rather than continuing: saving over a record whose resource map could not be read would replace the evidence with a well-formed empty one and lose it permanently. Repair or remove the record first.`;
|
|
65536
|
-
}
|
|
65537
|
-
/**
|
|
65538
|
-
* The warning a view emits when it emptied one or more {@link
|
|
65539
|
-
* RenderedStateContainer}s it could not walk (go-to-k/cdkd#3187).
|
|
65540
|
-
*
|
|
65541
|
-
* Deliberately NOT {@link malformedResourcesWarning}'s text, and the reason is
|
|
65542
|
-
* narrower than it looks. That one tells the reader not to run `cdkd deploy` /
|
|
65543
|
-
* `cdkd destroy` because an unreadable `resources` MAP is indistinguishable
|
|
65544
|
-
* from an empty stack: deploy would re-CREATE everything and destroy would
|
|
65545
|
-
* delete nothing. No container named here can produce that specific confusion —
|
|
65546
|
-
* the resource SET is still readable — so borrowing that sentence would attach
|
|
65547
|
-
* a re-create-the-world warning to a record whose resource list is intact.
|
|
65548
|
-
*
|
|
65549
|
-
* It is NOT that these containers are display-only. `properties` is read by the
|
|
65550
|
-
* deploy change calculation (`src/analyzer/diff-calculator.ts`), which imports
|
|
65551
|
-
* nothing from this module, and a non-object there compares unequal to any
|
|
65552
|
-
* desired object and yields a spurious property-change set — filed as
|
|
65553
|
-
* go-to-k/cdkd#3191. An earlier revision of this comment asserted the
|
|
65554
|
-
* display-only premise, which would have read as licence to drop a guard on
|
|
65555
|
-
* that path (review of go-to-k/cdkd#3190).
|
|
65556
|
-
*
|
|
65557
|
-
* What stays the same is the remedy: `--json` is the mode that shows the
|
|
65558
|
-
* stored value.
|
|
65559
|
-
*
|
|
65560
|
-
* ONE warning per record however many containers it names — a stack whose 500
|
|
65561
|
-
* resources all carry a hand-edited `properties` gets one line, not 500. The
|
|
65562
|
-
* caller FILTERS a fixed order (`RENDERED_CONTAINER_ORDER`), so the text is
|
|
65563
|
-
* stable across records. Not `.sort()` — that order is deliberately not
|
|
65564
|
-
* alphabetical, and its own JSDoc says so.
|
|
65565
|
-
*
|
|
65566
|
-
* Both identifiers are sanitized and then shell-quoted, and the command is
|
|
65567
|
-
* emitted LAST and UNWRAPPED, for the reasons {@link safeIdentifier}'s own note
|
|
65568
|
-
* gives.
|
|
65569
|
-
*
|
|
65570
|
-
* The container NAMES take {@link safeIdentifier} too — the SAME helper, so
|
|
65571
|
-
* they cannot drift from it — but NOT `shellQuote`, because they appear in the
|
|
65572
|
-
* PROSE and never inside the command this text tells the reader to run; the
|
|
65573
|
-
* command carries the two identifiers and nothing else.
|
|
65574
|
-
*
|
|
65575
|
-
* Sanitizing them is not dead code written for a case that cannot happen. The
|
|
65576
|
-
* union above is closed at COMPILE time, so without this the guarantee would
|
|
65577
|
-
* live in a comment, and the day a caller derives a name from a record instead
|
|
65578
|
-
* of from a literal an unsanitized element could forge a line, render as empty
|
|
65579
|
-
* quotes naming nothing, or run to kilobytes and push the remedy command off
|
|
65580
|
-
* the reader's screen. `safeIdentifier` closes all three and is the identity on
|
|
65581
|
-
* all four literals, so no user-visible text moves.
|
|
65582
|
-
*
|
|
65583
|
-
* What it does NOT close, stated rather than reassured away: a forged name made
|
|
65584
|
-
* only of printable ASCII still renders verbatim inside its quotes and could
|
|
65585
|
-
* read as prose. That residual is bounded to the PROSE — the command the reader
|
|
65586
|
-
* pastes is built from the two shell-quoted identifiers alone — and closing it
|
|
65587
|
-
* would mean JSON-quoting a name in the one place the text is meant to read as
|
|
65588
|
-
* English (review of go-to-k/cdkd#3190).
|
|
65589
|
-
*/
|
|
65590
|
-
function malformedRenderedContainersWarning(stackName, region, containers) {
|
|
65591
|
-
const stack = safeIdentifier(stackName);
|
|
65592
|
-
const reg = safeIdentifier(region);
|
|
65593
|
-
const names = containers.map((name) => `'${safeIdentifier(name)}'`).join(", ");
|
|
65594
|
-
return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has a non-object ${names} — the record is malformed or truncated. 'Object.entries' walks a string or a list as readily as a map, so rendering one INVENTS a row per character or element. Continuing with it EMPTY: this view shows no rows there, which is not the same as the record holding none. A per-resource container is named once however many resources hold one. See the stored values with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
|
|
65595
|
-
}
|
|
65596
|
-
/** The warning a caller of {@link repairMalformedResourcesForReadOnly} emits. */
|
|
65597
|
-
function malformedResourcesWarning(stackName, region) {
|
|
65598
|
-
return `${malformedStateDetail(stackName, region)} Continuing with an EMPTY resource set: this command's output describes zero resources, which is not the same as the stack having none.`;
|
|
65599
|
-
}
|
|
65600
|
-
/**
|
|
65601
|
-
* For a command that can WRITE state: refuse the record by name instead of
|
|
65602
|
-
* repairing it.
|
|
65603
|
-
*
|
|
65604
|
-
* Repairing is actively DANGEROUS here, and the PR that introduced this module
|
|
65605
|
-
* shipped that danger for one round before its security review caught it.
|
|
65606
|
-
* `cdkd scrub` gates its `saveState` on `recordsChanged > 0`, which an OUTPUTS
|
|
65607
|
-
* change alone satisfies — so a record holding `"resources": null` and a
|
|
65608
|
-
* plaintext secret in `outputs` would be scrubbed, and then saved back with a
|
|
65609
|
-
* repaired, WELL-FORMED `resources: {}`. The malformed record is the only
|
|
65610
|
-
* signal that anything is wrong; laundering it into a legitimate-looking empty
|
|
65611
|
-
* one is permanent and silent. The next `cdkd deploy` then reads zero resources
|
|
65612
|
-
* and CREATES the whole stack a second time, and the next `cdkd destroy`
|
|
65613
|
-
* deletes nothing and orphans every live resource — and the one-shot warning
|
|
65614
|
-
* that would have said so is long gone, quite possibly for a different
|
|
65615
|
-
* operator. `cdkd import --force` launders it the same way.
|
|
65616
|
-
*
|
|
65617
|
-
* Refusing still satisfies #3018, whose complaint was the BARE `TypeError`:
|
|
65618
|
-
* this names the stack, the region, the defect and the remedy, and exits on a
|
|
65619
|
-
* code rather than on a stack trace.
|
|
65620
|
-
*/
|
|
65621
|
-
function refuseMalformedState(state, stackName, region) {
|
|
65622
|
-
if (hasReadableResources(state)) return;
|
|
65623
|
-
throw new CdkdError(malformedStateRefusalMessage(stackName, region), STATE_RESOURCES_MALFORMED);
|
|
65624
|
-
}
|
|
65625
|
-
|
|
65626
65717
|
//#endregion
|
|
65627
65718
|
//#region src/cli/commands/diff-recursive.ts
|
|
65628
65719
|
/**
|
|
@@ -65745,6 +65836,7 @@ async function loadStateOrEmpty(stackName, region, stateBackend) {
|
|
|
65745
65836
|
const result = await stateBackend.getState(stackName, region);
|
|
65746
65837
|
if (result) {
|
|
65747
65838
|
if (repairMalformedResourcesForReadOnly(result.state)) logger.warn(malformedResourcesWarning(stackName, region));
|
|
65839
|
+
if (repairMalformedOutputsForReadOnly(result.state)) logger.warn(malformedOutputsWarning(stackName, region));
|
|
65748
65840
|
return result.state;
|
|
65749
65841
|
}
|
|
65750
65842
|
return {
|
|
@@ -93736,4 +93828,4 @@ function buildProgram() {
|
|
|
93736
93828
|
|
|
93737
93829
|
//#endregion
|
|
93738
93830
|
export { buildProgram };
|
|
93739
|
-
//# sourceMappingURL=program-
|
|
93831
|
+
//# sourceMappingURL=program-DUCNL9hK.js.map
|