@go-to-k/cdkd 0.116.0 → 0.117.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/cli.js CHANGED
@@ -6434,11 +6434,14 @@ var LambdaFunctionProvider = class {
6434
6434
  * etc.) are filtered at compare time — we still avoid serializing them on
6435
6435
  * the wire.
6436
6436
  *
6437
- * `Code` is intentionally omitted: `GetFunction` returns a pre-signed S3
6438
- * URL for the deployed code, not the asset hash cdkd state holds, so they
6439
- * could never match. Lambda code drift is best detected separately (the
6440
- * function's `CodeSha256` does live in `GetFunction` but is not what
6441
- * cdkd's `Code: { S3Bucket, S3Key }` state property carries).
6437
+ * `Code.S3Bucket` / `Code.S3Key` / `Code.S3ObjectVersion` / `Code.ZipFile`
6438
+ * are not surfaced: `GetFunction` returns a pre-signed S3 URL for the
6439
+ * deployed code, not the asset hash cdkd state holds, so they could
6440
+ * never match. Those keys are declared via `getDriftUnknownPaths` so
6441
+ * the drift comparator skips them. `Code.ImageUri` IS surfaced for
6442
+ * container Lambdas (`PackageType: 'Image'`) — AWS returns it on the
6443
+ * `GetFunction.Code.ImageUri` field, so a console-side image swap is
6444
+ * detectable as drift.
6442
6445
  *
6443
6446
  * `Tags` is surfaced from the `Tags` map on the same `GetFunction`
6444
6447
  * response. CDK's auto-injected `aws:cdk:*` tags (which AWS happily
@@ -6467,6 +6470,7 @@ var LambdaFunctionProvider = class {
6467
6470
  result["Layers"] = (cfg.Layers ?? []).map((l) => l.Arn).filter((arn) => !!arn);
6468
6471
  result["Architectures"] = cfg.Architectures ? [...cfg.Architectures] : [];
6469
6472
  if (cfg.PackageType !== void 0) result["PackageType"] = cfg.PackageType;
6473
+ if (resp.Code?.ImageUri !== void 0) result["Code"] = { ImageUri: resp.Code.ImageUri };
6470
6474
  result["TracingConfig"] = { Mode: cfg.TracingConfig?.Mode ?? "PassThrough" };
6471
6475
  if (cfg.EphemeralStorage?.Size !== void 0) result["EphemeralStorage"] = { Size: cfg.EphemeralStorage.Size };
6472
6476
  result["VpcConfig"] = {
@@ -6482,15 +6486,30 @@ var LambdaFunctionProvider = class {
6482
6486
  }
6483
6487
  }
6484
6488
  /**
6485
- * `Code: { S3Bucket, S3Key }` is set on create / update but `GetFunction`
6486
- * only returns a pre-signed URL for the deployed code, never the original
6487
- * asset key — so a state-recorded `Code` value can never match an
6488
- * AWS-current snapshot. Tell the drift comparator to skip the whole
6489
- * `Code` subtree to avoid the guaranteed false-positive that would fire
6490
- * on every clean run.
6489
+ * Lambda ZIP-package `Code` sub-paths AWS does not return on read.
6490
+ *
6491
+ * `GetFunction` returns a pre-signed S3 URL for ZIP-deployed code
6492
+ * (`Code.Location`), not the original `S3Bucket` / `S3Key` cdkd state
6493
+ * holds. `ZipFile` is inline source that AWS never echoes back. These
6494
+ * three fields are write-only via the GetFunction API (Category 1).
6495
+ *
6496
+ * `Code.ImageUri` IS recoverable — `GetFunction.Code.ImageUri` returns
6497
+ * the templated image URI for container Lambdas — so it is surfaced by
6498
+ * `readCurrentState` and NOT declared drift-unknown. `Code.SourceKMSKeyArn`
6499
+ * is also write-only on the FunctionCodeLocation read shape.
6500
+ *
6501
+ * Pre-PR this method returned the whole `['Code']` subtree as
6502
+ * drift-unknown, which also hid `Code.ImageUri` drift on container
6503
+ * Lambdas. Narrowing the skip-list re-enables that detection.
6491
6504
  */
6492
6505
  getDriftUnknownPaths() {
6493
- return ["Code"];
6506
+ return [
6507
+ "Code.S3Bucket",
6508
+ "Code.S3Key",
6509
+ "Code.S3ObjectVersion",
6510
+ "Code.ZipFile",
6511
+ "Code.SourceKMSKeyArn"
6512
+ ];
6494
6513
  }
6495
6514
  /**
6496
6515
  * Adopt an existing Lambda function into cdkd state.
@@ -35764,6 +35783,7 @@ function extractLambdaProperties(stack, logicalId, resource, resources) {
35764
35783
  const props = resource.Properties ?? {};
35765
35784
  const memoryMb = typeof props["MemorySize"] === "number" ? props["MemorySize"] : 128;
35766
35785
  const timeoutSec = typeof props["Timeout"] === "number" ? props["Timeout"] : 3;
35786
+ const ephemeralStorageMb = extractEphemeralStorageMb(props, logicalId);
35767
35787
  const code = props["Code"] ?? {};
35768
35788
  const imageUri = extractImageUri(code["ImageUri"], logicalId, stack.stackName, resources);
35769
35789
  if (imageUri !== void 0) return extractImageLambdaProperties({
@@ -35773,7 +35793,8 @@ function extractLambdaProperties(stack, logicalId, resource, resources) {
35773
35793
  memoryMb,
35774
35794
  timeoutSec,
35775
35795
  props,
35776
- imageUri
35796
+ imageUri,
35797
+ ...ephemeralStorageMb !== void 0 && { ephemeralStorageMb }
35777
35798
  });
35778
35799
  const runtime = typeof props["Runtime"] === "string" ? props["Runtime"] : "";
35779
35800
  const handler = typeof props["Handler"] === "string" ? props["Handler"] : "";
@@ -35794,10 +35815,44 @@ function extractLambdaProperties(stack, logicalId, resource, resources) {
35794
35815
  timeoutSec,
35795
35816
  codePath,
35796
35817
  layers,
35818
+ ...ephemeralStorageMb !== void 0 && { ephemeralStorageMb },
35797
35819
  ...inlineCode !== void 0 && { inlineCode }
35798
35820
  };
35799
35821
  }
35800
35822
  /**
35823
+ * Parse `Properties.EphemeralStorage.Size` (issue #440). CFn shape:
35824
+ * `{ EphemeralStorage: { Size: <MiB> } }`. CDK's
35825
+ * `cdk.Size.gibibytes(N)` serializes to `N * 1024`. AWS-side range is
35826
+ * 512..10240 MiB (the deployed function rejects anything outside that
35827
+ * range at create time); cdkd rejects > 10240 here so a misconfigured
35828
+ * template fails fast at `cdkd local invoke` boot rather than hanging
35829
+ * on a `docker run` that AWS would have refused anyway. The 512 floor
35830
+ * is AWS's minimum (the default when `EphemeralStorage` is omitted is
35831
+ * also 512), but we deliberately accept values DOWN to 1 so users can
35832
+ * exercise the cap with a deliberately-small `/tmp` in local tests —
35833
+ * `--tmpfs /tmp:size=Nm` itself enforces no lower bound; the only
35834
+ * cross-check is "would AWS accept this?", which the deploy side
35835
+ * already gates upstream.
35836
+ *
35837
+ * Returns `undefined` when the property is absent, NaN, < 1, or
35838
+ * non-numeric. Hard-rejects > 10240. Intrinsic-valued sizes (the
35839
+ * `{ Ref: 'SomeParam' }` shape that's uncommon for EphemeralStorage
35840
+ * but theoretically valid) drop to `undefined` with a one-line warn
35841
+ * via the calling logger — local invoke can't resolve those without
35842
+ * the template's Parameters context the deploy engine has, and the
35843
+ * fallback (no `--tmpfs`) is safer than guessing.
35844
+ */
35845
+ function extractEphemeralStorageMb(props, logicalId) {
35846
+ const raw = props["EphemeralStorage"];
35847
+ if (raw === void 0 || raw === null) return void 0;
35848
+ if (typeof raw !== "object" || Array.isArray(raw)) return void 0;
35849
+ const size = raw["Size"];
35850
+ if (typeof size !== "number") return;
35851
+ if (!Number.isFinite(size) || size < 1) return void 0;
35852
+ if (size > 10240) throw new LocalInvokeResolutionError(`Lambda '${logicalId}' has Properties.EphemeralStorage.Size = ${size} MiB, which exceeds the AWS limit of 10240 MiB. AWS would reject the function at deploy time; cap the value to <= 10240 (10 GiB) and retry.`);
35853
+ return Math.floor(size);
35854
+ }
35855
+ /**
35801
35856
  * Extract the `Code.ImageUri` value across the shapes CDK actually synthesizes.
35802
35857
  *
35803
35858
  * Supported shapes:
@@ -35849,7 +35904,7 @@ function extractImageUri(value, logicalId, stackName, resources) {
35849
35904
  * optional in CFn — the defaults match the AWS-side defaults.
35850
35905
  */
35851
35906
  function extractImageLambdaProperties(args) {
35852
- const { stack, logicalId, resource, memoryMb, timeoutSec, props, imageUri } = args;
35907
+ const { stack, logicalId, resource, memoryMb, timeoutSec, ephemeralStorageMb, props, imageUri } = args;
35853
35908
  const rawImageConfig = props["ImageConfig"] ?? {};
35854
35909
  const imageConfig = {};
35855
35910
  if (Array.isArray(rawImageConfig["Command"])) imageConfig.command = rawImageConfig["Command"].filter((s) => typeof s === "string");
@@ -35873,7 +35928,8 @@ function extractImageLambdaProperties(args) {
35873
35928
  imageUri,
35874
35929
  imageConfig,
35875
35930
  architecture,
35876
- layers: []
35931
+ layers: [],
35932
+ ...ephemeralStorageMb !== void 0 && { ephemeralStorageMb }
35877
35933
  };
35878
35934
  }
35879
35935
  /**
@@ -37413,6 +37469,7 @@ async function runDetached(opts) {
37413
37469
  args.push("-v", `${mount.hostPath}:${mount.containerPath}${ro}`);
37414
37470
  }
37415
37471
  for (const [k, v] of Object.entries(opts.env)) args.push("-e", `${k}=${v}`);
37472
+ if (opts.tmpfs) args.push("--tmpfs", `${opts.tmpfs.target}:rw,size=${opts.tmpfs.sizeMb}m`);
37416
37473
  if (opts.workingDir) args.push("--workdir", opts.workingDir);
37417
37474
  let entryPointTail = [];
37418
37475
  if (opts.entryPoint && opts.entryPoint.length > 0) {
@@ -38863,7 +38920,8 @@ function createContainerPool(specs, options) {
38863
38920
  hostPort,
38864
38921
  host: spec.containerHost,
38865
38922
  name,
38866
- ...spec.debugPort !== void 0 && { debugPort: spec.debugPort }
38923
+ ...spec.debugPort !== void 0 && { debugPort: spec.debugPort },
38924
+ ...spec.tmpfs !== void 0 && { tmpfs: spec.tmpfs }
38867
38925
  });
38868
38926
  const stopLogStream = streamingEnabled ? streamLogs(containerId) : () => void 0;
38869
38927
  try {
@@ -42294,13 +42352,18 @@ async function buildContainerSpec(args) {
42294
42352
  if (stsRegion) dockerEnv["AWS_REGION"] = stsRegion;
42295
42353
  } else forwardAwsEnv$1(dockerEnv);
42296
42354
  if (debugPort !== void 0) dockerEnv["NODE_OPTIONS"] = `--inspect-brk=0.0.0.0:${debugPort}`;
42355
+ const tmpfs = lambda.ephemeralStorageMb !== void 0 ? {
42356
+ target: "/tmp",
42357
+ sizeMb: lambda.ephemeralStorageMb
42358
+ } : void 0;
42297
42359
  return {
42298
42360
  lambda,
42299
42361
  codeDir,
42300
42362
  env: dockerEnv,
42301
42363
  containerHost,
42302
42364
  ...optDir !== void 0 && { optDir },
42303
- ...debugPort !== void 0 && { debugPort }
42365
+ ...debugPort !== void 0 && { debugPort },
42366
+ ...tmpfs !== void 0 && { tmpfs }
42304
42367
  };
42305
42368
  }
42306
42369
  /**
@@ -42352,6 +42415,7 @@ function resolveLambdaByLogicalId(logicalId, stacks) {
42352
42415
  let codePath = null;
42353
42416
  if (!inlineCode) codePath = resolveAssetCodePath(stack, logicalId, resource);
42354
42417
  const layers = resolveLambdaLayers(stack, logicalId, props);
42418
+ const ephemeralStorageMb = extractEphemeralStorageMb(props, logicalId);
42355
42419
  return {
42356
42420
  kind: "zip",
42357
42421
  stack,
@@ -42363,7 +42427,8 @@ function resolveLambdaByLogicalId(logicalId, stacks) {
42363
42427
  timeoutSec,
42364
42428
  codePath,
42365
42429
  layers,
42366
- ...inlineCode !== void 0 && { inlineCode }
42430
+ ...inlineCode !== void 0 && { inlineCode },
42431
+ ...ephemeralStorageMb !== void 0 && { ephemeralStorageMb }
42367
42432
  };
42368
42433
  }
42369
42434
  throw new Error(`No AWS::Lambda::Function resource named '${logicalId}' found in target stacks. This is likely a synthesis bug — the route-discovery phase resolved a route to this logical ID.`);
@@ -43921,7 +43986,8 @@ async function localInvokeCommand(target, options) {
43921
43986
  ...debugPort !== void 0 && { debugPort },
43922
43987
  ...imagePlan.platform !== void 0 && { platform: imagePlan.platform },
43923
43988
  ...imagePlan.entryPoint !== void 0 && { entryPoint: imagePlan.entryPoint },
43924
- ...imagePlan.workingDir !== void 0 && { workingDir: imagePlan.workingDir }
43989
+ ...imagePlan.workingDir !== void 0 && { workingDir: imagePlan.workingDir },
43990
+ ...imagePlan.tmpfs !== void 0 && { tmpfs: imagePlan.tmpfs }
43925
43991
  });
43926
43992
  stopLogs = streamLogs(containerId);
43927
43993
  sigintHandler = () => {
@@ -43968,6 +44034,7 @@ async function resolveZipImagePlan(lambda, options) {
43968
44034
  await pullImage(image, options.pull === false);
43969
44035
  const layerPlan = materializeLambdaLayers(lambda.layers);
43970
44036
  const containerCodePath = resolveRuntimeCodeMountPath(lambda.runtime);
44037
+ const tmpfs = resolveTmpfsForLambda(lambda);
43971
44038
  return {
43972
44039
  image,
43973
44040
  mounts: [{
@@ -43978,7 +44045,36 @@ async function resolveZipImagePlan(lambda, options) {
43978
44045
  extraMounts: layerPlan.mount ? [layerPlan.mount] : [],
43979
44046
  cmd: [lambda.handler],
43980
44047
  ...inlineTmpDir !== void 0 && { inlineTmpDir },
43981
- ...layerPlan.tmpDir !== void 0 && { layersTmpDir: layerPlan.tmpDir }
44048
+ ...layerPlan.tmpDir !== void 0 && { layersTmpDir: layerPlan.tmpDir },
44049
+ ...tmpfs !== void 0 && { tmpfs }
44050
+ };
44051
+ }
44052
+ /**
44053
+ * Build the `--tmpfs /tmp:rw,size=<N>m` plan for a Lambda (issue #440).
44054
+ *
44055
+ * The shape is identical for ZIP and IMAGE Lambdas — `--tmpfs` overlays
44056
+ * mount-time inside any container, regardless of whether the image is a
44057
+ * public Lambda base image (ZIP path) or a user-built container Lambda.
44058
+ * Returns `undefined` when the template did not declare
44059
+ * `EphemeralStorage`, in which case the caller emits no `--tmpfs` flag
44060
+ * and the container's `/tmp` is whatever the base image provides
44061
+ * (matches pre-#440 behavior). The lambda-resolver's
44062
+ * `extractEphemeralStorageMb` already enforces the AWS 10240 MiB
44063
+ * ceiling at parse time.
44064
+ *
44065
+ * Target path is always `/tmp` — AWS Lambda's `/tmp` is the ONLY
44066
+ * sized-tmpfs surface the `EphemeralStorage.Size` property controls,
44067
+ * and the constant is centralized here so a future fixture / docs
44068
+ * update has a single grep target.
44069
+ */
44070
+ function resolveTmpfsForLambda(lambda) {
44071
+ if (lambda.ephemeralStorageMb === void 0) return void 0;
44072
+ const logger = getLogger();
44073
+ if (lambda.kind === "image") logger.info(`Lambda ${lambda.logicalId}: capping /tmp at ${lambda.ephemeralStorageMb} MiB via --tmpfs (overlays any base-image /tmp content)`);
44074
+ else logger.debug(`Lambda ${lambda.logicalId}: applying EphemeralStorage cap via --tmpfs /tmp:size=${lambda.ephemeralStorageMb}m`);
44075
+ return {
44076
+ target: "/tmp",
44077
+ sizeMb: lambda.ephemeralStorageMb
43982
44078
  };
43983
44079
  }
43984
44080
  /**
@@ -44046,6 +44142,7 @@ async function resolveContainerImagePlan(lambda, options) {
44046
44142
  ...options.region !== void 0 && { region: options.region }
44047
44143
  });
44048
44144
  }
44145
+ const tmpfs = resolveTmpfsForLambda(lambda);
44049
44146
  return {
44050
44147
  image: imageRef,
44051
44148
  mounts: [],
@@ -44053,7 +44150,8 @@ async function resolveContainerImagePlan(lambda, options) {
44053
44150
  cmd: lambda.imageConfig.command ?? [],
44054
44151
  platform,
44055
44152
  ...lambda.imageConfig.entryPoint && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
44056
- ...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory }
44153
+ ...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory },
44154
+ ...tmpfs !== void 0 && { tmpfs }
44057
44155
  };
44058
44156
  }
44059
44157
  /**
@@ -45623,7 +45721,7 @@ function reorderArgs(argv) {
45623
45721
  */
45624
45722
  async function main() {
45625
45723
  const program = new Command();
45626
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.116.0");
45724
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.117.0");
45627
45725
  program.addCommand(createBootstrapCommand());
45628
45726
  program.addCommand(createSynthCommand());
45629
45727
  program.addCommand(createListCommand());