@go-to-k/cdkd 0.262.0 → 0.262.1

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.
@@ -3906,13 +3906,22 @@ function cacheOptionToFlag(option) {
3906
3906
  */
3907
3907
  const loggedInRegistries = /* @__PURE__ */ new Set();
3908
3908
  /**
3909
+ * Whether a `docker push` failure looks like an ECR authentication failure
3910
+ * (missing / stale / expired credential) rather than a network / repo / other
3911
+ * error. Case-insensitive. Used by the lazy-login path to decide whether to
3912
+ * log in and retry — a NON-auth failure is surfaced unchanged, never retried.
3913
+ */
3914
+ function isDockerAuthFailure(errText) {
3915
+ return /no basic auth credentials|unauthorized|authentication required|denied|\b401\b|\b403\b/i.test(errText);
3916
+ }
3917
+ /**
3909
3918
  * Publishes Docker image assets to ECR
3910
3919
  *
3911
3920
  * Handles:
3912
3921
  * - Placeholder resolution
3913
3922
  * - Existence check (skip if already pushed)
3914
3923
  * - docker build with Dockerfile, build args, target
3915
- * - ECR authentication
3924
+ * - lazy ECR authentication (push first, log in only on an auth failure)
3916
3925
  * - docker tag + docker push
3917
3926
  */
3918
3927
  var DockerAssetPublisher = class {
@@ -3935,10 +3944,8 @@ var DockerAssetPublisher = class {
3935
3944
  }
3936
3945
  const localTag = `cdkd-asset-${assetHash}`;
3937
3946
  await this.buildImage(asset, cdkOutputDir, localTag);
3938
- await this.ecrLogin(client, accountId, destRegion);
3939
3947
  const fullUri = `${accountId}.dkr.ecr.${destRegion}.amazonaws.com/${repositoryName}:${imageTag}`;
3940
- await this.tagImage(localTag, fullUri);
3941
- await this.pushImage(fullUri);
3948
+ await this.tagAndPushWithLazyLogin(client, localTag, fullUri, accountId, destRegion);
3942
3949
  this.logger.debug(`✅ Published: ${ecrUri}`);
3943
3950
  } finally {
3944
3951
  client.destroy();
@@ -3972,10 +3979,8 @@ var DockerAssetPublisher = class {
3972
3979
  this.logger.debug(`Image already exists, skipping: ${ecrUri}`);
3973
3980
  continue;
3974
3981
  }
3975
- await this.ecrLogin(client, accountId, destRegion);
3976
3982
  const fullUri = `${accountId}.dkr.ecr.${destRegion}.amazonaws.com/${repositoryName}:${imageTag}`;
3977
- await this.tagImage(localTag, fullUri);
3978
- await this.pushImage(fullUri);
3983
+ await this.tagAndPushWithLazyLogin(client, localTag, fullUri, accountId, destRegion);
3979
3984
  this.logger.debug(`✅ Published: ${ecrUri}`);
3980
3985
  } finally {
3981
3986
  client.destroy();
@@ -4025,6 +4030,41 @@ var DockerAssetPublisher = class {
4025
4030
  }
4026
4031
  }
4027
4032
  /**
4033
+ * Tag then push an image, logging in to ECR lazily — only if the push fails
4034
+ * with an auth-failure signature.
4035
+ *
4036
+ * cdkd (like `cdk --hotswap`) leans on the developer's persistent docker
4037
+ * credential store: a valid ECR credential (`~/.docker/config.json` /
4038
+ * keychain; ECR tokens live ~12h) left by an earlier login this session lets
4039
+ * a fresh cdkd process push with NO `GetAuthorizationToken` + `docker login`
4040
+ * round-trip (~3.3s saved). We attempt the push FIRST and only pay the login
4041
+ * when it is actually needed:
4042
+ *
4043
+ * 1. If this PROCESS already logged into the registry (issue #1184 cache),
4044
+ * push directly — still self-healing: a mid-process token expiry falls
4045
+ * into the same auth-failure retry below.
4046
+ * 2. Otherwise push optimistically. On a NON-auth failure (network,
4047
+ * repo-not-found, etc.) surface the error unchanged. On an auth failure
4048
+ * (no pre-existing cred, OR a stale/expired cred), run a forced ECR
4049
+ * login and retry the push ONCE.
4050
+ *
4051
+ * A stale cred and a missing cred take the SAME branch, so cdkd never
4052
+ * fail-hard on an expired credential — it re-logs in and retries.
4053
+ */
4054
+ async tagAndPushWithLazyLogin(client, localTag, fullUri, accountId, region) {
4055
+ await this.tagImage(localTag, fullUri);
4056
+ try {
4057
+ await this.pushImage(fullUri);
4058
+ return;
4059
+ } catch (err) {
4060
+ const e = err;
4061
+ if (!isDockerAuthFailure(e.stderr || e.message || String(err))) throw err;
4062
+ this.logger.debug(`Docker push to ${fullUri} failed with an auth error; logging in to ECR and retrying`);
4063
+ }
4064
+ await this.ecrLogin(client, accountId, region, { force: true });
4065
+ await this.pushImage(fullUri);
4066
+ }
4067
+ /**
4028
4068
  * Authenticate with ECR via `docker login --password-stdin`.
4029
4069
  *
4030
4070
  * The login is cached per registry (`<accountId>.dkr.ecr.<region>`) for the
@@ -4033,10 +4073,14 @@ var DockerAssetPublisher = class {
4033
4073
  * (mirrors `cdk-assets`). ECR tokens are valid ~12h and a deploy process is
4034
4074
  * short-lived, so this is safe. Keyed per registry so cross-account /
4035
4075
  * cross-region assets each get their own login.
4076
+ *
4077
+ * `force: true` bypasses the per-process cache short-circuit — used by the
4078
+ * lazy-login retry after a push fails auth, where the cached entry may hold a
4079
+ * token that AWS has already expired.
4036
4080
  */
4037
- async ecrLogin(client, accountId, region) {
4081
+ async ecrLogin(client, accountId, region, options = {}) {
4038
4082
  const registryKey = `${accountId}.dkr.ecr.${region}.amazonaws.com`;
4039
- if (loggedInRegistries.has(registryKey)) {
4083
+ if (!options.force && loggedInRegistries.has(registryKey)) {
4040
4084
  this.logger.debug(`Reusing cached ECR login for ${registryKey}`);
4041
4085
  return;
4042
4086
  }
@@ -11125,7 +11169,7 @@ var CloudControlProvider = class {
11125
11169
  this.logger.debug(`Deleting resource ${logicalId} (${resourceType}), physical ID: ${physicalId}`);
11126
11170
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
11127
11171
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
11128
- const { ASGProvider } = await import("./asg-provider-Dk8OwSXQ.js").then((n) => n.n);
11172
+ const { ASGProvider } = await import("./asg-provider-D85MbFl6.js").then((n) => n.n);
11129
11173
  await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
11130
11174
  return;
11131
11175
  }
@@ -17866,4 +17910,4 @@ var DeployEngine = class {
17866
17910
 
17867
17911
  //#endregion
17868
17912
  export { getBootstrapMarkerKey as $, formatError as $t, refStateLookupFromResource as A, resolveBucketRegion as At, S3StateBackend as B, LocalMigrateError as Bt, findActionableSilentDrops as C, CFN_TEMPLATE_URL_LIMIT as Ct, isTerminationProtectionPropagationError as D, expectedOwnerParam as Dt, disableInstanceApiTermination as E, uploadCfnTemplate as Et, applyRoleArnIfSet as F, AssetError as Ft, WorkGraph as G, PartialFailureError as Gt, shouldRetainResource as H, LockError as Ht, DiffCalculator as I, CdkdError as It, loadPublishableAssetManifest as J, ResourceUpdateNotSupportedError as Jt, buildAssetRedirectMap as K, ProvisioningError as Kt, DagBuilder as L, ConfigError as Lt, normalizeAwsTagsToCfn as M, getAwsClients as Mt, resolveExplicitPhysicalId as N, resetAwsClients as Nt, IntrinsicFunctionResolver as O, AssemblyReader as Ot, assertRegionMatch as P, setAwsClients as Pt, ensureAssetStorage as Q, SynthesisError as Qt, TemplateParser as R, DependencyError as Rt, ProviderRegistry as S, CFN_TEMPLATE_BODY_LIMIT as St, slowCcOperationTimeoutMs as T, findLargeInlineResources as Tt, AssetPublisher as U, MissingCdkCliError as Ut, rebuildClientForBucketRegion as V, LocalStartServiceError as Vt, stringifyValue as W, NestedStackChildDirectDestroyError as Wt, AssetModeResolver as X, StackTerminationProtectionError as Xt, rewriteTemplateAssetReferences as Y, StackHasActiveImportsError as Yt, BOOTSTRAP_MARKER_PREFIX as Z, StateError as Zt, green as _, resolveSkipPrefix as _t, withRetry as a, getDockerCmd as at, IAMRoleProvider as b, resolveUseCdkBootstrapAssets as bt, computeImplicitDeleteEdges as c, AssetManifestLoader as ct, isStatefulRecreateTargetSync as d, synthesisStatusMessage as dt, isCdkdError as en, parseBootstrapMarker as et, renderStatefulReason as f, getDefaultStateBucketName as ft, gray as g, resolveCaptureObservedState as gt, cyan as h, resolveAutoAssetStorage as ht, withResourceDeadline as i, formatDockerLoginError as it, WAFv2WebACLProvider as j, AwsClients as jt, cfnRefValueFromPhysicalId as k, clearBucketRegionCache as kt, extractDeploymentEventError as l, getDockerImageBySourceHash as lt, bold as m, resolveApp as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, withErrorHandling as nn, validateContainerRepoName as nt, isRetryableTransientError as o, runDockerForeground as ot, formatResourceLine as p, getLegacyStateBucketName as pt, createAssetRedirectResolver as q, ResourceTimeoutError as qt, DeployEngine as r, __exportAll as rn, buildDockerImage as rt, IMPLICIT_DELETE_DEPENDENCIES as s, runDockerStreaming as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, normalizeAwsError as tn, validateAssetBucketName as tt, MULTI_REGION_RECREATE_BLOCKED_TYPES as u, Synthesizer as ut, red as v, resolveStateBucketWithDefault as vt, CloudControlProvider as w, MIGRATE_TMP_PREFIX as wt, collectInlinePolicyNamesManagedBySiblings as x, warnDeprecatedNoPrefixCliFlag as xt, yellow as y, resolveStateBucketWithDefaultAndSource as yt, LockManager as z, LocalInvokeBuildError as zt };
17869
- //# sourceMappingURL=deploy-engine-BiwL0VId.js.map
17913
+ //# sourceMappingURL=deploy-engine-DbhK2y6L.js.map