cdk-local 0.168.0 → 0.168.2

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.
@@ -16,7 +16,7 @@ import { GetParameterCommand, GetParametersCommand, SSMClient } from "@aws-sdk/c
16
16
  import { unzipSync } from "fflate";
17
17
  import { MultiSelectPrompt } from "@clack/core";
18
18
  import { S_BAR, S_BAR_END, S_BAR_START, S_CHECKBOX_ACTIVE, S_CHECKBOX_INACTIVE, S_CHECKBOX_SELECTED, confirm, isCancel, multiselect, select, spinner, text } from "@clack/prompts";
19
- import { CloudFormationClient, DescribeStacksCommand, ListExportsCommand, ListStackResourcesCommand } from "@aws-sdk/client-cloudformation";
19
+ import { CloudFormationClient, DescribeStacksCommand, GetTemplateCommand, ListExportsCommand, ListStackResourcesCommand } from "@aws-sdk/client-cloudformation";
20
20
  import { GetFunctionConfigurationCommand, LambdaClient } from "@aws-sdk/client-lambda";
21
21
  import { BedrockAgentCoreControlClient, GetAgentRuntimeCommand } from "@aws-sdk/client-bedrock-agentcore-control";
22
22
  import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
@@ -5449,6 +5449,319 @@ async function resolveSsmParameters(client, refs, label) {
5449
5449
  return out;
5450
5450
  }
5451
5451
 
5452
+ // src/local/secret-attributes.ts
5453
+ const SECRET_ATTRIBUTE_NAME = /secret|password|credential/i;
5454
+ const NON_SECRET_ATTRIBUTE_SUFFIX = /(arn|id|name|url|alias|status)$/i;
5455
+ const SECRET_VALUED_ATTRIBUTES = /* @__PURE__ */ new Map([
5456
+ ["AWS::AppSync::ApiKey", ["ApiKey", "ApiKeyId"]],
5457
+ ["AWS::EC2::IpamExternalResourceVerificationToken", ["TokenValue"]],
5458
+ ["AWS::IVS::StreamKey", ["Value"]]
5459
+ ]);
5460
+ function isSecretAttributeName(attribute) {
5461
+ return SECRET_ATTRIBUTE_NAME.test(attribute) && !NON_SECRET_ATTRIBUTE_SUFFIX.test(attribute);
5462
+ }
5463
+ function isSecretValuedAttribute(resourceType, attribute) {
5464
+ if (typeof resourceType !== "string") return false;
5465
+ return SECRET_VALUED_ATTRIBUTES.get(resourceType)?.includes(attribute) === true;
5466
+ }
5467
+ function isCustomResourceType(resourceType) {
5468
+ return typeof resourceType === "string" && (resourceType.startsWith("Custom::") || resourceType === "AWS::CloudFormation::CustomResource");
5469
+ }
5470
+
5471
+ // src/local/cfn-producer-secrets.ts
5472
+ const SEGMENT_SUBSTRING_FLOOR = 4;
5473
+ const NAMED_LEAF_EXACT_FLOOR = 8;
5474
+ const NAMED_LEAF_FLOOR = 16;
5475
+ const MAX_DEPTH = 32;
5476
+ const MAX_STACKS = 256;
5477
+ const APPSYNC_ARN = /^arn:[^:]+:appsync:[^:]*:[^:]*:(.+)$/;
5478
+ const APPSYNC_APIKEY_PATH = /^apis\/([^/|]+)\/apikeys?\/([^/|]+)$/;
5479
+ function secretPhysicalIdSegment(resourceType, physicalId) {
5480
+ if (resourceType !== "AWS::AppSync::ApiKey") return void 0;
5481
+ if (typeof physicalId !== "string" || physicalId === "") return void 0;
5482
+ const parts = physicalId.split("|");
5483
+ if (parts.length === 2 && parts[0] !== "" && parts[1] !== "") return parts[1];
5484
+ const arn = APPSYNC_ARN.exec(physicalId);
5485
+ const path = arn ? APPSYNC_APIKEY_PATH.exec(arn[1]) : null;
5486
+ return path ? path[2] : physicalId;
5487
+ }
5488
+ function holds(value, needle, floor) {
5489
+ return value === needle || needle.length >= floor && value.includes(needle);
5490
+ }
5491
+ const isPlaintext = (v) => v !== "" && v !== "***" && !v.includes("{{resolve:");
5492
+ const isRecord = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
5493
+ var CfnProducerSecretJudge = class CfnProducerSecretJudge {
5494
+ client;
5495
+ listResources;
5496
+ exports;
5497
+ label;
5498
+ resourceReads = /* @__PURE__ */ new Map();
5499
+ outputReads = /* @__PURE__ */ new Map();
5500
+ templateReads = /* @__PURE__ */ new Map();
5501
+ summaries = /* @__PURE__ */ new Map();
5502
+ constructor(client, exports, label, listResources) {
5503
+ this.client = client;
5504
+ this.listResources = listResources;
5505
+ this.exports = exports;
5506
+ this.label = label;
5507
+ }
5508
+ async judgeExport(exportName, served) {
5509
+ let summary = this.summaries.get(exportName);
5510
+ if (summary === void 0) {
5511
+ summary = this.summarize(exportName);
5512
+ this.summaries.set(exportName, summary);
5513
+ }
5514
+ return verdictOf(await summary, served);
5515
+ }
5516
+ async summarize(exportName) {
5517
+ const walk = {
5518
+ summary: {
5519
+ segments: /* @__PURE__ */ new Set(),
5520
+ typed: /* @__PURE__ */ new Set(),
5521
+ named: /* @__PURE__ */ new Set(),
5522
+ opaque: void 0,
5523
+ stale: false
5524
+ },
5525
+ stacks: /* @__PURE__ */ new Set(),
5526
+ exports: /* @__PURE__ */ new Set()
5527
+ };
5528
+ await this.addExport(exportName, walk, 0, true);
5529
+ return walk.summary;
5530
+ }
5531
+ static opaque(walk, why) {
5532
+ walk.summary.opaque ??= why;
5533
+ }
5534
+ async addExport(name, walk, depth, top) {
5535
+ if (walk.exports.has(name)) return;
5536
+ walk.exports.add(name);
5537
+ const shownExport = displayUntrustedValue(name);
5538
+ if (depth > MAX_DEPTH) {
5539
+ CfnProducerSecretJudge.opaque(walk, `the re-exports go past the ${MAX_DEPTH}-level bound`);
5540
+ return;
5541
+ }
5542
+ const entry = (await this.exports())?.get(name);
5543
+ if (entry === void 0) {
5544
+ CfnProducerSecretJudge.opaque(walk, `the producer re-exports ${shownExport}, which ListExports does not list`);
5545
+ return;
5546
+ }
5547
+ const stackId = entry.exportingStackId;
5548
+ if (stackId === void 0 || stackId === "") {
5549
+ CfnProducerSecretJudge.opaque(walk, `ListExports names no exporting stack for ${shownExport}`);
5550
+ return;
5551
+ }
5552
+ const shownStack = displayUntrustedValue(stackId);
5553
+ await this.addTree(stackId, walk, depth);
5554
+ const outputs = await this.readOutputs(stackId);
5555
+ if ("error" in outputs) {
5556
+ CfnProducerSecretJudge.opaque(walk, outputs.error);
5557
+ return;
5558
+ }
5559
+ const output = outputs.ok.find((o) => o.ExportName === name);
5560
+ if (output?.OutputKey === void 0 || output.OutputValue !== entry.value) {
5561
+ if (top) walk.summary.stale = true;
5562
+ else CfnProducerSecretJudge.opaque(walk, `the producer re-exports ${shownExport}, which ${shownStack} no longer declares`);
5563
+ return;
5564
+ }
5565
+ const template = await this.readTemplate(stackId);
5566
+ if ("error" in template) {
5567
+ CfnProducerSecretJudge.opaque(walk, template.error);
5568
+ return;
5569
+ }
5570
+ await this.traceOutput({
5571
+ stackId,
5572
+ template: template.ok
5573
+ }, output.OutputKey, output.OutputValue, walk, depth);
5574
+ }
5575
+ async addTree(stackId, walk, depth) {
5576
+ if (walk.stacks.has(stackId)) return;
5577
+ if (walk.stacks.size >= MAX_STACKS) {
5578
+ CfnProducerSecretJudge.opaque(walk, `the producer tree goes past ${MAX_STACKS} stacks`);
5579
+ return;
5580
+ }
5581
+ walk.stacks.add(stackId);
5582
+ const resources = await this.readResources(stackId);
5583
+ if ("error" in resources) {
5584
+ CfnProducerSecretJudge.opaque(walk, resources.error);
5585
+ return;
5586
+ }
5587
+ for (const r of resources.ok) {
5588
+ const segment = secretPhysicalIdSegment(r.ResourceType, r.PhysicalResourceId);
5589
+ if (segment !== void 0 && isPlaintext(segment)) walk.summary.segments.add(segment);
5590
+ if (r.ResourceType === "AWS::CloudFormation::Stack" && r.PhysicalResourceId) {
5591
+ if (depth + 1 > MAX_DEPTH) {
5592
+ CfnProducerSecretJudge.opaque(walk, `the nested stacks go past the ${MAX_DEPTH}-level bound`);
5593
+ continue;
5594
+ }
5595
+ await this.addTree(r.PhysicalResourceId, walk, depth + 1);
5596
+ }
5597
+ }
5598
+ }
5599
+ async traceOutput(stack, key, value, walk, depth) {
5600
+ const outputs = stack.template["Outputs"];
5601
+ const def = isRecord(outputs) && Object.hasOwn(outputs, key) ? outputs[key] : void 0;
5602
+ if (!isRecord(def) || !Object.hasOwn(def, "Value")) {
5603
+ CfnProducerSecretJudge.opaque(walk, `the template of ${displayUntrustedValue(stack.stackId)} declares no output ${displayUntrustedValue(key)}`);
5604
+ return;
5605
+ }
5606
+ await this.trace(def["Value"], stack, value, walk, depth, /* @__PURE__ */ new Set());
5607
+ }
5608
+ async trace(node, stack, value, walk, depth, shadowed) {
5609
+ if (Array.isArray(node)) {
5610
+ for (const item of node) await this.trace(item, stack, value, walk, depth, shadowed);
5611
+ return;
5612
+ }
5613
+ if (!isRecord(node)) return;
5614
+ for (const [key, child] of Object.entries(node)) {
5615
+ if (key === "Ref" && typeof child === "string") await this.readRef(child, stack, value, walk, depth);
5616
+ else if (key === "Fn::GetAtt") {
5617
+ const att = getAttOf(child);
5618
+ if (att === void 0) CfnProducerSecretJudge.opaque(walk, "an exported Fn::GetAtt is computed");
5619
+ else await this.readGetAtt(att[0], att[1], stack, value, walk, depth);
5620
+ } else if (key === "Fn::Sub") {
5621
+ const template = Array.isArray(child) ? child[0] : child;
5622
+ const vars = Array.isArray(child) && isRecord(child[1]) ? child[1] : {};
5623
+ const inScope = /* @__PURE__ */ new Set([...shadowed, ...Object.keys(vars)]);
5624
+ if (typeof template === "string") for (const m of template.matchAll(/\$\{([^}!][^}]*)\}/g)) {
5625
+ const ref = m[1].trim();
5626
+ if (inScope.has(ref) || ref.startsWith("AWS::")) continue;
5627
+ const dot = ref.indexOf(".");
5628
+ if (dot > 0) await this.readGetAtt(ref.slice(0, dot), ref.slice(dot + 1), stack, value, walk, depth);
5629
+ else await this.readRef(ref, stack, value, walk, depth);
5630
+ }
5631
+ else await this.trace(template, stack, value, walk, depth, shadowed);
5632
+ for (const v of Object.values(vars)) await this.trace(v, stack, value, walk, depth, shadowed);
5633
+ continue;
5634
+ } else if (key === "Fn::ImportValue") {
5635
+ if (typeof child === "string") await this.addExport(child, walk, depth + 1, false);
5636
+ else CfnProducerSecretJudge.opaque(walk, "the producer re-exports an Fn::ImportValue whose name is computed");
5637
+ continue;
5638
+ }
5639
+ await this.trace(child, stack, value, walk, depth, shadowed);
5640
+ }
5641
+ }
5642
+ async readRef(name, stack, value, walk, depth) {
5643
+ const params = stack.template["Parameters"];
5644
+ const param = isRecord(params) && Object.hasOwn(params, name) ? params[name] : void 0;
5645
+ if (!isRecord(param)) return;
5646
+ const noEcho = param["NoEcho"];
5647
+ if ((noEcho === true || noEcho === "true") && isPlaintext(value)) {
5648
+ walk.summary.typed.add(value);
5649
+ return;
5650
+ }
5651
+ const parent = stack.parent;
5652
+ if (parent !== void 0 && Object.hasOwn(parent.bindings, name)) await this.trace(parent.bindings[name], parent.stack, value, walk, depth, /* @__PURE__ */ new Set());
5653
+ }
5654
+ async readGetAtt(logicalId, attribute, stack, value, walk, depth) {
5655
+ const resources = stack.template["Resources"];
5656
+ const res = isRecord(resources) && Object.hasOwn(resources, logicalId) ? resources[logicalId] : void 0;
5657
+ const type = isRecord(res) ? res["Type"] : void 0;
5658
+ if (type === "AWS::CloudFormation::Stack" && attribute.startsWith("Outputs.")) {
5659
+ await this.traceNestedOutput(stack, logicalId, attribute.slice(8), walk, depth);
5660
+ return;
5661
+ }
5662
+ if (!isPlaintext(value)) return;
5663
+ if (isSecretValuedAttribute(type, attribute) || isCustomResourceType(type)) walk.summary.typed.add(value);
5664
+ else if (isSecretAttributeName(attribute) && value.length >= NAMED_LEAF_EXACT_FLOOR) walk.summary.named.add(value);
5665
+ }
5666
+ async traceNestedOutput(stack, logicalId, key, walk, depth) {
5667
+ const shownParent = displayUntrustedValue(stack.stackId);
5668
+ if (depth + 1 > MAX_DEPTH) {
5669
+ CfnProducerSecretJudge.opaque(walk, `the nested stacks go past the ${MAX_DEPTH}-level bound`);
5670
+ return;
5671
+ }
5672
+ const resources = await this.readResources(stack.stackId);
5673
+ if ("error" in resources) {
5674
+ CfnProducerSecretJudge.opaque(walk, resources.error);
5675
+ return;
5676
+ }
5677
+ const nestedId = resources.ok.find((r) => r.LogicalResourceId === logicalId)?.PhysicalResourceId;
5678
+ if (!nestedId) {
5679
+ CfnProducerSecretJudge.opaque(walk, `${shownParent} lists no nested stack ${displayUntrustedValue(logicalId)}`);
5680
+ return;
5681
+ }
5682
+ const outputs = await this.readOutputs(nestedId);
5683
+ if ("error" in outputs) {
5684
+ CfnProducerSecretJudge.opaque(walk, outputs.error);
5685
+ return;
5686
+ }
5687
+ const output = outputs.ok.find((o) => o.OutputKey === key);
5688
+ const template = await this.readTemplate(nestedId);
5689
+ if ("error" in template) {
5690
+ CfnProducerSecretJudge.opaque(walk, template.error);
5691
+ return;
5692
+ }
5693
+ if (output?.OutputValue === void 0) {
5694
+ CfnProducerSecretJudge.opaque(walk, `the nested stack ${displayUntrustedValue(nestedId)} has no output ${displayUntrustedValue(key)}`);
5695
+ return;
5696
+ }
5697
+ const nestedRes = stack.template["Resources"]?.[logicalId];
5698
+ const props = isRecord(nestedRes) ? nestedRes["Properties"] : void 0;
5699
+ const bindings = isRecord(props) && isRecord(props["Parameters"]) ? props["Parameters"] : {};
5700
+ await this.traceOutput({
5701
+ stackId: nestedId,
5702
+ template: template.ok,
5703
+ parent: {
5704
+ stack,
5705
+ bindings
5706
+ }
5707
+ }, key, output.OutputValue, walk, depth + 1);
5708
+ }
5709
+ memo(cache, stackId, operation, read) {
5710
+ let got = cache.get(stackId);
5711
+ if (got === void 0) {
5712
+ got = Promise.resolve().then(read).then((ok) => ({ ok }), (err) => {
5713
+ const why = err instanceof UnjudgeableStackError ? err.message : describeAwsFailureForWarn(err, `${this.label}: CloudFormation ${operation}(${displayUntrustedValue(stackId)})`);
5714
+ return { error: `${operation} of ${displayUntrustedValue(stackId)} failed: ${why}` };
5715
+ });
5716
+ cache.set(stackId, got);
5717
+ }
5718
+ return got;
5719
+ }
5720
+ readResources(stackId) {
5721
+ return this.memo(this.resourceReads, stackId, "ListStackResources", async () => {
5722
+ return this.listResources(this.client, stackId);
5723
+ });
5724
+ }
5725
+ readOutputs(stackId) {
5726
+ return this.memo(this.outputReads, stackId, "DescribeStacks", async () => {
5727
+ const stack = (await this.client.send(new DescribeStacksCommand({ StackName: stackId }))).Stacks?.[0];
5728
+ if (!stack) throw new UnjudgeableStackError("it returned no stack");
5729
+ return stack.Outputs ?? [];
5730
+ });
5731
+ }
5732
+ readTemplate(stackId) {
5733
+ return this.memo(this.templateReads, stackId, "GetTemplate", async () => {
5734
+ const body = (await this.client.send(new GetTemplateCommand({ StackName: stackId }))).TemplateBody;
5735
+ let parsed;
5736
+ try {
5737
+ parsed = typeof body === "string" ? JSON.parse(body) : void 0;
5738
+ } catch {
5739
+ parsed = void 0;
5740
+ }
5741
+ if (!isRecord(parsed)) throw new UnjudgeableStackError("the template is not a JSON object");
5742
+ return parsed;
5743
+ });
5744
+ }
5745
+ };
5746
+ var UnjudgeableStackError = class extends Error {};
5747
+ function getAttOf(node) {
5748
+ if (Array.isArray(node) && typeof node[0] === "string" && typeof node[1] === "string") return [node[0], node[1]];
5749
+ if (typeof node === "string") {
5750
+ const dot = node.indexOf(".");
5751
+ if (dot > 0) return [node.slice(0, dot), node.slice(dot + 1)];
5752
+ }
5753
+ }
5754
+ function verdictOf(summary, served) {
5755
+ for (const s of summary.segments) if (holds(served, s, SEGMENT_SUBSTRING_FLOOR)) return { verdict: "secret" };
5756
+ for (const t of summary.typed) if (holds(served, t, SEGMENT_SUBSTRING_FLOOR)) return { verdict: "secret" };
5757
+ for (const n of summary.named) if (holds(served, n, NAMED_LEAF_FLOOR)) return { verdict: "secret" };
5758
+ if (summary.opaque !== void 0) return {
5759
+ verdict: "unreadable",
5760
+ detail: summary.opaque
5761
+ };
5762
+ if (summary.stale) return { verdict: "stale" };
5763
+ }
5764
+
5452
5765
  // src/local/cfn-local-state-provider.ts
5453
5766
  var CfnLocalStateProvider = class {
5454
5767
  label;
@@ -5614,20 +5927,33 @@ var CfnLocalStateProvider = class {
5614
5927
  let exportsPromise;
5615
5928
  const ensureExports = () => {
5616
5929
  if (exportsPromise) return exportsPromise;
5617
- exportsPromise = fetchAllExports(client).catch((err) => {
5930
+ exportsPromise = fetchAllExportEntries(client).catch((err) => {
5618
5931
  logger.warn(`${label}: ListExports (${region}) failed: ${formatAwsErrorForWarn(err, "CloudFormation ListExports")}. Fn::ImportValue intrinsics will warn-and-drop.`);
5619
5932
  });
5620
5933
  return exportsPromise;
5621
5934
  };
5935
+ const judge = new CfnProducerSecretJudge(client, ensureExports, label, fetchAllStackResources);
5936
+ const resolveImport = async (exportName) => {
5937
+ const map = await ensureExports();
5938
+ if (!map) return void 0;
5939
+ return map.get(exportName)?.value;
5940
+ };
5941
+ const resolveGetStackOutput = async (producerStack, producerRegion, outputName) => {
5942
+ logger.warn(`${label}: Fn::GetStackOutput ${displayUntrustedValue(producerStack)}.${displayUntrustedValue(outputName)} (${displayUntrustedValue(producerRegion)}) has no CloudFormation equivalent and cannot be resolved when reading state from a CloudFormation stack. Use Fn::ImportValue against an exported output instead.`);
5943
+ };
5622
5944
  return {
5623
- async resolveImport(exportName) {
5624
- const map = await ensureExports();
5625
- if (!map) return void 0;
5626
- return map.get(exportName);
5945
+ resolveImport,
5946
+ resolveGetStackOutput,
5947
+ async resolveImportJudged(exportName) {
5948
+ const value = await resolveImport(exportName);
5949
+ if (value === void 0) return { value };
5950
+ const judgement = await judge.judgeExport(exportName, value);
5951
+ return judgement === void 0 ? { value } : {
5952
+ value,
5953
+ ...judgement
5954
+ };
5627
5955
  },
5628
- async resolveGetStackOutput(producerStack, producerRegion, outputName) {
5629
- logger.warn(`${label}: Fn::GetStackOutput ${displayUntrustedValue(producerStack)}.${displayUntrustedValue(outputName)} (${displayUntrustedValue(producerRegion)}) has no CloudFormation equivalent and cannot be resolved when reading state from a CloudFormation stack. Use Fn::ImportValue against an exported output instead.`);
5630
- }
5956
+ resolveGetStackOutputJudged: async (producerStack, producerRegion, outputName) => ({ value: await resolveGetStackOutput(producerStack, producerRegion, outputName) })
5631
5957
  };
5632
5958
  }
5633
5959
  dispose() {
@@ -5688,7 +6014,7 @@ async function fetchAllStackResources(client, stackName) {
5688
6014
  } while (nextToken !== void 0 && nextToken !== "");
5689
6015
  return out;
5690
6016
  }
5691
- async function fetchAllExports(client) {
6017
+ async function fetchAllExportEntries(client) {
5692
6018
  const out = /* @__PURE__ */ new Map();
5693
6019
  let nextToken;
5694
6020
  let pages = 0;
@@ -5696,7 +6022,10 @@ async function fetchAllExports(client) {
5696
6022
  const resp = await client.send(new ListExportsCommand({ ...nextToken !== void 0 && { NextToken: nextToken } }));
5697
6023
  for (const exp of resp.Exports ?? []) {
5698
6024
  if (exp.Name === void 0 || exp.Value === void 0) continue;
5699
- out.set(exp.Name, exp.Value);
6025
+ out.set(exp.Name, {
6026
+ value: exp.Value,
6027
+ exportingStackId: exp.ExportingStackId
6028
+ });
5700
6029
  }
5701
6030
  nextToken = resp.NextToken;
5702
6031
  pages += 1;
@@ -5715,6 +6044,9 @@ function resolveCfnStackName(fromCfnStack, stackName) {
5715
6044
  if (typeof fromCfnStack === "string") return fromCfnStack;
5716
6045
  return stackName;
5717
6046
  }
6047
+ function deployedStackName(opts, stackName) {
6048
+ return resolveCfnStackName(opts.fromCfnStack ?? false, stackName);
6049
+ }
5718
6050
  function isCfnFlagPresent(opts) {
5719
6051
  const v = opts.fromCfnStack;
5720
6052
  return v !== void 0 && v !== false;
@@ -6033,6 +6365,78 @@ function looksLikeAccessDenied(err) {
6033
6365
  return name === "AccessDeniedException" || code === "AccessDeniedException" || /access denied/i.test(message) || /not authorized/i.test(message);
6034
6366
  }
6035
6367
 
6368
+ // src/local/cross-stack-secret-check.ts
6369
+ const SECRET_MASK = "***";
6370
+ function crossStackSecretCheckOf(resolver) {
6371
+ if (resolver === void 0 || typeof resolver.resolveImportJudged !== "function" || typeof resolver.resolveGetStackOutputJudged !== "function") return;
6372
+ const r = resolver;
6373
+ return {
6374
+ resolveImportJudged: (exportName) => r.resolveImportJudged(exportName),
6375
+ resolveGetStackOutputJudged: (stack, region, output) => r.resolveGetStackOutputJudged(stack, region, output)
6376
+ };
6377
+ }
6378
+ function strongerJudgement(a, b) {
6379
+ if (a === void 0) return b;
6380
+ if (b === void 0) return a;
6381
+ if (b.verdict === "secret" && a.verdict !== "secret") return b;
6382
+ return a;
6383
+ }
6384
+ function judgementOf(judged) {
6385
+ const { verdict, detail } = judged;
6386
+ if (verdict === void 0) return void 0;
6387
+ if (verdict === "secret") return { verdict };
6388
+ const known = verdict === "unreadable" || verdict === "stale" ? verdict : "unreadable";
6389
+ return typeof detail === "string" ? {
6390
+ verdict: known,
6391
+ detail
6392
+ } : { verdict: known };
6393
+ }
6394
+ function judgedClause(judgement) {
6395
+ const bin = getEmbedConfig().binaryName;
6396
+ if (judgement.verdict === "secret") return "holding a secret of the producer stack";
6397
+ if (judgement.verdict === "stale") return `the producer stack no longer exports, so ${bin} could not check it for secrets`;
6398
+ return judgement.detail !== void 0 ? `${bin} could not check for secrets (${judgement.detail})` : `whose producer stack ${bin} could not read to check it for secrets`;
6399
+ }
6400
+ function crossStackSecretArgvReason(judgement) {
6401
+ return `resolved a cross-stack value ${judgedClause(judgement)}, which ${getEmbedConfig().binaryName} will not put on the docker run command line; pass the value through Environment instead`;
6402
+ }
6403
+ function crossStackSecretValueFromReason(judgement) {
6404
+ if (judgement.verdict === "secret") return "ValueFrom resolved a cross-stack value holding a secret of the producer stack, rather than naming a Secrets Manager secret or an SSM parameter";
6405
+ return `ValueFrom resolved a cross-stack value ${judgedClause(judgement)}`;
6406
+ }
6407
+ function watchResolved(context, secrets) {
6408
+ const seen = {
6409
+ masked: false,
6410
+ producerSecret: void 0
6411
+ };
6412
+ const inner = context.crossStackResolver;
6413
+ if (!inner) return {
6414
+ context,
6415
+ seen
6416
+ };
6417
+ const watch = (judged) => {
6418
+ const { value } = judged;
6419
+ if (value === void 0) return value;
6420
+ if (value === SECRET_MASK) seen.masked = true;
6421
+ seen.producerSecret = strongerJudgement(seen.producerSecret, judgementOf(judged));
6422
+ return value;
6423
+ };
6424
+ const resolver = secrets ? {
6425
+ resolveImport: async (exportName) => watch(await secrets.resolveImportJudged(exportName)),
6426
+ resolveGetStackOutput: async (stack, region, output) => watch(await secrets.resolveGetStackOutputJudged(stack, region, output))
6427
+ } : {
6428
+ resolveImport: async (exportName) => watch({ value: await inner.resolveImport(exportName) }),
6429
+ resolveGetStackOutput: async (stack, region, output) => watch({ value: await inner.resolveGetStackOutput(stack, region, output) })
6430
+ };
6431
+ return {
6432
+ context: {
6433
+ ...context,
6434
+ crossStackResolver: resolver
6435
+ },
6436
+ seen
6437
+ };
6438
+ }
6439
+
6036
6440
  // src/local/state-resolver.ts
6037
6441
  function substituteAgainstState(value, contextOrResources) {
6038
6442
  const context = isContext(contextOrResources) ? contextOrResources : { resources: contextOrResources };
@@ -6131,9 +6535,15 @@ function resolvePseudoParameter(name, pseudo) {
6131
6535
  value: pseudo.urlSuffix
6132
6536
  };
6133
6537
  break;
6538
+ case "AWS::StackName":
6539
+ if (pseudo.stackName !== void 0) return {
6540
+ kind: "literal",
6541
+ value: pseudo.stackName
6542
+ };
6543
+ break;
6134
6544
  default: return {
6135
6545
  kind: "unresolved",
6136
- reason: `Ref ${displayIdent(name)}: pseudo parameter not supported (supported: AWS::AccountId, AWS::Region, AWS::Partition, AWS::URLSuffix)`
6546
+ reason: `Ref ${displayIdent(name)}: pseudo parameter not supported (supported: AWS::AccountId, AWS::Region, AWS::Partition, AWS::URLSuffix, AWS::StackName)`
6137
6547
  };
6138
6548
  }
6139
6549
  return {
@@ -6632,16 +7042,18 @@ async function substituteEnvVarsFromStateAsync(templateEnv, contextOrResources)
6632
7042
  audit
6633
7043
  };
6634
7044
  const context = isContext(contextOrResources) ? contextOrResources : { resources: contextOrResources };
7045
+ const producerSecrets = crossStackSecretCheckOf(context.crossStackResolver);
6635
7046
  for (const [key, value] of Object.entries(templateEnv)) {
6636
7047
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
6637
7048
  defineOwnKey(env, key, value);
6638
7049
  continue;
6639
7050
  }
6640
- const { result, consumedSensitive } = await resolveWithSensitivityAsync(value, context);
7051
+ const watched = watchResolved(context, producerSecrets);
7052
+ const { result, consumedSensitive } = await resolveWithSensitivityAsync(value, watched.context);
6641
7053
  if (result.kind === "literal") {
6642
7054
  defineOwnKey(env, key, result.value);
6643
7055
  audit.resolvedKeys.push(key);
6644
- if (consumedSensitive) audit.sensitiveKeys.push(key);
7056
+ if (consumedSensitive || watched.seen.producerSecret !== void 0) audit.sensitiveKeys.push(key);
6645
7057
  } else audit.unresolved.push({
6646
7058
  key,
6647
7059
  reason: result.reason
@@ -7285,21 +7697,13 @@ function resolveArgvArray(raw, field, subContext, context, unresolved) {
7285
7697
  });
7286
7698
  }
7287
7699
  const STATE_SECRET_MASK = "***";
7288
- const SECRET_ATTRIBUTE_NAME = /secret|password|credential/i;
7289
- const NON_SECRET_ATTRIBUTE_SUFFIX = /(arn|id|name|url|alias|status)$/i;
7290
- const SECRET_VALUED_ATTRIBUTES = /* @__PURE__ */ new Map([
7291
- ["AWS::AppSync::ApiKey", ["ApiKey"]],
7292
- ["AWS::EC2::IpamExternalResourceVerificationToken", ["TokenValue"]],
7293
- ["AWS::IVS::StreamKey", ["Value"]]
7294
- ]);
7295
7700
  function secretAttributeRead(element, stateResources) {
7296
7701
  for (const [logicalId, attribute] of getAttReads(element)) {
7297
7702
  const record = Object.hasOwn(stateResources, logicalId) ? stateResources[logicalId] : void 0;
7298
7703
  const recorded = record?.attributes;
7299
7704
  const stored = recorded && Object.hasOwn(recorded, attribute) ? recorded[attribute] : void 0;
7300
7705
  const type = typeof record?.resourceType === "string" ? record.resourceType : "";
7301
- const typed = SECRET_VALUED_ATTRIBUTES.get(type);
7302
- if (SECRET_ATTRIBUTE_NAME.test(attribute) && !NON_SECRET_ATTRIBUTE_SUFFIX.test(attribute) || typed?.includes(attribute) === true || type.startsWith("Custom::") || type === "AWS::CloudFormation::CustomResource" || type === "AWS::CloudFormation::Stack" && attribute.startsWith("Outputs.") || stored === STATE_SECRET_MASK) return `reads ${displayIdent(logicalId)}.${displayIdent(attribute)}, an attribute that is or may be a secret, which ${getEmbedConfig().binaryName} will not put on the docker run command line; pass the value through Environment or Secrets instead`;
7706
+ if (isSecretAttributeName(attribute) || isSecretValuedAttribute(type, attribute) || isCustomResourceType(type) || type === "AWS::CloudFormation::Stack" && attribute.startsWith("Outputs.") || stored === STATE_SECRET_MASK) return `reads ${displayIdent(logicalId)}.${displayIdent(attribute)}, an attribute that is or may be a secret, which ${getEmbedConfig().binaryName} will not put on the docker run command line; pass the value through Environment or Secrets instead`;
7303
7707
  }
7304
7708
  }
7305
7709
  function getAttReads(node, out = []) {
@@ -7345,20 +7749,17 @@ function computedAttributeRead(node) {
7345
7749
  if (r !== void 0) return r;
7346
7750
  }
7347
7751
  }
7348
- function withMaskWatch(context, masked) {
7349
- const inner = context.crossStackResolver;
7350
- if (!inner) return context;
7351
- const watch = (v) => {
7352
- if (v === STATE_SECRET_MASK) masked.hit = true;
7353
- return v;
7354
- };
7355
- return {
7356
- ...context,
7357
- crossStackResolver: {
7358
- resolveImport: async (exportName) => watch(await inner.resolveImport(exportName)),
7359
- resolveGetStackOutput: async (stack, region, output) => watch(await inner.resolveGetStackOutput(stack, region, output))
7360
- }
7361
- };
7752
+ const SECRET_POINTER_ARN = /^arn:aws(?:-[a-z]+)*:(?:secretsmanager:[a-z0-9-]+:\d{12}:secret:[A-Za-z0-9/_+=.@!-]+(?::[A-Za-z0-9/_+=.@-]*:[A-Za-z0-9/_+=.@-]*:[A-Za-z0-9/_+=.@-]*)?|ssm:[a-z0-9-]+:\d{12}:parameter\/[A-Za-z0-9/_.-]+)$/;
7753
+ function isSecretPointerArn(value) {
7754
+ return SECRET_POINTER_ARN.test(value);
7755
+ }
7756
+ function redropSecret(task, container, containerName, name, reason) {
7757
+ const own = `Secret ${displayIdent(name)} dropped:`;
7758
+ const line = `${own} ${reason}`;
7759
+ container.warnings = [...container.warnings.filter((w) => !w.startsWith(own)), line];
7760
+ const taskOwn = `Container ${displayIdent(containerName)}: ${own}`;
7761
+ task.warnings = [...task.warnings.filter((w) => !w.startsWith(taskOwn)), `Container ${displayIdent(containerName)}: ${line}`];
7762
+ if (!container.droppedSecretNames?.includes(name)) container.droppedSecretNames = [...container.droppedSecretNames ?? [], name];
7362
7763
  }
7363
7764
  const CROSS_STACK_ARGV_REASON = "a cross-stack reference (Fn::ImportValue / Fn::GetStackOutput): it resolves only from a state source with the producer stack deployed";
7364
7765
  function argvValue(sub, consumedSensitive) {
@@ -7715,6 +8116,7 @@ function withContainerState(context, state) {
7715
8116
  async function applyCrossStackResolverToTask(task, context, containerState) {
7716
8117
  if (!context.crossStackResolver) return;
7717
8118
  const { resolveDynamicReferences: _envOnly, ...secretContext } = context;
8119
+ const producerSecrets = crossStackSecretCheckOf(context.crossStackResolver);
7718
8120
  const rawContainers = (task.resource.Properties ?? {})["ContainerDefinitions"];
7719
8121
  if (!Array.isArray(rawContainers)) return;
7720
8122
  for (let idx = 0; idx < task.containers.length; idx += 1) {
@@ -7741,11 +8143,12 @@ async function applyCrossStackResolverToTask(task, context, containerState) {
7741
8143
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") continue;
7742
8144
  if (Object.hasOwn(container.environment, key)) continue;
7743
8145
  if (!isCrossStackIntrinsic(value)) continue;
7744
- const { result: sub, consumedSensitive } = await resolveWithSensitivityAsync(value, containerContext);
8146
+ const watched = watchResolved(containerContext, producerSecrets);
8147
+ const { result: sub, consumedSensitive } = await resolveWithSensitivityAsync(value, watched.context);
7745
8148
  if (sub.kind === "literal") {
7746
8149
  defineOwnKey(container.environment, key, String(sub.value));
7747
8150
  resolvedEnvKeys.add(key);
7748
- if (consumedSensitive && !container.sensitiveEnvKeys.includes(key)) container.sensitiveEnvKeys.push(key);
8151
+ if ((consumedSensitive || watched.seen.producerSecret !== void 0) && !container.sensitiveEnvKeys.includes(key)) container.sensitiveEnvKeys.push(key);
7749
8152
  }
7750
8153
  }
7751
8154
  if (Array.isArray(c["Secrets"])) for (const entry of c["Secrets"]) {
@@ -7757,7 +8160,12 @@ async function applyCrossStackResolverToTask(task, context, containerState) {
7757
8160
  if (typeof valueFromRaw === "string" && valueFromRaw.length > 0) continue;
7758
8161
  if (container.secrets.some((s) => s.name === sName)) continue;
7759
8162
  if (!isCrossStackIntrinsic(valueFromRaw)) continue;
7760
- const sub = await substituteAgainstStateAsync(valueFromRaw, ownState ? withContainerState(secretContext, ownState) : secretContext);
8163
+ const watched = watchResolved(ownState ? withContainerState(secretContext, ownState) : secretContext, producerSecrets);
8164
+ const sub = await substituteAgainstStateAsync(valueFromRaw, watched.context);
8165
+ if (watched.seen.producerSecret !== void 0 && !(watched.seen.producerSecret.verdict !== "secret" && sub.kind === "literal" && typeof sub.value === "string" && isSecretPointerArn(sub.value))) {
8166
+ redropSecret(task, container, containerName, sName, crossStackSecretValueFromReason(watched.seen.producerSecret));
8167
+ continue;
8168
+ }
7761
8169
  if (sub.kind === "literal" && typeof sub.value === "string" && sub.value.length > 0) {
7762
8170
  container.secrets.push({
7763
8171
  name: sName,
@@ -7784,9 +8192,9 @@ async function applyCrossStackResolverToTask(task, context, containerState) {
7784
8192
  });
7785
8193
  continue;
7786
8194
  }
7787
- const masked = { hit: false };
7788
- const { result: sub, consumedSensitive } = await resolveWithSensitivityAsync(rawElement, withMaskWatch(argvContext, masked));
7789
- const arg = masked.hit ? { reason: `resolved a cross-stack value recorded as the secret mask (${STATE_SECRET_MASK}), not the deployed value` } : argvValue(sub, consumedSensitive);
8195
+ const watched = watchResolved(argvContext, producerSecrets);
8196
+ const { result: sub, consumedSensitive } = await resolveWithSensitivityAsync(rawElement, watched.context);
8197
+ const arg = watched.seen.masked ? { reason: `resolved a cross-stack value recorded as the secret mask (${STATE_SECRET_MASK}), not the deployed value` } : watched.seen.producerSecret !== void 0 ? { reason: crossStackSecretArgvReason(watched.seen.producerSecret) } : argvValue(sub, consumedSensitive);
7790
8198
  if ("value" in arg) {
7791
8199
  target[u.index] = arg.value;
7792
8200
  continue;
@@ -10871,7 +11279,7 @@ function envHasCrossStackIntrinsic(templateEnv) {
10871
11279
  if (!templateEnv) return false;
10872
11280
  return Object.values(templateEnv).some(containsCrossStackIntrinsic);
10873
11281
  }
10874
- async function resolvePseudoParametersForInvoke(stackRegion, options) {
11282
+ async function resolvePseudoParametersForInvoke(stackRegion, options, stackName) {
10875
11283
  const logger = getLogger();
10876
11284
  const region = options.region ?? namedEnvAwsRegion() ?? process.env["AWS_DEFAULT_REGION"] ?? regionOrAmbientDefault(stackRegion);
10877
11285
  if (!region) logger.warn(`Resolver references \${AWS::Region} but ${getEmbedConfig().binaryName} could not determine the target region. Pass --region, set AWS_REGION, or declare env.region on the CDK stack.`);
@@ -10898,7 +11306,8 @@ async function resolvePseudoParametersForInvoke(stackRegion, options) {
10898
11306
  ...partitionAndSuffix && {
10899
11307
  partition: partitionAndSuffix.partition,
10900
11308
  urlSuffix: partitionAndSuffix.urlSuffix
10901
- }
11309
+ },
11310
+ ...stackName !== void 0 && { stackName: deployedStackName(options, stackName) }
10902
11311
  };
10903
11312
  return Object.keys(bag).length === 0 ? void 0 : bag;
10904
11313
  }
@@ -11015,7 +11424,7 @@ async function resolveLambdaContainerEnvWith(lambda, options, profileCredentials
11015
11424
  })
11016
11425
  };
11017
11426
  if (envHasIntrinsicValue$1(templateEnv)) {
11018
- const pseudo = await resolvePseudoParametersForInvoke(lambda.stack.region, options);
11427
+ const pseudo = await resolvePseudoParametersForInvoke(lambda.stack.region, options, lambda.stack.stackName);
11019
11428
  if (pseudo) subContext.pseudoParameters = pseudo;
11020
11429
  }
11021
11430
  if (envHasIntrinsicValue$1(templateEnv) && stateProvider.resolveTemplateSsmParameters) {
@@ -17731,7 +18140,7 @@ async function loadStackStateBundle(stack, provider, args) {
17731
18140
  region: loaded.region
17732
18141
  };
17733
18142
  if (args.intrinsicEnv) {
17734
- const pseudo = args.pseudoParameters ?? await resolvePseudoParametersForStartApi(loaded.region, args.options);
18143
+ const pseudo = args.pseudoParameters ?? await resolvePseudoParametersForStartApi(loaded.region, args.options, stack.stackName);
17735
18144
  if (pseudo) bundle.pseudoParameters = pseudo;
17736
18145
  }
17737
18146
  if (provider.resolveDeployedFunctionEnv) {
@@ -17758,7 +18167,7 @@ async function loadStackStateBundle(stack, provider, args) {
17758
18167
  provider.dispose();
17759
18168
  }
17760
18169
  }
17761
- async function resolvePseudoParametersForStartApi(stateRegion, options) {
18170
+ async function resolvePseudoParametersForStartApi(stateRegion, options, stackName) {
17762
18171
  const logger = getLogger();
17763
18172
  const region = options.region ?? namedEnvAwsRegion() ?? process.env["AWS_DEFAULT_REGION"] ?? regionOrAmbientDefault(stateRegion);
17764
18173
  let accountId;
@@ -17784,7 +18193,8 @@ async function resolvePseudoParametersForStartApi(stateRegion, options) {
17784
18193
  ...partitionAndSuffix && {
17785
18194
  partition: partitionAndSuffix.partition,
17786
18195
  urlSuffix: partitionAndSuffix.urlSuffix
17787
- }
18196
+ },
18197
+ ...stackName !== void 0 && { stackName: deployedStackName(options, stackName) }
17788
18198
  };
17789
18199
  return Object.keys(bag).length === 0 ? void 0 : bag;
17790
18200
  }
@@ -17938,7 +18348,7 @@ function computeCodeImageTag(sourceDir, runtime, entryPoint, dockerfile) {
17938
18348
 
17939
18349
  // src/local/agentcore-s3-bundle.ts
17940
18350
  async function downloadAndExtractS3Bundle(location, options = {}) {
17941
- const ref = formatRef(location);
18351
+ const ref = formatRef(location, options.redactBucket);
17942
18352
  getLogger().info(`Downloading fromS3 code bundle ${ref}...`);
17943
18353
  const bytes = await (options.fetchObject ?? defaultFetchObject$1(options))(location);
17944
18354
  let files;
@@ -17973,9 +18383,9 @@ async function downloadAndExtractS3Bundle(location, options = {}) {
17973
18383
  }).then(() => void 0)
17974
18384
  };
17975
18385
  }
17976
- function formatRef(location) {
18386
+ function formatRef(location, redactBucket = false) {
17977
18387
  const version = location.versionId ? `?versionId=${flattenToOneLine(location.versionId)}` : "";
17978
- return `s3://${flattenToOneLine(location.bucket)}/${flattenToOneLine(location.key)}${version}`;
18388
+ return `s3://${redactBucket ? "<cross-stack value withheld>" : flattenToOneLine(location.bucket)}/${flattenToOneLine(location.key)}${version}`;
17979
18389
  }
17980
18390
  function resolveSafeEntryPath(root, entry) {
17981
18391
  const dest = normalize(join(root, entry));
@@ -18007,11 +18417,11 @@ function defaultFetchObject$1(options) {
18007
18417
  Key: location.key,
18008
18418
  ...location.versionId && { VersionId: location.versionId }
18009
18419
  }));
18010
- if (!res.Body) throw new CdkLocalError(`S3 GetObject for ${formatRef(location)} returned an empty body.`, "LOCAL_INVOKE_AGENTCORE_S3_BUNDLE_EMPTY_BODY");
18420
+ if (!res.Body) throw new CdkLocalError(`S3 GetObject for ${formatRef(location, options.redactBucket)} returned an empty body.`, "LOCAL_INVOKE_AGENTCORE_S3_BUNDLE_EMPTY_BODY");
18011
18421
  return await res.Body.transformToByteArray();
18012
18422
  } catch (err) {
18013
18423
  if (err instanceof CdkLocalError) throw err;
18014
- throw new CdkLocalError(`S3 GetObject for ${formatRef(location)} failed: ${describeAwsFailureForWarn(err, "S3 GetObject (fromS3 bundle)")}`, "LOCAL_INVOKE_AGENTCORE_S3_BUNDLE_FETCH_FAILED");
18424
+ throw new CdkLocalError(`S3 GetObject for ${formatRef(location, options.redactBucket)} failed: ${describeAwsFailureForWarn(err, "S3 GetObject (fromS3 bundle)")}`, "LOCAL_INVOKE_AGENTCORE_S3_BUNDLE_FETCH_FAILED");
18015
18425
  } finally {
18016
18426
  client.destroy();
18017
18427
  }
@@ -18681,7 +19091,7 @@ async function localInvokeAgentCoreCommand(target, options, extraStateProviders)
18681
19091
  logger.info(`${resolved.protocol} runtime: invoking the local container's ${pathLabel} directly (vanilla ${resolved.protocol}). An inbound JWT / --bearer-token is an AgentCore managed-plane concern and is not applied locally.`);
18682
19092
  }
18683
19093
  } else authorization = await resolveInboundAuthorization(resolved, options);
18684
- await resolveFromS3BucketIntrinsic(resolved, stateProvider, loadedState, imageContext);
19094
+ await resolveFromS3BucketIntrinsic(resolved, stateProvider, loadedState, imageContext, options);
18685
19095
  const image = await resolveAgentCoreImage(resolved, options, loadedState, stateProvider);
18686
19096
  const { env: dockerEnv, sensitiveEnvKeys } = await buildContainerEnv(resolved, options, profileCredentials, profileCredsFile, stateProvider, loadedState, imageContext);
18687
19097
  const hostPort = await pickFreePort();
@@ -18750,7 +19160,7 @@ async function localInvokeAgentCoreCommand(target, options, extraStateProviders)
18750
19160
  loaded: void 0
18751
19161
  };
18752
19162
  const newResolved = resolveAgentCoreTarget(resolvedTarget, newStacks, newImageContext);
18753
- await resolveFromS3BucketIntrinsic(newResolved, stateProvider, newLoaded, newImageContext);
19163
+ await resolveFromS3BucketIntrinsic(newResolved, stateProvider, newLoaded, newImageContext, options);
18754
19164
  const newImage = await resolveAgentCoreImage(newResolved, options, newLoaded, stateProvider);
18755
19165
  const { env: newEnv, sensitiveEnvKeys: newSensitive } = await buildContainerEnv(newResolved, options, profileCredentials, profileCredsFile, stateProvider, newLoaded, newImageContext);
18756
19166
  if (signal?.aborted) throw new CdkLocalError("Reload cancelled: shutting down.", "LOCAL_INVOKE_AGENTCORE_WATCH_CANCELLED");
@@ -18992,7 +19402,8 @@ async function resolveAgentCoreCodeImageFromS3(resolved, code, s3Source, options
18992
19402
  workload: {
18993
19403
  logicalId: resolved.logicalId,
18994
19404
  cdkPath: readCdkPathOrUndefined(resolved.resource)
18995
- }
19405
+ },
19406
+ ...s3Source.bucketWithheld === true && { redactBucket: true }
18996
19407
  });
18997
19408
  try {
18998
19409
  return await buildAgentCoreCodeImage({
@@ -19040,8 +19451,10 @@ async function buildContainerEnvWith(resolved, options, profileCredentials, prof
19040
19451
  consumer: `AgentCore Runtime ${resolved.logicalId} cross-stack env value`
19041
19452
  })
19042
19453
  };
19043
- const pseudo = imageContext?.pseudoParameters ?? derivePseudoParametersFromRegion(loaded.region);
19044
- if (pseudo) subContext.pseudoParameters = pseudo;
19454
+ subContext.pseudoParameters = imageContext?.pseudoParameters ?? {
19455
+ ...derivePseudoParametersFromRegion(loaded.region),
19456
+ stackName: deployedStackName(options, resolved.stack.stackName)
19457
+ };
19045
19458
  if (imageContext?.stateParameters) subContext.parameters = imageContext.stateParameters;
19046
19459
  if (imageContext?.stateSensitiveParameters?.length) subContext.sensitiveParameters = new Set(imageContext.stateSensitiveParameters);
19047
19460
  const resolver = await stateProvider.buildCrossStackResolver(loaded.region);
@@ -19091,7 +19504,7 @@ async function buildContainerEnvWith(resolved, options, profileCredentials, prof
19091
19504
  sensitiveEnvKeys
19092
19505
  };
19093
19506
  }
19094
- async function resolveFromS3BucketIntrinsic(resolved, stateProvider, loaded, imageContext) {
19507
+ async function resolveFromS3BucketIntrinsic(resolved, stateProvider, loaded, imageContext, options = {}) {
19095
19508
  const s3Source = resolved.codeArtifact?.s3Source;
19096
19509
  if (!s3Source || s3Source.bucketIntrinsic === void 0) return;
19097
19510
  if (s3Source.bucket !== void 0) return;
@@ -19100,15 +19513,20 @@ async function resolveFromS3BucketIntrinsic(resolved, stateProvider, loaded, ima
19100
19513
  resources: imageContext?.stateResources ?? loaded.resources,
19101
19514
  consumerRegion: loaded.region
19102
19515
  };
19103
- const pseudo = imageContext?.pseudoParameters ?? derivePseudoParametersFromRegion(loaded.region);
19104
- if (pseudo) subContext.pseudoParameters = pseudo;
19516
+ subContext.pseudoParameters = imageContext?.pseudoParameters ?? {
19517
+ ...derivePseudoParametersFromRegion(loaded.region),
19518
+ stackName: deployedStackName(options, resolved.stack.stackName)
19519
+ };
19105
19520
  const crossStackResolver = await stateProvider.buildCrossStackResolver(loaded.region);
19106
19521
  if (crossStackResolver) subContext.crossStackResolver = crossStackResolver;
19107
- const result = await substituteAgainstStateAsync(s3Source.bucketIntrinsic, subContext);
19522
+ const watched = watchResolved(subContext, crossStackSecretCheckOf(subContext.crossStackResolver));
19523
+ const result = await substituteAgainstStateAsync(s3Source.bucketIntrinsic, watched.context);
19108
19524
  if (result.kind !== "literal") throw new CdkLocalError(`Could not resolve AgentCore Runtime ${displayIdent(resolved.logicalId)} fromS3 Code.S3.Bucket intrinsic (${displayUntrustedValue(describeIntrinsic(s3Source.bucketIntrinsic))}) against the --from-cfn-stack state: ${result.reason}. Confirm the referenced resource / export exists in the deployed stack.`, "LOCAL_INVOKE_AGENTCORE_FROMS3_BUCKET_INTRINSIC_UNRESOLVED");
19109
19525
  if (typeof result.value !== "string" || result.value.length === 0) throw new CdkLocalError(`AgentCore Runtime ${displayIdent(resolved.logicalId)} fromS3 Code.S3.Bucket intrinsic resolved to a ${typeof result.value} value, not a bucket name string. (${displayUntrustedValue(describeIntrinsic(s3Source.bucketIntrinsic))})`, "LOCAL_INVOKE_AGENTCORE_FROMS3_BUCKET_INTRINSIC_NOT_STRING");
19110
19526
  s3Source.bucket = result.value;
19111
- getLogger().info(`Resolved fromS3 Code.S3.Bucket from state: ${describeIntrinsic(s3Source.bucketIntrinsic)} -> ${result.value}`);
19527
+ const withheld = watched.seen.producerSecret !== void 0 || watched.seen.masked;
19528
+ if (withheld) s3Source.bucketWithheld = true;
19529
+ getLogger().info(withheld ? `Resolved fromS3 Code.S3.Bucket from state: ${describeIntrinsic(s3Source.bucketIntrinsic)} (value not shown: a cross-stack value its producer stack says may be a secret)` : `Resolved fromS3 Code.S3.Bucket from state: ${describeIntrinsic(s3Source.bucketIntrinsic)} -> ${result.value}`);
19112
19530
  }
19113
19531
  function describeIntrinsic(value) {
19114
19532
  if (!value || typeof value !== "object") return String(value);
@@ -19128,8 +19546,10 @@ async function buildAgentCoreImageContext(candidate, stateProvider, options) {
19128
19546
  logger.warn(`--from-cfn-stack: STS GetCallerIdentity failed: ${describeAwsFailureForWarn(err, "STS GetCallerIdentity")}. A same-stack ECR image URI referencing \${AWS::AccountId} may not resolve.`);
19129
19547
  }
19130
19548
  const context = {};
19131
- const pseudo = derivePseudoParametersFromRegion(region, accountId);
19132
- if (pseudo) context.pseudoParameters = pseudo;
19549
+ context.pseudoParameters = {
19550
+ ...derivePseudoParametersFromRegion(region, accountId),
19551
+ stackName: deployedStackName(options, candidate.stackName)
19552
+ };
19133
19553
  const loaded = await stateProvider.load(candidate.stackName, candidate.region);
19134
19554
  if (loaded) {
19135
19555
  context.stateResources = loaded.resources;
@@ -25287,7 +25707,8 @@ async function buildEcsImageResolutionContext$1(target, stacks, options, statePr
25287
25707
  ...partitionAndSuffix && {
25288
25708
  partition: partitionAndSuffix.partition,
25289
25709
  urlSuffix: partitionAndSuffix.urlSuffix
25290
- }
25710
+ },
25711
+ stackName: deployedStackName(options, candidate.stackName)
25291
25712
  };
25292
25713
  }
25293
25714
  const wantsState = needs.needsStateResources || needs.needsEnvOrSecretSubstitution || wantsStateForTaskRole;
@@ -25784,7 +26205,8 @@ async function buildEcsImageResolutionContext(candidate, stateProvider, options,
25784
26205
  ...partitionAndSuffix && {
25785
26206
  partition: partitionAndSuffix.partition,
25786
26207
  urlSuffix: partitionAndSuffix.urlSuffix
25787
- }
26208
+ },
26209
+ stackName: deployedStackName(options, candidate.stackName)
25788
26210
  };
25789
26211
  }
25790
26212
  const wantsState = needs.needsStateResources || needs.needsEnvOrSecretSubstitution || wantsStateForTaskRole;
@@ -30450,7 +30872,7 @@ async function serveAgentCore(target, options, extraStateProviders, hostSynthesi
30450
30872
  const sigv4Context = await resolveAgentCoreSigV4Context(options, resolved, loadedState, stateProvider);
30451
30873
  const authPlan = selectServeInboundAuth(resolved, options, sigv4Context !== void 0);
30452
30874
  if (authPlan.authCheck && resolved.jwtAuthorizer) logger.info(`Inbound JWT: each request verified per-request against ${resolved.jwtAuthorizer.discoveryUrl}${options.verifyAuth === false ? " (verification DISABLED via --no-verify-auth)" : ""}.`);
30453
- await resolveFromS3BucketIntrinsic(resolved, stateProvider, loadedState, imageContext);
30875
+ await resolveFromS3BucketIntrinsic(resolved, stateProvider, loadedState, imageContext, options);
30454
30876
  const image = await resolveAgentCoreImage(resolved, options, loadedState, stateProvider);
30455
30877
  const { env: dockerEnv, sensitiveEnvKeys } = await buildContainerEnv(resolved, options, profileCredentials, profileCredsFile, stateProvider, loadedState, imageContext);
30456
30878
  let containerHostPort = await pickFreePort();
@@ -30561,7 +30983,7 @@ async function serveAgentCore(target, options, extraStateProviders, hostSynthesi
30561
30983
  freshImageContext = ctx.context;
30562
30984
  freshLoaded = ctx.loaded;
30563
30985
  freshResolved = resolveAgentCoreTarget(resolvedTarget, freshStacks, freshImageContext);
30564
- await resolveFromS3BucketIntrinsic(freshResolved, stateProvider, freshLoaded, freshImageContext);
30986
+ await resolveFromS3BucketIntrinsic(freshResolved, stateProvider, freshLoaded, freshImageContext, options);
30565
30987
  const assetCtx = await loadAgentCoreAssetContext({
30566
30988
  resolvedTarget,
30567
30989
  resolved: freshResolved,
@@ -37297,4 +37719,4 @@ function addStudioSpecificOptions(cmd) {
37297
37719
  }
37298
37720
 
37299
37721
  export { postHook as $, AGENTCORE_A2A_PROTOCOL as $a, probeHostGatewaySupport as $i, addImageOverrideOptions as $n, loopbackForwarderPlan as $o, resolveApiTargetSubset as $r, classifyS3Error as $t, microvmFidelityWarnings as A, createLocalStateProvider as Aa, translateLambdaResponse as Ai, stripCloudFrontImport as An, readEnvCallerCredentials as Ao, A2A_CONTAINER_PORT as Ar, readContainerLogTail as At, MICROVM_WS_BASE_PROTOCOL as B, resolveWatchConfig as Ba, ConnectionRegistry as Bi, createLocalStartAlbCommand as Bn, HOST_DEFAULT_CREDENTIALS_MISS_TTL_MS as Bo, AGENTCORE_SESSION_ID_HEADER as Br, parseWebFunctionBuildConfig as Bt, addListSpecificOptions as C, substituteAgainstState as Ca, attachAuthorizers as Ci, WEB_FUNCTION_REVISION_TYPE as Cn, resolveDynamicReferencesInEnv as Co, setShadowReadyTimeoutMs as Cr, parseKvsFileOverrides as Ct, buildMicrovmLambdaView as D, materializeLayerFromArn as Da, isFunctionUrlOacFronted as Di, compileCloudFrontFunction as Dn, SECOND_ASSUME_MESSAGE as Do, createLocalInvokeAgentCoreCommand as Dr, WEB_FUNCTION_CONTAINER_PORT as Dt, addStartMicrovmSpecificOptions as E, substituteEnvVarsFromStateAsync as Ea, buildCorsConfigFromCloudFrontChain as Ei, resolveWebFunctionTarget as En, awsEndpointOptions as Eo, addInvokeAgentCoreSpecificOptions as Er, RecentOutput as Et, microvmImageTag as F, resolveCfnRegion as Fa, pickResponseTemplate as Fi, findFileAssetForObjectKey as Fn, AUTH_OFF_PLACEHOLDER_CREDENTIALS as Fo, MCP_PROTOCOL_VERSION as Fr, buildNodeEntryFileStart as Ft, startMicrovmFrontDoor as G, discoverWebSocketApis as Ga, buildDisconnectEvent as Gi, addStartServiceSpecificOptions as Gn, collectHostEndpointOverrides as Go, SUPPORTED_CODE_RUNTIMES as Gr, readWebFunctionServiceConfig as Gt, PROXY_PORT_HEADER as H, countTargets as Ha, handleConnectionsRequest as Hi, resolveAlbTarget as Hn, applyWorkloadAwsWiringToEnv as Ho, waitForAgentCoreHttpReady as Hr, WEB_FUNCTION_HTTP_ENDPOINT_ENV as Ht, planMicrovmPorts as I, resolveCfnStackName as Ia, selectIntegrationResponse as Ii, isBucketDeploymentResource as In, CA_TRUST_ENV_KEYS as Io, mcpInvokeOnce as Ir, defaultWebFunctionPlatform as It, MICROVM_HOOK_PATH_PREFIX as J, parseSelectionExpressionPath as Ja, createFileWatcher as Ji, addRunTaskSpecificOptions as Jn, getActiveWorkloadAwsWiring as Jo, renderCodeDockerfile as Jr, idFromArn as Jt, stripMicrovmProxyHeaders as K, discoverWebSocketApisOrThrow as Ka, buildMessageEvent as Ki, createLocalStartServiceCommand as Kn, displayEndpointValue as Ko, buildAgentCoreCodeImage as Kr, webFunctionAssumeRole as Kt, readExposedPorts as L, CfnLocalStateProvider as La, tryParseStatus as Li, resolveBucketDeploymentObjectKey as Ln, DEFAULT_AWS_EMULATOR_URL as Lo, parseSseForJsonRpc as Lr, resolveWebFunctionRuntime as Lt, DEFAULT_TERMINATE_HOOK_TIMEOUT_MS as M, isCfnFlagPresent as Ma, buildHttpApiV2Event as Mi, createLocalFileKvsDataSource as Mn, resetWorkloadIdentity as Mo, a2aInvokeOnce as Mr, waitForWebFunctionReady as Mt, LocalMicrovm as N, rejectExplicitCfnStackWithMultipleStacks as Na, buildRestV1Event as Ni, createUnboundCloudFrontModule as Nn, workloadClientConfig as No, MCP_CONTAINER_PORT as Nr, watchContainerExit as Nt, createLocalStartMicrovmCommand as O, LocalStateSourceError as Oa, matchPreflight as Oi, runViewerRequest as On, assumedRoleRecorded as Oo, bridgeAgentCoreWs as Or, containerFailure as Ot, buildMicrovmImage as P, resolveCfnFallbackRegion as Pa, evaluateResponseParameters as Pi, bucketDeploymentSourceObjectKeys as Pn, workloadStsClientConfig as Po, MCP_PATH as Pr, WEB_FUNCTION_RUNTIMES as Pt, pollBuildHook as Q, resolveLambdaArnIntrinsic as Qa, HOST_GATEWAY_MIN_VERSION as Qi, addEcsAssumeRoleOptions as Qn, logMixedModeForWorkload as Qo, createWatchPredicates as Qr, resolveDeployedOriginBucket as Qt, setContainerPaused as R, collectSsmParameterRefs as Ra, VtlEvaluationError as Ri, addAlbSpecificOptions as Rn, EMULATOR_SCRUBBED_ENV_KEYS as Ro, AGENTCORE_SIGV4_SERVICE as Rr, supportedWebFunctionRuntimes as Rt, StudioEventBus as S, containsCrossStackIntrinsic as Sa, invokeTokenAuthorizer as Si, WEB_FUNCTION_ENDPOINT_TYPE as Sn, parseDynamicReference as So, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as Sr, normalizeKvsFileKeys as St, formatTargetListing as T, substituteEnvVarsFromState as Ta, buildCorsConfigByApiId as Ti, WebFunctionResolutionError as Tn, addAwsEndpointOptions as To, attachContainerLogStreamer as Tr, resolveCloudFrontTarget as Tt, rewriteUpgradeResponseHead as U, listTargets as Ua, parseConnectionsPath as Ui, isApplicationLoadBalancer as Un, awsEmulatorEnvName as Uo, waitForAgentCorePing as Ur, buildWebFunctionLambdaView as Ut, MicrovmStateError as V, resolveSingleTarget as Va, buildMgmtEndpointEnvUrl as Vi, parseLbPortOverrides as Vn, activateWorkloadAwsWiring as Vo, invokeAgentCore as Vr, resolveWebFunctionArtifact as Vt, selectTargetPort as W, availableWebSocketApiIdentifiers as Wa, buildConnectEvent as Wi, resolveAlbFrontDoor as Wn, awsEmulatorSqsHostBlocks as Wo, downloadAndExtractS3Bundle as Wr, finalizeWebFunctionEnv as Wt, callRuntimeHook as X, discoverRoutes as Xa, createLocalInvokeCommand as Xi, MAX_TASKS_SUBNET_RANGE_CAP as Xn, getContainerJavaTruststorePath as Xo, addStartApiSpecificOptions as Xr, createDeployedKvsDataSource as Xt, MicrovmHookError as Y, webSocketApiMatchesIdentifier as Ya, addInvokeSpecificOptions as Yi, createLocalRunTaskCommand as Yn, getContainerCaBundlePath as Yo, toCmdArgv as Yr, resolveKvsModulesForDistribution as Yt, generateMicrovmId as Z, pickRefLogicalId as Za, HOST_DOCKER_INTERNAL_GATEWAY as Zi, addCommonEcsServiceOptions as Zn, javaTruststoreToolOptions as Zo, createLocalStartApiCommand as Zr, resolveDeployedKvsArnByName as Zt, filterStudioTargetGroups as _, resolveRuntimeFileExtension as _a, verifyJwtViaDiscovery as _i, pickKvsLogicalIdFromArn as _n, containsDynamicReference as _o, isLocalCdkAssetImage as _r, sqsEmulatorOriginOf as _s, attachAgentCoreWsBridge as _t, createLocalStudioCommand as a, buildLoopbackForwarderDockerArgs as aa, filterRoutesByApiIdentifiers as ai, serveLambdaUrlOrigin as an, pickAgentCoreCandidateStack as ao, resolveSharedSidecarCredentials as ar, resolveAwsEmulatorOption as as, disposeMicrovmCodeArtifact as at, renderStudioHtml as b, assertEcsTaskCommandsResolved as ba, evaluateCachedLambdaPolicy as bi, pickWebFunctionEndpointLogicalIdFromOrigin as bn, keysNotFromTemplate as bo, CloudMapRegistry as br, buildStsClientConfig as bs, addStartCloudFrontSpecificOptions as bt, startStudioProxy as c, ensureForwarderImage as ca, startApiServer as ci, buildEdgeRequestEvent as cn, formatStateRemedy as co, buildImageOverrideTag as cr, setActiveWorkloadAwsWiring as cs, resolveMicrovmImageTarget as ct, createStudioDispatcher as d, buildContainerImage as da, defaultCredentialsLoader as di, httpHeadersToEdge as dn, LocalInvokeBuildError as do, mergeForService as dr, MIXED_MODE_RESIGN_BODY_CAP_BYTES as ds, createLocalStartWebFunctionCommand as dt, resolveHostGatewayExtraHosts as ea, createAuthorizerCache as ei, createS3OriginReader as en, AGENTCORE_AGUI_PROTOCOL as eo, buildEcsImageResolutionContext$1 as er, mergeJavaToolOptions as es, runHookBody as et, filterStudioCustomResources as f, dockerRegistryEnv as fa, buildCognitoJwksUrl as fi, CLOUDFRONT_DISTRIBUTION_TYPE as fn, ambientDefaultRegion as fo, parseImageOverrideFlags as fr, REAL_SQS_QUEUE_URL as fs, addStartAgentCoreSpecificOptions as ft, annotatePinnedEcsTargets as g, resolveRuntimeCodeMountPath as ga, verifyJwtAuthorizer as gi, pickFunctionUrlLogicalIdFromOrigin as gn, DynamicReferenceResolver as go, imageOverrideKeyAliases as gr, rewriteSqsQueueUrlsInEnv as gs, startAgentCoreHttpServer as gt, annotateEcsTaskPinnedTargets as h, stripEcrCredentials as ha, verifyCognitoJwt as hi, isCloudFrontDistribution as hn, DynamicReferenceResolutionError as ho, describePinnedImageUri as hr, repointLocalSqsQueueUrlsInEnv as hs, selectServeInboundAuth as ht, coerceStopRequest as i, awaitLoopbackForwarderStatus as ia, filterRoutesByApiIdentifier as ii, serveFromStaticOrigin as in, AgentCoreResolutionError as io, resolveEcsAssumeRoleOption as ir, readProfileEndpointSettings as is, MicrovmResolutionError as it, readRunHookPayload as j, groupWorkloadsRoutedApart as ja, applyAuthorizerOverlay as ji, createCloudFrontModule as jn, recordAssumedRole as jo, A2A_PATH as jr, startWebFunctionContainer as jt, finalizeMicrovmEnv as k, UNNAMED_WORKLOAD as ka, matchRoute as ki, runViewerResponse as kn, deployAccountStsClientConfig as ko, invokeAgentCoreWs as kr, planWebFunctionContainer as kt, relayServeRequest as l, startLoopbackForwarder as la, resolveSelectionExpression as li, buildEdgeResponseEvent as ln, substituteImagePlaceholders as lo, canonicalizeImageOverrideKeys as lr, takeAwsEmulatorStateSourceHint as ls, s3KeyOfUri as lt, annotateAlbPinnedBackingServices as m, noImplicitEcrPullArgs as ma, createJwksCache as mi, extractKvsAssociations as mn, setAmbientDefaultRegion as mo, runImageOverrideBuilds as mr, realSqsHostnames as ms, buildAgentCoreServeAuthCheck as mt, coerceRunRequest as n, withWorkloadAwsWiring as na, buildStageMap as ni, startCloudFrontServer as nn, AGENTCORE_MCP_PROTOCOL as no, parseMaxTasks as nr, probeAwsEmulatorHealth as ns, MICROVM_DEFAULT_INGRESS_PORT as nt, resolveServeBaseUrl as o, buildNamespaceOwnerForwarderDockerArgs as oa, groupRoutesByServer as oi, applyEdgeRequestResult as on, resolveAgentCoreTarget as oo, runEcsServiceEmulator as or, resolveHostDefaultCredentials as os, readMicrovmImageConfig as ot, isCustomResourceLambdaTarget as p, isEcrRegistryConfigKey as pa, buildJwksUrlFromIssuer as pi, describeS3OriginDomain as pn, namedEnvAwsRegion as po, resolveImageOverrides as pr, isRealAwsHost as ps, createLocalStartAgentCoreCommand as pt, MAX_RUN_HOOK_PAYLOAD_BYTES as q, filterWebSocketApisByIdentifiers as qa, classifySourceChange as qi, serviceStrategy as qn, effectiveLoopbackPorts as qo, computeCodeImageTag as qr, webFunctionFidelityWarnings as qt, coerceServeRequest as r, LOOPBACK_FORWARDER_IMAGE as ra, availableApiIdentifiers as ri, resolveErrorResponseCandidates as rn, AGENTCORE_RUNTIME_TYPE as ro, parseRestartPolicy as rr, readEmulatorRunFiles as rs, MICROVM_IMAGE_TYPE as rt, createStudioServeManager as s, describeForwarderFailure as sa, readMtlsMaterialsFromDisk as si, applyEdgeResponseResult as sn, derivePseudoParametersFromRegion as so, ImageOverrideError as sr, resolveWorkloadAwsWiring as ss, resolveMicrovmCodeArtifact as st, addStudioSpecificOptions as t, attachLoopbackForwarder as ta, attachStageContext as ti, matchBehavior as tn, AGENTCORE_HTTP_PROTOCOL as to, ecsClusterOption as tr, parseAwsEndpoint as ts, waitForAppAnswer as tt, reinvoke as u, architectureToPlatform as ua, resolveServiceIntegrationParameters as ui, edgeHeadersToHttp as un, tryResolveImageFnJoin as uo, enforceImageOverrideOrphans as ur, writeCaBundleFile as us, addStartWebFunctionSpecificOptions as ut, startStudioServer as v, resolveRuntimeImage as va, buildMethodArn as vi, pickLambdaEdgeFunctionLogicalId as vn, deployedFillMayBeSecret as vo, listPinnedTargets as vr, buildJavaTrustStore as vs, startAgentCoreWsBridge as vt, createLocalListCommand as w, substituteAgainstStateAsync as wa, applyCorsResponseHeaders as wi, WEB_FUNCTION_TYPE as wn, withoutKeys as wo, getContainerNetworkIp as wr, parseOriginOverrides as wt, createStudioStore as x, assertEcsTaskImagesResolvable as xa, invokeRequestAuthorizer as xi, resolveCloudFrontDistribution as xn, keysOverriddenBy as xo, DEFAULT_SHADOW_READY_TIMEOUT_MS as xr, resolveProfileCredentials as xs, createLocalStartCloudFrontCommand as xt, toStudioTargetGroups as y, EcsTaskResolutionError as ya, computeRequestIdentityHash as yi, pickTargetFunctionLogicalId as yn, firstUsableRegion as yo, buildCloudMapIndex as yr, createMixedModeTlsMaterials as ys, LocalStartCloudFrontError as yt, MICROVM_CONTROL_PATH as z, resolveSsmParameters as za, bufferToBody as zi, albStrategy as zn, HOST_CA_TRUST_ENV_KEYS as zo, signAgentCoreInvocation as zr, disposeWebFunctionArtifact as zt };
37300
- //# sourceMappingURL=local-studio-CAxQV9HT.js.map
37722
+ //# sourceMappingURL=local-studio-D_aFesGK.js.map