cdk-local 0.160.1 → 0.161.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.
@@ -1,21 +1,18 @@
1
- import { C as sanitizeServiceExceptionMessage, S as isAwsServiceException, _ as resolveAssemblyPath, a as isDockerClientEnvKey, b as describeCredentialLoadFailure, c as runDockerStreaming, d as absoluteAssemblyPathEscape, f as assemblyPathEscape, g as renderAssemblyPathEscape, h as namesTheSameDirectory, i as getDockerCmd, l as spawnStreaming, m as isPasteableCommandArg, n as finchSecretArgvRefusal, o as isMalformedEnvKey, p as displayUntrustedValue, r as formatDockerLoginError, s as runDockerForeground, u as warnFinchArgvExposure, v as clampErrorName, w as stringifyThrown, x as flattenToOneLine, y as describeAwsFailureForWarn } from "./docker-cmd-CoZdbeos.js";
2
1
  import { a as displayIdent, c as getEmbedConfig, i as STACK_REF_MAX_CODE_POINTS, o as displayStackName, s as displayToolOutput, t as getLogger, u as setEmbedConfig } from "./logger-Co5XVwco.js";
2
+ import { A as warnWorkloadCredentialsStripped, B as formatAuthority, C as accountLookupStsClientConfig, H as hostFromAuthority, I as proxyAwareFetch, M as workloadStsClientConfig, N as buildProxyClientConfig, R as isLoopbackHostname, V as formatHostForAuthority, _ as resolveHostDefaultCredentials, a as activateWorkloadAwsWiring, j as workloadClientConfig, l as effectiveLoopbackPorts, o as applyWorkloadAwsWiringToEnv, s as awsEmulatorEnvName, u as getActiveWorkloadAwsWiring, w as applyWorkloadEnvCredentials, z as isWildcardHostname } from "./workload-aws-wiring-BIxf0jtl.js";
3
+ import { c as clampErrorName, d as flattenToOneLine, f as isAwsServiceException, l as describeAwsFailureForWarn, m as stringifyThrown, o as renderAssemblyPathEscape, p as sanitizeServiceExceptionMessage, r as displayUntrustedValue, s as resolveAssemblyPath, t as absoluteAssemblyPathEscape, u as describeCredentialLoadFailure } from "./assembly-path-R96uhMm1.js";
4
+ import { A as parseEcrRegistryHost, B as RouteDiscoveryError, C as warnIfEmulatedPlatform, D as buildDockerImage, E as pullEcrImage, F as tryResolveImageFnJoin, G as applyRoleArnIfSet, H as withErrorHandling, I as CdkLocalError, J as isIamRoleArn, K as assumeRoleCredentials, L as InteractiveTtyRequiredError, M as derivePseudoParametersFromRegion, N as formatStateRemedy, O as resolveAssetSourcePath, P as substituteImagePlaceholders, R as LocalInvokeBuildError, S as buildContainerImage, T as parseEcrUri, U as defineOwnKey, V as TargetSelectionCancelledError, W as AssumeRoleFailure, X as buildStsClientConfig, Y as refusedRoleArnMessage, Z as resolveProfileCredentials, a as describeRefusedSensitiveEnvKeys, c as execEnvForSecrets, d as pullImage, f as removeContainer, i as attachLoopbackForwarder, j as derivePartitionAndUrlSuffix, k as describeExitWithoutArgv, l as pickFreePort, m as streamLogs, n as SENSITIVE_ENV_KEYS, p as runDetached, q as describeRejectedRoleArn, r as appendEnvFlags, s as ensureDockerAvailable, t as DockerRunnerError, u as prepareLoopbackForwarder, w as isImageInLocalCache, x as architectureToPlatform, z as LocalStartServiceError } from "./docker-runner-CnXQIUjd.js";
5
+ import { a as isDockerClientEnvKey, c as runDockerStreaming, i as getDockerCmd, n as finchSecretArgvRefusal, o as isMalformedEnvKey, u as warnFinchArgvExposure } from "./docker-cmd-Cjg3jGYF.js";
3
6
  import { chmodSync, cpSync, createWriteStream, existsSync, lstatSync, mkdirSync, mkdtempSync, promises, readFileSync, readdirSync, readlinkSync, realpathSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
4
- import { homedir, hostname, tmpdir } from "node:os";
5
- import * as nodePath from "node:path";
6
- import path, { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
7
7
  import { Command, InvalidArgumentError, Option } from "commander";
8
- import { AssumeRoleCommand, GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
8
+ import { STSClient } from "@aws-sdk/client-sts";
9
9
  import * as nodeCrypto from "node:crypto";
10
10
  import { X509Certificate, createHash, createHmac, createPublicKey, createVerify, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
11
- import { Agent, createServer, request } from "node:http";
12
- import { Agent as Agent$1, createServer as createServer$1, request as request$1 } from "node:https";
13
- import { brotliDecompressSync, gunzipSync, inflateSync } from "node:zlib";
14
- import { NodeHttpHandler } from "@smithy/node-http-handler";
15
- import { Agent as Agent$2 } from "agent-base";
16
- import { HttpProxyAgent } from "http-proxy-agent";
17
- import { HttpsProxyAgent } from "https-proxy-agent";
18
- import { getProxyForUrl } from "proxy-from-env";
11
+ import { createServer, request } from "node:http";
12
+ import { createServer as createServer$1 } from "node:https";
13
+ import * as nodePath from "node:path";
14
+ import path, { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
15
+ import { homedir, hostname, tmpdir } from "node:os";
19
16
  import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager";
20
17
  import { GetParameterCommand, GetParametersCommand, SSMClient } from "@aws-sdk/client-ssm";
21
18
  import { unzipSync } from "fflate";
@@ -25,10 +22,8 @@ import { CloudFormationClient, DescribeStacksCommand, ListExportsCommand, ListSt
25
22
  import { GetFunctionConfigurationCommand, LambdaClient } from "@aws-sdk/client-lambda";
26
23
  import { BedrockAgentCoreControlClient, GetAgentRuntimeCommand } from "@aws-sdk/client-bedrock-agentcore-control";
27
24
  import { execFile, spawn } from "node:child_process";
28
- import { connect, createServer as createServer$2 } from "node:net";
29
- import { StringDecoder } from "node:string_decoder";
25
+ import { connect } from "node:net";
30
26
  import { promisify } from "node:util";
31
- import { ECRClient, GetAuthorizationTokenCommand } from "@aws-sdk/client-ecr";
32
27
  import { readFile } from "fs/promises";
33
28
  import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, posix, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "path";
34
29
  import { WebSocket, WebSocketServer } from "ws";
@@ -53,603 +48,6 @@ import { promisify as promisify$1 } from "util";
53
48
  import { randomUUID as randomUUID$1 } from "crypto";
54
49
  import { EventEmitter } from "node:events";
55
50
 
56
- //#region src/utils/url-authority.ts
57
- const IPV6_LITERAL_CHARS = /^[0-9A-Fa-f:.]+$/;
58
- function formatHostForAuthority(host) {
59
- const inner = host.length > 1 && host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
60
- if (!inner.includes(":")) return host;
61
- const zoneAt = inner.indexOf("%");
62
- const literal = zoneAt === -1 ? inner : inner.slice(0, zoneAt);
63
- if (!IPV6_LITERAL_CHARS.test(literal)) return host;
64
- return `[${literal}]`;
65
- }
66
- function formatAuthority(host, port) {
67
- return `${formatHostForAuthority(host)}:${port}`;
68
- }
69
- function hostFromAuthority(authority) {
70
- if (authority.startsWith("[")) {
71
- const close = authority.indexOf("]");
72
- if (close === -1) return "";
73
- const afterBracket = authority.slice(close + 1);
74
- if (afterBracket !== "" && !/^:\d+$/.test(afterBracket)) return "";
75
- return authority.slice(1, close);
76
- }
77
- const firstColon = authority.indexOf(":");
78
- if (firstColon === -1) return authority;
79
- if (authority.includes(":", firstColon + 1)) return "";
80
- return authority.slice(0, firstColon);
81
- }
82
-
83
- //#endregion
84
- //#region src/utils/loopback-host.ts
85
- function normaliseHostLiteral(hostname) {
86
- return hostname.trim().replace(/^\[/, "").replace(/\]$/, "").toLowerCase();
87
- }
88
- function isLoopbackLiteral(h) {
89
- if (h === "localhost") return true;
90
- if (h === "::1" || h === "0:0:0:0:0:0:0:1") return true;
91
- const mapped = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(h);
92
- if (mapped) return parseInt(mapped[1], 16) >> 8 === 127;
93
- const dotted = /^(?:::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(h);
94
- if (!dotted) return false;
95
- const octets = dotted.slice(1).map(Number);
96
- if (octets.some((o) => o > 255)) return false;
97
- return octets[0] === 127;
98
- }
99
- function isWildcardLiteral(h) {
100
- return h === "0.0.0.0" || h === "::" || h === "0:0:0:0:0:0:0:0" || h === "::ffff:0.0.0.0" || h === "::ffff:0:0";
101
- }
102
- function isLoopbackHostname(hostname) {
103
- return isLoopbackLiteral(normaliseHostLiteral(hostname));
104
- }
105
- function isWildcardHostname(hostname) {
106
- return isWildcardLiteral(normaliseHostLiteral(hostname));
107
- }
108
- function isLoopbackHost(hostname) {
109
- const h = normaliseHostLiteral(hostname).replace(/\.$/, "");
110
- return h.endsWith(".localhost") || isLoopbackLiteral(h) || isWildcardLiteral(h);
111
- }
112
-
113
- //#endregion
114
- //#region src/utils/aws-proxy.ts
115
- const AGENT_OPTS = {
116
- keepAlive: true,
117
- maxSockets: 50
118
- };
119
- function isProxyEnvConfigured() {
120
- return PROXY_ENV_VARIABLES.some((key) => Boolean(process.env[key]));
121
- }
122
- const PROXY_ENV_VARIABLES = [
123
- "https_proxy",
124
- "HTTPS_PROXY",
125
- "http_proxy",
126
- "HTTP_PROXY",
127
- "all_proxy",
128
- "ALL_PROXY"
129
- ];
130
- function isSpeakableProxyEnvValue(value) {
131
- return !value.includes("://") || isSpeakableProxy(value.trim());
132
- }
133
- const AWS_ENDPOINT_PROBES = ["https://sts.amazonaws.com", "http://sts.amazonaws.com"];
134
- function everySetProxyEnvValueIsUnspeakable() {
135
- const set = PROXY_ENV_VARIABLES.map((key) => process.env[key] ?? "").filter((v) => v !== "");
136
- return set.length > 0 && !set.some(isSpeakableProxyEnvValue);
137
- }
138
- const warnedProxySchemes = /* @__PURE__ */ new Set();
139
- function proxySchemeOf(proxyUrl) {
140
- const match = /^([a-z][a-z0-9+.-]{0,31}):\/\//i.exec(proxyUrl);
141
- return match ? match[1].toLowerCase() : "(unrecognized)";
142
- }
143
- function isSpeakableProxy(proxyUrl) {
144
- return /^https?:\/\//i.test(proxyUrl);
145
- }
146
- function warnUnspeakableProxy(proxyUrl) {
147
- const scheme = proxySchemeOf(proxyUrl);
148
- if (warnedProxySchemes.has(scheme)) return;
149
- try {
150
- getLogger().child("aws-proxy").warn(`Unsupported proxy scheme "${scheme}" — cdk-local speaks HTTP CONNECT proxies only, so requests it would carry go DIRECT instead of through the proxy. Set HTTPS_PROXY / HTTP_PROXY / ALL_PROXY to an http:// or https:// proxy URL. (The proxy URL is withheld here: it can carry credentials.)`);
151
- } catch {
152
- return;
153
- }
154
- warnedProxySchemes.add(scheme);
155
- }
156
- function resolveProxyForTarget(targetHref) {
157
- const proxyUrl = getProxyForUrl(targetHref).trim();
158
- if (proxyUrl === "") return "";
159
- if (isSpeakableProxy(proxyUrl)) return proxyUrl;
160
- warnUnspeakableProxy(proxyUrl);
161
- return "";
162
- }
163
- var EnvRoutingProxyAgent = class extends Agent$2 {
164
- proxyAgents = /* @__PURE__ */ new Map();
165
- directHttpAgent = new Agent(AGENT_OPTS);
166
- directHttpsAgent = new Agent$1(AGENT_OPTS);
167
- constructor() {
168
- super(AGENT_OPTS);
169
- }
170
- connect(_req, options) {
171
- const secure = options.secureEndpoint;
172
- const host = options.host ?? "localhost";
173
- const port = options.port || (secure ? 443 : 80);
174
- const proxyUrl = resolveProxyForTarget(`${secure ? "https" : "http"}://${formatAuthority(host, port)}`);
175
- if (!proxyUrl) return secure ? this.directHttpsAgent : this.directHttpAgent;
176
- const key = `${secure ? "https" : "http"}|${proxyUrl}`;
177
- let agent = this.proxyAgents.get(key);
178
- if (!agent) {
179
- agent = secure ? new HttpsProxyAgent(proxyUrl, AGENT_OPTS) : new HttpProxyAgent(proxyUrl, AGENT_OPTS);
180
- this.proxyAgents.set(key, agent);
181
- }
182
- return agent;
183
- }
184
- destroy() {
185
- for (const agent of this.proxyAgents.values()) agent.destroy();
186
- this.proxyAgents.clear();
187
- this.directHttpAgent.destroy();
188
- this.directHttpsAgent.destroy();
189
- super.destroy();
190
- }
191
- };
192
- function buildProxyRequestHandler() {
193
- const agent = new EnvRoutingProxyAgent();
194
- return new NodeHttpHandler({
195
- httpAgent: agent,
196
- httpsAgent: agent
197
- });
198
- }
199
- function buildProxyClientConfig(opts = {}) {
200
- if (!isProxyEnvConfigured()) return {};
201
- if (everySetProxyEnvValueIsUnspeakable()) {
202
- for (const probe of AWS_ENDPOINT_PROBES) resolveProxyForTarget(probe);
203
- return {};
204
- }
205
- const profile = opts.profile;
206
- let chain;
207
- const credentials = async (identityProperties) => {
208
- chain ??= (async () => {
209
- const { defaultProvider } = await import("@aws-sdk/credential-provider-node");
210
- return defaultProvider({
211
- ...profile ? { profile } : {},
212
- clientConfig: { requestHandler: buildProxyRequestHandler() }
213
- });
214
- })().catch((err) => {
215
- chain = void 0;
216
- throw err;
217
- });
218
- return (await chain)(identityProperties);
219
- };
220
- return {
221
- requestHandler: buildProxyRequestHandler(),
222
- credentials
223
- };
224
- }
225
- const MAX_FETCH_REDIRECTS = 20;
226
- const NULL_BODY_STATUSES = /* @__PURE__ */ new Set([
227
- 204,
228
- 205,
229
- 304
230
- ]);
231
- const REQUEST_STALL_TIMEOUT_MS = 3e5;
232
- function isRedirectStatus(status) {
233
- return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
234
- }
235
- function parseHttpUrl(href) {
236
- const parsed = new URL(href);
237
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new TypeError(`Unsupported protocol for a proxied request: "${parsed.protocol}"`);
238
- return parsed;
239
- }
240
- function getThroughAgent(url, agent, timeoutMs = REQUEST_STALL_TIMEOUT_MS) {
241
- return new Promise((resolve, reject) => {
242
- let settled = false;
243
- let timer;
244
- let rearm = () => void 0;
245
- const succeed = (value) => {
246
- if (settled) return;
247
- settled = true;
248
- if (timer) clearTimeout(timer);
249
- resolve(value);
250
- };
251
- const fail = (err) => {
252
- if (settled) return;
253
- settled = true;
254
- if (timer) clearTimeout(timer);
255
- reject(err);
256
- };
257
- const req = (url.protocol === "https:" ? request$1 : request)(url, {
258
- agent,
259
- headers: {
260
- accept: "*/*",
261
- "accept-encoding": "identity"
262
- }
263
- }, (res) => {
264
- rearm();
265
- const chunks = [];
266
- res.on("data", (chunk) => {
267
- rearm();
268
- chunks.push(chunk);
269
- });
270
- res.on("error", fail);
271
- res.on("end", () => {
272
- if (res.statusCode === void 0) {
273
- fail(/* @__PURE__ */ new Error("Malformed HTTP response: no status code"));
274
- return;
275
- }
276
- succeed({
277
- status: res.statusCode,
278
- statusText: res.statusMessage ?? "",
279
- headers: res.headers,
280
- body: Buffer.concat(chunks)
281
- });
282
- });
283
- });
284
- req.on("error", fail);
285
- rearm = () => {
286
- if (settled) return;
287
- if (timer) clearTimeout(timer);
288
- timer = setTimeout(() => {
289
- req.destroy();
290
- fail(/* @__PURE__ */ new Error(`Proxied request stalled for ${timeoutMs} ms with no progress`));
291
- }, timeoutMs);
292
- timer.unref?.();
293
- };
294
- rearm();
295
- req.end();
296
- });
297
- }
298
- function decodeContentEncoding(raw) {
299
- const header = raw.headers["content-encoding"];
300
- const encoding = (Array.isArray(header) ? header.join(",") : header ?? "").trim().toLowerCase();
301
- if (encoding === "" || encoding === "identity") return {
302
- body: raw.body,
303
- decoded: false
304
- };
305
- try {
306
- if (encoding === "gzip" || encoding === "x-gzip") return {
307
- body: gunzipSync(raw.body),
308
- decoded: true
309
- };
310
- if (encoding === "deflate" || encoding === "x-deflate") return {
311
- body: inflateSync(raw.body),
312
- decoded: true
313
- };
314
- if (encoding === "br") return {
315
- body: brotliDecompressSync(raw.body),
316
- decoded: true
317
- };
318
- } catch {
319
- return {
320
- body: raw.body,
321
- decoded: false
322
- };
323
- }
324
- return {
325
- body: raw.body,
326
- decoded: false
327
- };
328
- }
329
- function toWebResponse(raw) {
330
- if (raw.status < 200 || raw.status > 599) throw new Error(`Unsupported HTTP status in response: ${raw.status}`);
331
- const { body, decoded } = decodeContentEncoding(raw);
332
- const headers = new Headers();
333
- for (const [name, value] of Object.entries(raw.headers)) {
334
- if (value === void 0) continue;
335
- if (decoded && (name === "content-encoding" || name === "content-length")) continue;
336
- if (Array.isArray(value)) for (const one of value) headers.append(name, one);
337
- else headers.append(name, value);
338
- }
339
- return new Response(NULL_BODY_STATUSES.has(raw.status) ? null : body, {
340
- status: raw.status,
341
- statusText: raw.statusText.replace(/[^\t\x20-\x7e\x80-\xff]/g, ""),
342
- headers
343
- });
344
- }
345
- async function proxyAwareFetch(url, opts = {}) {
346
- if (!isProxyEnvConfigured()) return globalThis.fetch(url);
347
- let target = parseHttpUrl(url);
348
- for (let hop = 0;; hop++) {
349
- if (isLoopbackHost(target.hostname) || resolveProxyForTarget(target.href) === "") return globalThis.fetch(target.href);
350
- const agent = new EnvRoutingProxyAgent();
351
- let raw;
352
- try {
353
- raw = await getThroughAgent(target, agent, opts.timeoutMs);
354
- } finally {
355
- agent.destroy();
356
- }
357
- const location = raw.headers["location"];
358
- if (!isRedirectStatus(raw.status) || typeof location !== "string" || location === "") return toWebResponse(raw);
359
- if (hop >= MAX_FETCH_REDIRECTS) throw new Error(`Too many redirects (more than ${MAX_FETCH_REDIRECTS})`);
360
- target = parseHttpUrl(new URL(location, target).href);
361
- }
362
- }
363
-
364
- //#endregion
365
- //#region src/utils/profile-resolver.ts
366
- async function resolveProfileCredentials(profile) {
367
- const sts = new STSClient(buildStsClientConfig({ profile }));
368
- try {
369
- const credsProvider = sts.config.credentials;
370
- const creds = typeof credsProvider === "function" ? await credsProvider() : credsProvider;
371
- if (!creds || !creds.accessKeyId || !creds.secretAccessKey) {
372
- const ssoHint = isPasteableCommandArg(profile) ? "Check `aws sso login --profile " + profile + "` for SSO profiles" : "For an SSO profile, run `aws sso login` for that profile (the command is not written out because the name as rendered may not be the one your shell would act on)";
373
- throw new Error(`--profile ${displayUntrustedValue(profile)}: credential provider chain resolved without usable credentials. ${ssoHint}, or check \`~/.aws/credentials\` / \`~/.aws/config\` for regular profiles.`);
374
- }
375
- let region;
376
- try {
377
- const regionProvider = sts.config.region;
378
- const resolved = typeof regionProvider === "function" ? await regionProvider() : regionProvider;
379
- if (typeof resolved === "string" && resolved.length > 0) region = resolved;
380
- } catch (err) {
381
- const msg = err instanceof Error ? err.message : String(err);
382
- if (!(/region is missing/i.test(msg) || /could not resolve region/i.test(msg) || /no region in config/i.test(msg) || /region.*not.*set/i.test(msg))) throw err;
383
- region = void 0;
384
- }
385
- return {
386
- accessKeyId: creds.accessKeyId,
387
- secretAccessKey: creds.secretAccessKey,
388
- ...creds.sessionToken && { sessionToken: creds.sessionToken },
389
- ...region && { region }
390
- };
391
- } finally {
392
- sts.destroy();
393
- }
394
- }
395
- function buildStsClientConfig(args) {
396
- return {
397
- ...buildProxyClientConfig({ profile: args.profile }),
398
- ...args.region && { region: args.region },
399
- ...args.profile && { profile: args.profile }
400
- };
401
- }
402
-
403
- //#endregion
404
- //#region src/utils/workload-identity.ts
405
- function copyCredentials(c) {
406
- return c ? {
407
- accessKeyId: c.accessKeyId,
408
- secretAccessKey: c.secretAccessKey,
409
- ...c.sessionToken ? { sessionToken: c.sessionToken } : {}
410
- } : void 0;
411
- }
412
- let record;
413
- let stripWarned = false;
414
- const SECOND_ASSUME_MESSAGE = "A role was already assumed in this process; refusing to assume a second one. Pass --role-arn once.";
415
- function recordAssumedRole(caller, role) {
416
- if (record !== void 0) throw new Error(SECOND_ASSUME_MESSAGE);
417
- record = {
418
- caller: copyCredentials(caller),
419
- role: copyCredentials(role)
420
- };
421
- }
422
- function assumedRoleRecorded() {
423
- return record !== void 0;
424
- }
425
- function readEnvCallerCredentials(env = process.env) {
426
- const accessKeyId = env["AWS_ACCESS_KEY_ID"];
427
- const secretAccessKey = env["AWS_SECRET_ACCESS_KEY"];
428
- if (!accessKeyId || !secretAccessKey) return void 0;
429
- const sessionToken = env["AWS_SESSION_TOKEN"];
430
- return {
431
- accessKeyId,
432
- secretAccessKey,
433
- ...sessionToken ? { sessionToken } : {}
434
- };
435
- }
436
- function resetWorkloadIdentity() {
437
- record = void 0;
438
- stripWarned = false;
439
- }
440
- function callerRecord() {
441
- return getEmbedConfig().workloadIdentity === "caller" ? record : void 0;
442
- }
443
- const MULTIPLE_CREDENTIAL_SOURCES_WARNING = "Multiple credential sources detected";
444
- const chainLogger = {
445
- debug: () => {},
446
- info: () => {},
447
- warn: (...args) => {
448
- const text = args.map(String).join(" ");
449
- if (text.includes(MULTIPLE_CREDENTIAL_SOURCES_WARNING)) return;
450
- getLogger().warn(text);
451
- },
452
- error: (...args) => {
453
- getLogger().error(args.map(String).join(" "));
454
- }
455
- };
456
- function callerChainWithoutEnv(proxied) {
457
- let chain;
458
- return async (identityProperties) => {
459
- chain ??= (async () => {
460
- const { defaultProvider } = await import("@aws-sdk/credential-provider-node");
461
- return defaultProvider({
462
- profile: "default",
463
- logger: chainLogger,
464
- ...proxied ? { clientConfig: { requestHandler: buildProxyRequestHandler() } } : {}
465
- });
466
- })().catch((err) => {
467
- chain = void 0;
468
- throw err;
469
- });
470
- return (await chain)(identityProperties);
471
- };
472
- }
473
- function workloadClientConfig(opts = {}) {
474
- const base = buildProxyClientConfig({ profile: opts.profile });
475
- const rec = callerRecord();
476
- if (!rec) return base;
477
- if (opts.profile || process.env["AWS_PROFILE"]) return base;
478
- if (rec.caller) {
479
- const caller = rec.caller;
480
- const credentials = async () => ({
481
- accessKeyId: caller.accessKeyId,
482
- secretAccessKey: caller.secretAccessKey,
483
- ...caller.sessionToken ? { sessionToken: caller.sessionToken } : {}
484
- });
485
- return {
486
- ...base,
487
- credentials
488
- };
489
- }
490
- return {
491
- ...base,
492
- credentials: callerChainWithoutEnv(base.requestHandler !== void 0)
493
- };
494
- }
495
- function workloadStsClientConfig(args) {
496
- return {
497
- ...workloadClientConfig({ profile: args.profile }),
498
- ...args.region && { region: args.region },
499
- ...args.profile && { profile: args.profile }
500
- };
501
- }
502
- function deployAccountStsClientConfig(args) {
503
- const role = callerRecord()?.role;
504
- if (!role) return {
505
- ...buildProxyClientConfig({ profile: args.profile }),
506
- ...args.region && { region: args.region },
507
- ...args.profile && { profile: args.profile }
508
- };
509
- const credentials = async () => ({
510
- accessKeyId: role.accessKeyId,
511
- secretAccessKey: role.secretAccessKey,
512
- ...role.sessionToken ? { sessionToken: role.sessionToken } : {}
513
- });
514
- return {
515
- ...buildProxyClientConfig(),
516
- ...args.region && { region: args.region },
517
- ...args.profile && { profile: args.profile },
518
- credentials
519
- };
520
- }
521
- function accountLookupStsClientConfig(args) {
522
- return args.readFromCfnStack ? workloadStsClientConfig({
523
- region: args.region,
524
- profile: args.profile
525
- }) : deployAccountStsClientConfig({
526
- region: args.region,
527
- profile: args.profile
528
- });
529
- }
530
- function applyWorkloadEnvCredentials(env) {
531
- const rec = callerRecord();
532
- if (!rec) return "unchanged";
533
- if (rec.caller) {
534
- env["AWS_ACCESS_KEY_ID"] = rec.caller.accessKeyId;
535
- env["AWS_SECRET_ACCESS_KEY"] = rec.caller.secretAccessKey;
536
- if (rec.caller.sessionToken) env["AWS_SESSION_TOKEN"] = rec.caller.sessionToken;
537
- else delete env["AWS_SESSION_TOKEN"];
538
- return "restored";
539
- }
540
- delete env["AWS_ACCESS_KEY_ID"];
541
- delete env["AWS_SECRET_ACCESS_KEY"];
542
- delete env["AWS_SESSION_TOKEN"];
543
- return "stripped";
544
- }
545
- function warnWorkloadCredentialsStripped() {
546
- if (stripWarned) return;
547
- stripWarned = true;
548
- getLogger().warn("The --role-arn role is not handed to the emulated workload, and your shell had no static AWS credentials to hand it instead, so the container receives none. Pass --profile <name>, or export static credentials, to give it an identity.");
549
- }
550
-
551
- //#endregion
552
- //#region src/utils/role-arn.ts
553
- const IAM_ROLE_ARN_MAX_LENGTH = 2048;
554
- const IAM_ROLE_ARN_PATTERN = /^arn:[A-Za-z0-9-]+:iam::[0-9]+:role\/[!-~]+$/;
555
- function isIamRoleArn(value) {
556
- if (typeof value !== "string") return false;
557
- if (value.length > 2048) return false;
558
- return IAM_ROLE_ARN_PATTERN.test(value);
559
- }
560
- const REJECTED_ARN_PREVIEW_MAX = 128;
561
- function describeRejectedRoleArn(value) {
562
- if (typeof value !== "string") return `a non-string ${typeof value} value`;
563
- const points = [...flattenToOneLine(value)];
564
- return `"${points.length <= REJECTED_ARN_PREVIEW_MAX ? points.join("") : `${points.slice(0, REJECTED_ARN_PREVIEW_MAX).join("")}...`}" (${points.length} characters)`;
565
- }
566
- function refusedRoleArnMessage(value) {
567
- return `AssumeRole refused: the role ARN is not a well-formed IAM role ARN (expected arn:<partition>:iam::<account>:role/<name>, at most ${IAM_ROLE_ARN_MAX_LENGTH} characters): ${describeRejectedRoleArn(value)}. Nothing was sent to STS.`;
568
- }
569
- var AssumeRoleFailure = class AssumeRoleFailure extends Error {
570
- detail;
571
- constructor(message, detail) {
572
- super(message);
573
- this.name = "AssumeRoleFailure";
574
- this.detail = detail;
575
- Object.setPrototypeOf(this, AssumeRoleFailure.prototype);
576
- }
577
- };
578
- async function assumeRoleCredentials(opts) {
579
- if (!isIamRoleArn(opts.roleArn)) {
580
- const detail = `the role ARN is not well-formed: ${describeRejectedRoleArn(opts.roleArn)}`;
581
- const message = refusedRoleArnMessage(opts.roleArn);
582
- throw opts.makeError ? opts.makeError(message) : new AssumeRoleFailure(message, detail);
583
- }
584
- const sts = new STSClient(workloadStsClientConfig({
585
- region: opts.region,
586
- profile: opts.profile
587
- }));
588
- const shownArn = flattenToOneLine(opts.roleArn);
589
- let response;
590
- try {
591
- response = await sts.send(new AssumeRoleCommand({
592
- RoleArn: opts.roleArn,
593
- RoleSessionName: `${getEmbedConfig().resourceNamePrefix}-${opts.sessionNameSuffix}-${Date.now()}`,
594
- DurationSeconds: 3600
595
- }));
596
- } catch (err) {
597
- const detail = describeAwsFailureForWarn(err, "STS AssumeRole");
598
- const message = `AssumeRole(${shownArn}) failed: ${detail}`;
599
- throw opts.makeError ? opts.makeError(message) : new AssumeRoleFailure(message, detail);
600
- } finally {
601
- sts.destroy();
602
- }
603
- const creds = response.Credentials;
604
- if (!creds?.AccessKeyId || !creds.SecretAccessKey || !creds.SessionToken) {
605
- const message = `AssumeRole(${shownArn}) returned no usable credentials.`;
606
- throw opts.makeError ? opts.makeError(message) : new AssumeRoleFailure(message, "the response carried no usable credentials");
607
- }
608
- return {
609
- accessKeyId: creds.AccessKeyId,
610
- secretAccessKey: creds.SecretAccessKey,
611
- sessionToken: creds.SessionToken
612
- };
613
- }
614
- async function applyRoleArnIfSet(opts) {
615
- const roleArn = opts.roleArn || process.env[`${getEmbedConfig().envPrefix}_ROLE_ARN`];
616
- if (!roleArn) return;
617
- if (!isIamRoleArn(roleArn)) throw new Error(refusedRoleArnMessage(roleArn));
618
- if (assumedRoleRecorded() && getEmbedConfig().workloadIdentity === "caller") throw new Error(SECOND_ASSUME_MESSAGE);
619
- const logger = getLogger().child("role-arn");
620
- const shownArn = flattenToOneLine(roleArn);
621
- logger.debug(`Assuming role ${shownArn}...`);
622
- const sts = new STSClient(buildStsClientConfig({
623
- region: opts.region,
624
- profile: opts.profile
625
- }));
626
- let response;
627
- try {
628
- response = await sts.send(new AssumeRoleCommand({
629
- RoleArn: roleArn,
630
- RoleSessionName: `${getEmbedConfig().binaryName}-${Date.now()}`,
631
- DurationSeconds: 3600
632
- }));
633
- } catch (err) {
634
- throw new Error(`AssumeRole(${shownArn}) failed: ${describeAwsFailureForWarn(err, "STS AssumeRole")}`);
635
- } finally {
636
- sts.destroy();
637
- }
638
- if (!response.Credentials) throw new Error(`AssumeRole returned no credentials for role ${shownArn}`);
639
- const { AccessKeyId, SecretAccessKey, SessionToken, Expiration } = response.Credentials;
640
- if (!AccessKeyId || !SecretAccessKey || !SessionToken) throw new Error(`AssumeRole response missing credentials fields for role ${shownArn}`);
641
- if (!assumedRoleRecorded()) recordAssumedRole(readEnvCallerCredentials(), {
642
- accessKeyId: AccessKeyId,
643
- secretAccessKey: SecretAccessKey,
644
- sessionToken: SessionToken
645
- });
646
- process.env["AWS_ACCESS_KEY_ID"] = AccessKeyId;
647
- process.env["AWS_SECRET_ACCESS_KEY"] = SecretAccessKey;
648
- process.env["AWS_SESSION_TOKEN"] = SessionToken;
649
- logger.info(`Assumed role ${shownArn} (session expires ${Expiration?.toISOString() ?? "unknown"})`);
650
- }
651
-
652
- //#endregion
653
51
  //#region src/cli/options.ts
654
52
  function parseContextOptions(contextArgs) {
655
53
  const context = {};
@@ -668,6 +66,13 @@ function commonOptions() {
668
66
  new Option("-y, --yes", "Automatically answer interactive prompts with the recommended response").default(false)
669
67
  ];
670
68
  }
69
+ function awsEndpointOptions() {
70
+ return [new Option("--aws-emulator [url]", `Run against a local AWS Emulator (default https://127.0.0.1:9297; the port selects ~/.aws/emulator/<port>/): this command's own AWS calls (--from-cfn-stack included) and every workload container use it, and containers get only its credentials and trust its CA (env: ${awsEmulatorEnvName()})`), new Option("--ca-bundle <file>", "PEM CA bundle mounted read-only into every workload container, with AWS_CA_BUNDLE / NODE_EXTRA_CA_CERTS / REQUESTS_CA_BUNDLE / SSL_CERT_FILE pointed at it (default: the host AWS_CA_BUNDLE)")];
71
+ }
72
+ function addAwsEndpointOptions(cmd) {
73
+ for (const opt of awsEndpointOptions()) cmd.addOption(opt);
74
+ return cmd;
75
+ }
671
76
  const regionOption = new Option("--region <region>", "AWS region for SDK calls; defaults to AWS_REGION env, the synthesized stack region, or the resolved profile region");
672
77
  function appOptions() {
673
78
  const { envPrefix } = getEmbedConfig();
@@ -705,17 +110,6 @@ function effectiveAssumeRoleArn(logicalId, opt) {
705
110
  return opt.perLambda?.[logicalId] ?? opt.globalArn;
706
111
  }
707
112
 
708
- //#endregion
709
- //#region src/utils/own-keys.ts
710
- function defineOwnKey(target, key, value) {
711
- Object.defineProperty(target, key, {
712
- value,
713
- writable: true,
714
- enumerable: true,
715
- configurable: true
716
- });
717
- }
718
-
719
113
  //#endregion
720
114
  //#region src/local/dynamic-reference-resolver.ts
721
115
  var DynamicReferenceResolutionError = class DynamicReferenceResolutionError extends Error {
@@ -1054,86 +448,6 @@ async function resolveDynamicReferencesInEnv(env, options) {
1054
448
  }
1055
449
  }
1056
450
 
1057
- //#endregion
1058
- //#region src/utils/error-handler.ts
1059
- var CdkLocalError = class CdkLocalError extends Error {
1060
- code;
1061
- cause;
1062
- constructor(message, code, cause) {
1063
- super(message);
1064
- this.code = code;
1065
- this.cause = cause;
1066
- this.name = "CdkLocalError";
1067
- Object.setPrototypeOf(this, CdkLocalError.prototype);
1068
- }
1069
- };
1070
- var LocalInvokeBuildError = class LocalInvokeBuildError extends CdkLocalError {
1071
- constructor(message, cause) {
1072
- super(message, "LOCAL_INVOKE_BUILD_ERROR", cause);
1073
- this.name = "LocalInvokeBuildError";
1074
- Object.setPrototypeOf(this, LocalInvokeBuildError.prototype);
1075
- }
1076
- };
1077
- var RouteDiscoveryError = class RouteDiscoveryError extends CdkLocalError {
1078
- constructor(message, cause) {
1079
- super(message, "ROUTE_DISCOVERY_ERROR", cause);
1080
- this.name = "RouteDiscoveryError";
1081
- Object.setPrototypeOf(this, RouteDiscoveryError.prototype);
1082
- }
1083
- };
1084
- var LocalStartServiceError = class LocalStartServiceError extends CdkLocalError {
1085
- constructor(message, cause) {
1086
- super(message, "LOCAL_START_SERVICE_ERROR", cause);
1087
- this.name = "LocalStartServiceError";
1088
- Object.setPrototypeOf(this, LocalStartServiceError.prototype);
1089
- }
1090
- };
1091
- var TargetSelectionCancelledError = class TargetSelectionCancelledError extends CdkLocalError {
1092
- silent = true;
1093
- exitCode = 130;
1094
- constructor() {
1095
- super("Target selection cancelled.", "TARGET_SELECTION_CANCELLED");
1096
- this.name = "TargetSelectionCancelledError";
1097
- Object.setPrototypeOf(this, TargetSelectionCancelledError.prototype);
1098
- }
1099
- };
1100
- var InteractiveTtyRequiredError = class InteractiveTtyRequiredError extends CdkLocalError {
1101
- constructor(message) {
1102
- super(message, "INTERACTIVE_TTY_REQUIRED");
1103
- this.name = "InteractiveTtyRequiredError";
1104
- Object.setPrototypeOf(this, InteractiveTtyRequiredError.prototype);
1105
- }
1106
- };
1107
- function isCdkLocalError(error) {
1108
- return error instanceof CdkLocalError;
1109
- }
1110
- function formatError(error) {
1111
- if (isCdkLocalError(error)) {
1112
- let message = `${error.name}: ${error.message}`;
1113
- if (error.cause) message += `\nCaused by: ${error.cause.message}`;
1114
- return message;
1115
- }
1116
- if (error instanceof Error) return `${error.name}: ${error.message}`;
1117
- return String(error);
1118
- }
1119
- function handleError(error) {
1120
- const logger = getLogger();
1121
- if (!(error instanceof CdkLocalError && error.silent)) logger.error(formatError(error));
1122
- if (error instanceof Error && error.stack) logger.debug("Stack trace:", error.stack);
1123
- const customExitCode = error instanceof CdkLocalError ? error.exitCode : void 0;
1124
- const exitCode = typeof customExitCode === "number" ? customExitCode : 1;
1125
- process.exit(exitCode);
1126
- }
1127
- function withErrorHandling(fn) {
1128
- return async (...args) => {
1129
- try {
1130
- await fn(...args);
1131
- } catch (error) {
1132
- handleError(error);
1133
- }
1134
- };
1135
- }
1136
-
1137
451
  //#endregion
1138
452
  //#region src/cli/cdk-path.ts
1139
453
  function readCdkPath(resource) {
@@ -1269,301 +583,37 @@ function pathGlobMatches(pattern, subject) {
1269
583
  }
1270
584
 
1271
585
  //#endregion
1272
- //#region src/local/intrinsic-image.ts
1273
- function formatStateRemedy(context) {
1274
- if (context?.stateLoadFailureMessage) return `the state-source attempt failed: ${context.stateLoadFailureMessage}; verify the stack name (try --from-cfn-stack <deployed-name> if it differs from the synthesized name) and that --region / --profile target the right account`;
1275
- return "pass --from-cfn-stack to load the deployed stack state";
1276
- }
1277
- const PARTITION_TABLE = [
1278
- {
1279
- regionPrefix: "cn-",
1280
- partition: "aws-cn",
1281
- urlSuffix: "amazonaws.com.cn"
1282
- },
1283
- {
1284
- regionPrefix: "us-gov-",
1285
- partition: "aws-us-gov",
1286
- urlSuffix: "amazonaws.com"
1287
- },
1288
- {
1289
- regionPrefix: "us-isob-",
1290
- partition: "aws-iso-b",
1291
- urlSuffix: "sc2s.sgov.gov"
1292
- },
1293
- {
1294
- regionPrefix: "us-isof-",
1295
- partition: "aws-iso-f",
1296
- urlSuffix: "csp.hci.ic.gov"
1297
- },
1298
- {
1299
- regionPrefix: "us-iso-",
1300
- partition: "aws-iso",
1301
- urlSuffix: "c2s.ic.gov"
1302
- },
1303
- {
1304
- regionPrefix: "eu-isoe-",
1305
- partition: "aws-iso-e",
1306
- urlSuffix: "cloud.adc-e.uk"
1307
- },
1308
- {
1309
- regionPrefix: "eusc-",
1310
- partition: "aws-eusc",
1311
- urlSuffix: "amazonaws.eu"
586
+ //#region src/utils/stringify.ts
587
+ function stringifyValue(value) {
588
+ switch (typeof value) {
589
+ case "string": return value;
590
+ case "number":
591
+ case "boolean":
592
+ case "bigint": return String(value);
593
+ case "symbol": return value.toString();
594
+ case "undefined": return "undefined";
595
+ case "function": return value.name ? `[Function: ${value.name}]` : "[Function]";
596
+ case "object":
597
+ if (value === null) return "null";
598
+ try {
599
+ const json = JSON.stringify(value);
600
+ if (json !== void 0) return json;
601
+ } catch {}
602
+ return Object.prototype.toString.call(value);
1312
603
  }
1313
- ];
1314
- function derivePartitionAndUrlSuffix(region) {
1315
- const normalized = region.toLowerCase();
1316
- for (const row of PARTITION_TABLE) if (normalized.startsWith(row.regionPrefix)) return {
1317
- partition: row.partition,
1318
- urlSuffix: row.urlSuffix
1319
- };
1320
- return {
1321
- partition: "aws",
1322
- urlSuffix: "amazonaws.com"
1323
- };
1324
604
  }
1325
- function derivePseudoParametersFromRegion(region, accountId) {
1326
- if (!region || typeof region !== "string" || region.length === 0) return void 0;
1327
- const { partition, urlSuffix } = derivePartitionAndUrlSuffix(region);
1328
- return {
1329
- ...accountId !== void 0 && { accountId },
1330
- region,
1331
- partition,
1332
- urlSuffix
1333
- };
1334
- }
1335
- function tryResolveImageFnJoin(raw, resources, context) {
1336
- if (!raw || typeof raw !== "object") return { kind: "not-applicable" };
1337
- const arg = raw["Fn::Join"];
1338
- if (arg === void 0) return { kind: "not-applicable" };
1339
- if (!Array.isArray(arg) || arg.length !== 2 || !Array.isArray(arg[1])) return {
1340
- kind: "unsupported-join",
1341
- reason: "Fn::Join must be [delimiter, [elements]]"
1342
- };
1343
- const [delimiter, elements] = arg;
1344
- if (typeof delimiter !== "string") return {
1345
- kind: "unsupported-join",
1346
- reason: `Fn::Join delimiter must be a string, got ${typeof delimiter}`
1347
- };
1348
- const repoLogicalId = findEcrRepositoryRefInTree(elements, resources);
1349
- const stateResources = context?.stateResources;
1350
- if (repoLogicalId && !stateResources) return {
1351
- kind: "needs-state",
1352
- repoLogicalId
1353
- };
1354
- const parts = [];
1355
- for (const element of elements) {
1356
- const r = resolveImageIntrinsic(element, resources, context);
1357
- if (r === void 0) {
1358
- if (!repoLogicalId) return { kind: "not-applicable" };
1359
- return {
1360
- kind: "unsupported-join",
1361
- reason: "one or more Fn::Join elements could not be resolved"
1362
- };
1363
- }
1364
- parts.push(r);
1365
- }
1366
- return {
1367
- kind: "resolved",
1368
- uri: parts.join(delimiter)
1369
- };
1370
- }
1371
- function findEcrRepositoryRefInTree(node, resources) {
1372
- if (node === null || node === void 0) return void 0;
1373
- if (typeof node === "string" || typeof node === "number" || typeof node === "boolean") return;
1374
- if (Array.isArray(node)) {
1375
- for (const item of node) {
1376
- const hit = findEcrRepositoryRefInTree(item, resources);
1377
- if (hit) return hit;
1378
- }
1379
- return;
1380
- }
1381
- if (typeof node !== "object") return void 0;
1382
- const obj = node;
1383
- if (typeof obj["Ref"] === "string") {
1384
- const target = obj["Ref"];
1385
- if (resources[target]?.Type === "AWS::ECR::Repository") return target;
1386
- return;
1387
- }
1388
- const getAtt = obj["Fn::GetAtt"];
1389
- if (getAtt !== void 0) {
1390
- let lid;
1391
- if (Array.isArray(getAtt) && typeof getAtt[0] === "string") lid = getAtt[0];
1392
- else if (typeof getAtt === "string") lid = getAtt.split(".")[0];
1393
- if (lid && resources[lid]?.Type === "AWS::ECR::Repository") return lid;
1394
- return;
1395
- }
1396
- for (const value of Object.values(obj)) {
1397
- const hit = findEcrRepositoryRefInTree(value, resources);
1398
- if (hit) return hit;
1399
- }
1400
- }
1401
- function resolveImageIntrinsic(node, resources, context) {
1402
- const v = resolveImageIntrinsicAny(node, resources, context);
1403
- if (typeof v === "string") return v;
1404
- if (typeof v === "number" || typeof v === "boolean") return String(v);
1405
- }
1406
- function resolveImageIntrinsicAny(node, resources, context) {
1407
- if (node === null || node === void 0) return void 0;
1408
- if (typeof node === "string" || typeof node === "number" || typeof node === "boolean") return node;
1409
- if (Array.isArray(node)) return;
1410
- if (typeof node !== "object") return void 0;
1411
- const obj = node;
1412
- const keys = Object.keys(obj);
1413
- if (keys.length !== 1) return void 0;
1414
- const intrinsic = keys[0];
1415
- const arg = obj[intrinsic];
1416
- if (intrinsic === "Ref") {
1417
- if (typeof arg !== "string") return void 0;
1418
- if (arg.startsWith("AWS::")) {
1419
- const p = context?.pseudoParameters;
1420
- if (!p) return void 0;
1421
- if (arg === "AWS::URLSuffix") return p.urlSuffix;
1422
- if (arg === "AWS::Partition") return p.partition;
1423
- if (arg === "AWS::Region") return p.region;
1424
- if (arg === "AWS::AccountId") return p.accountId;
1425
- return;
1426
- }
1427
- if (resources[arg]?.Type !== "AWS::ECR::Repository") return void 0;
1428
- const stateEntry = context?.stateResources?.[arg];
1429
- if (!stateEntry) return void 0;
1430
- return stateEntry.physicalId;
1431
- }
1432
- if (intrinsic === "Fn::GetAtt") {
1433
- let logicalId;
1434
- let attr;
1435
- if (Array.isArray(arg) && arg.length === 2 && typeof arg[0] === "string" && typeof arg[1] === "string") {
1436
- logicalId = arg[0];
1437
- attr = arg[1];
1438
- } else if (typeof arg === "string") {
1439
- const dot = arg.indexOf(".");
1440
- if (dot > 0 && dot < arg.length - 1) {
1441
- logicalId = arg.slice(0, dot);
1442
- attr = arg.slice(dot + 1);
1443
- }
1444
- }
1445
- if (!logicalId || !attr) return void 0;
1446
- if (resources[logicalId]?.Type !== "AWS::ECR::Repository") return void 0;
1447
- const cached = context?.stateResources?.[logicalId]?.attributes?.[attr];
1448
- if (typeof cached === "string" && cached.length > 0) return cached;
1449
- const physicalId = context?.stateResources?.[logicalId]?.physicalId;
1450
- const p = context?.pseudoParameters;
1451
- if (physicalId && p?.region && p.accountId) {
1452
- if (attr === "Arn" && p.partition) return `arn:${p.partition}:ecr:${p.region}:${p.accountId}:repository/${physicalId}`;
1453
- if (attr === "RepositoryUri" && p.urlSuffix) return `${p.accountId}.dkr.ecr.${p.region}.${p.urlSuffix}/${physicalId}`;
1454
- }
1455
- return;
1456
- }
1457
- if (intrinsic === "Fn::Split") {
1458
- if (!Array.isArray(arg) || arg.length !== 2) return void 0;
1459
- const argArr = arg;
1460
- const delim = argArr[0];
1461
- if (typeof delim !== "string") return void 0;
1462
- const src = resolveImageIntrinsicAny(argArr[1], resources, context);
1463
- if (typeof src !== "string") return void 0;
1464
- return src.split(delim);
1465
- }
1466
- if (intrinsic === "Fn::Select") {
1467
- if (!Array.isArray(arg) || arg.length !== 2) return void 0;
1468
- const argArr = arg;
1469
- const rawIndex = argArr[0];
1470
- let index;
1471
- if (typeof rawIndex === "number") index = rawIndex;
1472
- else if (typeof rawIndex === "string" && /^-?\d+$/.test(rawIndex)) index = Number.parseInt(rawIndex, 10);
1473
- if (index === void 0 || !Number.isFinite(index)) return void 0;
1474
- const list = resolveImageIntrinsicAny(argArr[1], resources, context);
1475
- if (Array.isArray(list)) {
1476
- if (index < 0 || index >= list.length) return void 0;
1477
- const picked = list[index];
1478
- if (typeof picked === "string") return picked;
1479
- return;
1480
- }
1481
- if (Array.isArray(argArr[1])) {
1482
- const listLiteral = argArr[1];
1483
- if (index < 0 || index >= listLiteral.length) return void 0;
1484
- return resolveImageIntrinsic(listLiteral[index], resources, context);
1485
- }
1486
- return;
1487
- }
1488
- if (intrinsic === "Fn::Join") {
1489
- if (!Array.isArray(arg) || arg.length !== 2) return void 0;
1490
- const [delim, parts] = arg;
1491
- if (typeof delim !== "string" || !Array.isArray(parts)) return void 0;
1492
- const resolved = [];
1493
- for (const part of parts) {
1494
- const r = resolveImageIntrinsic(part, resources, context);
1495
- if (r === void 0) return void 0;
1496
- resolved.push(r);
1497
- }
1498
- return resolved.join(delim);
1499
- }
1500
- if (intrinsic === "Fn::Sub") {
1501
- let template;
1502
- if (typeof arg === "string") template = arg;
1503
- else if (Array.isArray(arg) && typeof arg[0] === "string") template = arg[0];
1504
- if (template === void 0) return void 0;
1505
- const out = substituteImagePlaceholders(template, resources, context);
1506
- if (out.includes("${")) return void 0;
1507
- return out;
1508
- }
1509
- }
1510
- function substituteImagePlaceholders(flat, resources, context) {
1511
- if (!flat.includes("${")) return flat;
1512
- return flat.replace(/\$\{([^}]+)\}/g, (full, key) => {
1513
- if (context?.pseudoParameters) {
1514
- if (key === "AWS::AccountId" && context.pseudoParameters.accountId) return context.pseudoParameters.accountId;
1515
- if (key === "AWS::Region" && context.pseudoParameters.region) return context.pseudoParameters.region;
1516
- if (key === "AWS::Partition" && context.pseudoParameters.partition) return context.pseudoParameters.partition;
1517
- if (key === "AWS::URLSuffix" && context.pseudoParameters.urlSuffix) return context.pseudoParameters.urlSuffix;
1518
- }
1519
- if (context?.stateResources) {
1520
- const dot = key.indexOf(".");
1521
- const logicalId = dot === -1 ? key : key.slice(0, dot);
1522
- const refResource = resources[logicalId];
1523
- const stateEntry = context.stateResources[logicalId];
1524
- if (refResource?.Type === "AWS::ECR::Repository" && stateEntry) {
1525
- if (dot === -1) return stateEntry.physicalId;
1526
- const attr = key.slice(dot + 1);
1527
- const cached = stateEntry.attributes?.[attr];
1528
- if (typeof cached === "string") return cached;
1529
- }
1530
- }
1531
- return full;
1532
- });
1533
- }
1534
-
1535
- //#endregion
1536
- //#region src/utils/stringify.ts
1537
- function stringifyValue(value) {
1538
- switch (typeof value) {
1539
- case "string": return value;
1540
- case "number":
1541
- case "boolean":
1542
- case "bigint": return String(value);
1543
- case "symbol": return value.toString();
1544
- case "undefined": return "undefined";
1545
- case "function": return value.name ? `[Function: ${value.name}]` : "[Function]";
1546
- case "object":
1547
- if (value === null) return "null";
1548
- try {
1549
- const json = JSON.stringify(value);
1550
- if (json !== void 0) return json;
1551
- } catch {}
1552
- return Object.prototype.toString.call(value);
1553
- }
1554
- }
1555
-
1556
- //#endregion
1557
- //#region src/local/lambda-resolver.ts
1558
- function resolveLambdaArchitecture(props, logicalId) {
1559
- const arches = props["Architectures"];
1560
- if (Array.isArray(arches) && arches.length > 0) {
1561
- const first = arches[0];
1562
- if (first === "arm64") return "arm64";
1563
- if (first === "x86_64") return "x86_64";
1564
- throw new LocalInvokeResolutionError(`Lambda ${displayIdent(logicalId)} has unsupported Architectures value ${displayIdent(String(first))}. ${getEmbedConfig().cliName} supports x86_64 and arm64.`);
1565
- }
1566
- return "x86_64";
605
+
606
+ //#endregion
607
+ //#region src/local/lambda-resolver.ts
608
+ function resolveLambdaArchitecture(props, logicalId) {
609
+ const arches = props["Architectures"];
610
+ if (Array.isArray(arches) && arches.length > 0) {
611
+ const first = arches[0];
612
+ if (first === "arm64") return "arm64";
613
+ if (first === "x86_64") return "x86_64";
614
+ throw new LocalInvokeResolutionError(`Lambda ${displayIdent(logicalId)} has unsupported Architectures value ${displayIdent(String(first))}. ${getEmbedConfig().cliName} supports x86_64 and arm64.`);
615
+ }
616
+ return "x86_64";
1567
617
  }
1568
618
  var LocalInvokeResolutionError = class LocalInvokeResolutionError extends Error {
1569
619
  constructor(message) {
@@ -4838,69 +3888,6 @@ function applyDeployedEnvFallback(resolvedEnv, unresolved, deployedEnv) {
4838
3888
  };
4839
3889
  }
4840
3890
 
4841
- //#endregion
4842
- //#region src/local/ecr-uri.ts
4843
- const FIPS_AND_DUAL_STACK_PARTITIONS = ["aws", "aws-us-gov"];
4844
- const ECR_REGISTRY_HOST_FORMS = [
4845
- { labels: "dkr.ecr" },
4846
- {
4847
- labels: "dkr.ecr-fips",
4848
- partitions: FIPS_AND_DUAL_STACK_PARTITIONS
4849
- },
4850
- {
4851
- labels: "dkr-ecr",
4852
- fixedUrlSuffix: "on.aws",
4853
- partitions: FIPS_AND_DUAL_STACK_PARTITIONS
4854
- },
4855
- {
4856
- labels: "dkr-ecr-fips",
4857
- fixedUrlSuffix: "on.aws",
4858
- partitions: FIPS_AND_DUAL_STACK_PARTITIONS
4859
- }
4860
- ];
4861
- const ECR_HOST_FORM_BY_LABELS = new Map(ECR_REGISTRY_HOST_FORMS.map((f) => [f.labels, f]));
4862
- function escapeRegExp(value) {
4863
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4864
- }
4865
- const ECR_URI_HOST_REGEX = new RegExp(`^(\\d{12})\\.(${[...ECR_REGISTRY_HOST_FORMS].sort((a, b) => b.labels.length - a.labels.length).map((f) => escapeRegExp(f.labels)).join("|")})\\.([^./]+)\\.([^/]+)/`, "i");
4866
- const CANONICAL_REGION_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9-]*$/;
4867
- const REGION_SHAPE = /^(?:(?:us|eu|ap|sa|ca|me|af|il|mx)-[a-z0-9]+-[0-9]+|cn-[a-z0-9]+-[0-9]+|us-gov-[a-z0-9]+-[0-9]+|us-iso-[a-z0-9]+-[0-9]+|us-isob-[a-z0-9]+-[0-9]+|eu-isoe-[a-z0-9]+-[0-9]+|us-isof-[a-z0-9]+-[0-9]+|eusc-[a-z]+-[a-z0-9]+-[0-9]+)$/;
4868
- const CANONICAL_URL_SUFFIX = /^[A-Za-z0-9][A-Za-z0-9.-]*$/;
4869
- function foldAsciiUpperCase(value) {
4870
- return value.replace(/[A-Z]+/g, (run) => run.toLowerCase());
4871
- }
4872
- function isRegistryHostComponent(component) {
4873
- return component.includes(".") || component.includes(":") || component === "localhost";
4874
- }
4875
- function canonicalizeImageUriHost(imageUri) {
4876
- const slash = imageUri.indexOf("/");
4877
- if (slash < 0) return imageUri;
4878
- const host = imageUri.slice(0, slash);
4879
- if (!isRegistryHostComponent(host)) return imageUri;
4880
- return foldAsciiUpperCase(host) + imageUri.slice(slash);
4881
- }
4882
- function parseEcrRegistryHost(imageUri) {
4883
- const m = ECR_URI_HOST_REGEX.exec(imageUri);
4884
- if (!m) return void 0;
4885
- const [, accountId, rawLabels, rawRegion, rawSuffix] = m;
4886
- if (!CANONICAL_REGION_SEGMENT.test(rawRegion)) return void 0;
4887
- if (!CANONICAL_URL_SUFFIX.test(rawSuffix)) return void 0;
4888
- const form = ECR_HOST_FORM_BY_LABELS.get(foldAsciiUpperCase(rawLabels));
4889
- if (!form) return void 0;
4890
- const region = foldAsciiUpperCase(rawRegion);
4891
- if (!REGION_SHAPE.test(region)) return void 0;
4892
- const suffix = foldAsciiUpperCase(rawSuffix);
4893
- const partition = derivePartitionAndUrlSuffix(region);
4894
- if (form.partitions && !form.partitions.includes(partition.partition)) return void 0;
4895
- if (suffix !== (form.fixedUrlSuffix ?? partition.urlSuffix)) return void 0;
4896
- return {
4897
- accountId,
4898
- region,
4899
- registryHost: `${accountId}.${form.labels}.${region}.${suffix}`,
4900
- form
4901
- };
4902
- }
4903
-
4904
3891
  //#endregion
4905
3892
  //#region src/local/ecs-task-resolver.ts
4906
3893
  var EcsTaskResolutionError = class EcsTaskResolutionError extends Error {
@@ -5556,1215 +4543,219 @@ function resolveRoleArn(value, resources, subContext) {
5556
4543
  if (attr === "" || attr === "Arn") refLogicalId = arg[0];
5557
4544
  }
5558
4545
  }
5559
- if (refLogicalId !== void 0) {
5560
- if (resources[refLogicalId]?.Type !== "AWS::IAM::Role") return void 0;
5561
- return `arn:aws:iam::${TASK_ROLE_ACCOUNT_PLACEHOLDER}:role/${refLogicalId}`;
5562
- }
5563
- if ("Fn::Join" in obj || "Fn::Sub" in obj) {
5564
- if (!subContext) return void 0;
5565
- const sub = substituteAgainstState(value, subContext);
5566
- if (sub.kind === "literal" && typeof sub.value === "string" && sub.value.length > 0) return sub.value;
5567
- return;
5568
- }
5569
- }
5570
- function pickString(value) {
5571
- return typeof value === "string" && value.length > 0 ? value : void 0;
5572
- }
5573
- function pickStringArray$1(value) {
5574
- if (!Array.isArray(value)) return void 0;
5575
- const out = [];
5576
- for (const v of value) if (typeof v === "string") out.push(v);
5577
- return out;
5578
- }
5579
- function notFoundError$2(target, stack, resources) {
5580
- const tasks = [];
5581
- for (const [logicalId, resource] of Object.entries(resources)) {
5582
- if (resource.Type !== "AWS::ECS::TaskDefinition") continue;
5583
- const meta = resource.Metadata;
5584
- const cdkPath = typeof meta?.["aws:cdk:path"] === "string" ? meta["aws:cdk:path"] : "";
5585
- tasks.push({
5586
- displayPath: cdkPath || logicalId,
5587
- logicalId
5588
- });
5589
- }
5590
- let msg = `target '${target}' did not match any ECS task definition in ${stack.stackName}.\n\n`;
5591
- if (tasks.length === 0) msg += `Stack ${stack.stackName} has no AWS::ECS::TaskDefinition resources.`;
5592
- else {
5593
- const width = Math.max(...tasks.map((t) => t.displayPath.length));
5594
- msg += `Available task definitions in ${stack.stackName}:\n`;
5595
- for (const t of tasks) msg += ` ${t.displayPath.padEnd(width)} (${displayIdent(t.logicalId)})\n`;
5596
- }
5597
- return new EcsTaskResolutionError(msg.trimEnd());
5598
- }
5599
- function checkVolumeHostPath(hostPath) {
5600
- try {
5601
- return existsSync(hostPath) && statSync(hostPath).isDirectory();
5602
- } catch {
5603
- return false;
5604
- }
5605
- }
5606
- async function applyCrossStackResolverToTask(task, context) {
5607
- if (!context.crossStackResolver) return;
5608
- const { resolveDynamicReferences: _envOnly, ...secretContext } = context;
5609
- const rawContainers = (task.resource.Properties ?? {})["ContainerDefinitions"];
5610
- if (!Array.isArray(rawContainers)) return;
5611
- for (let idx = 0; idx < task.containers.length; idx += 1) {
5612
- const container = task.containers[idx];
5613
- const raw = rawContainers[idx];
5614
- if (!raw || typeof raw !== "object") continue;
5615
- const c = raw;
5616
- const containerName = pickString(c["Name"]) ?? container.name;
5617
- const resolvedEnvKeys = /* @__PURE__ */ new Set();
5618
- const resolvedSecretNames = /* @__PURE__ */ new Set();
5619
- if (Array.isArray(c["Environment"])) for (const entry of c["Environment"]) {
5620
- if (!entry || typeof entry !== "object") continue;
5621
- const e = entry;
5622
- const key = pickString(e["Name"]);
5623
- const value = e["Value"];
5624
- if (!key) continue;
5625
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") continue;
5626
- if (Object.hasOwn(container.environment, key)) continue;
5627
- if (!isCrossStackIntrinsic(value)) continue;
5628
- const { result: sub, consumedSensitive } = await resolveWithSensitivityAsync(value, context);
5629
- if (sub.kind === "literal") {
5630
- defineOwnKey(container.environment, key, String(sub.value));
5631
- resolvedEnvKeys.add(key);
5632
- if (consumedSensitive && !container.sensitiveEnvKeys.includes(key)) container.sensitiveEnvKeys.push(key);
5633
- }
5634
- }
5635
- if (Array.isArray(c["Secrets"])) for (const entry of c["Secrets"]) {
5636
- if (!entry || typeof entry !== "object") continue;
5637
- const e = entry;
5638
- const sName = pickString(e["Name"]);
5639
- const valueFromRaw = e["ValueFrom"];
5640
- if (!sName) continue;
5641
- if (typeof valueFromRaw === "string" && valueFromRaw.length > 0) continue;
5642
- if (container.secrets.some((s) => s.name === sName)) continue;
5643
- if (!isCrossStackIntrinsic(valueFromRaw)) continue;
5644
- const sub = await substituteAgainstStateAsync(valueFromRaw, secretContext);
5645
- if (sub.kind === "literal" && typeof sub.value === "string" && sub.value.length > 0) {
5646
- container.secrets.push({
5647
- name: sName,
5648
- valueFrom: sub.value
5649
- });
5650
- resolvedSecretNames.add(sName);
5651
- }
5652
- }
5653
- if (resolvedEnvKeys.size > 0 || resolvedSecretNames.size > 0) {
5654
- container.warnings = container.warnings.filter((w) => {
5655
- for (const k of resolvedEnvKeys) if (w.startsWith(`Environment ${displayIdent(k)} dropped:`)) return false;
5656
- for (const k of resolvedSecretNames) if (w.startsWith(`Secret ${displayIdent(k)} dropped:`)) return false;
5657
- return true;
5658
- });
5659
- task.warnings = task.warnings.filter((w) => {
5660
- for (const k of resolvedEnvKeys) if (w.startsWith(`Container ${displayIdent(containerName)}: Environment ${displayIdent(k)} dropped:`)) return false;
5661
- for (const k of resolvedSecretNames) if (w.startsWith(`Container ${displayIdent(containerName)}: Secret ${displayIdent(k)} dropped:`)) return false;
5662
- return true;
5663
- });
5664
- }
5665
- }
5666
- }
5667
-
5668
- //#endregion
5669
- //#region src/local/runtime-image.ts
5670
- const SUPPORTED_RUNTIMES = {
5671
- "nodejs18.x": {
5672
- image: "public.ecr.aws/lambda/nodejs:18",
5673
- fileExtension: ".js"
5674
- },
5675
- "nodejs20.x": {
5676
- image: "public.ecr.aws/lambda/nodejs:20",
5677
- fileExtension: ".js"
5678
- },
5679
- "nodejs22.x": {
5680
- image: "public.ecr.aws/lambda/nodejs:22",
5681
- fileExtension: ".js"
5682
- },
5683
- "nodejs24.x": {
5684
- image: "public.ecr.aws/lambda/nodejs:24",
5685
- fileExtension: ".js"
5686
- },
5687
- "python3.11": {
5688
- image: "public.ecr.aws/lambda/python:3.11",
5689
- fileExtension: ".py"
5690
- },
5691
- "python3.12": {
5692
- image: "public.ecr.aws/lambda/python:3.12",
5693
- fileExtension: ".py"
5694
- },
5695
- "python3.13": {
5696
- image: "public.ecr.aws/lambda/python:3.13",
5697
- fileExtension: ".py"
5698
- },
5699
- "python3.14": {
5700
- image: "public.ecr.aws/lambda/python:3.14",
5701
- fileExtension: ".py"
5702
- },
5703
- "ruby3.2": {
5704
- image: "public.ecr.aws/lambda/ruby:3.2",
5705
- fileExtension: ".rb"
5706
- },
5707
- "ruby3.3": {
5708
- image: "public.ecr.aws/lambda/ruby:3.3",
5709
- fileExtension: ".rb"
5710
- },
5711
- "java8.al2": {
5712
- image: "public.ecr.aws/lambda/java:8.al2",
5713
- fileExtension: null
5714
- },
5715
- java11: {
5716
- image: "public.ecr.aws/lambda/java:11",
5717
- fileExtension: null
5718
- },
5719
- java17: {
5720
- image: "public.ecr.aws/lambda/java:17",
5721
- fileExtension: null
5722
- },
5723
- java21: {
5724
- image: "public.ecr.aws/lambda/java:21",
5725
- fileExtension: null
5726
- },
5727
- dotnet6: {
5728
- image: "public.ecr.aws/lambda/dotnet:6",
5729
- fileExtension: null
5730
- },
5731
- dotnet8: {
5732
- image: "public.ecr.aws/lambda/dotnet:8",
5733
- fileExtension: null
5734
- },
5735
- "provided.al2": {
5736
- image: "public.ecr.aws/lambda/provided:al2",
5737
- fileExtension: null
5738
- },
5739
- "provided.al2023": {
5740
- image: "public.ecr.aws/lambda/provided:al2023",
5741
- fileExtension: null
5742
- }
5743
- };
5744
- var UnsupportedRuntimeError = class UnsupportedRuntimeError extends Error {
5745
- runtime;
5746
- constructor(runtime, message) {
5747
- super(message);
5748
- this.runtime = runtime;
5749
- this.name = "UnsupportedRuntimeError";
5750
- Object.setPrototypeOf(this, UnsupportedRuntimeError.prototype);
5751
- }
5752
- };
5753
- function resolveRuntimeImage(runtime) {
5754
- return resolveRuntimeSpec(runtime).image;
5755
- }
5756
- function resolveRuntimeFileExtension(runtime) {
5757
- const spec = resolveRuntimeSpec(runtime);
5758
- if (spec.fileExtension === null) throw new UnsupportedRuntimeError(runtime, `Inline 'Code.ZipFile' is not supported for runtime ${displayIdent(runtime)}. The Lambda Handler shape for this runtime names a compiled artifact (a JVM class, a .NET assembly, or — for the OS-only \`provided.*\` runtimes — an arbitrary \`bootstrap\` binary) that cannot be expressed as a single inline source file. Use \`lambda.Code.fromAsset(<dir>)\` with a directory containing the compiled output (.class hierarchy / JAR / DLL / native binary).`);
5759
- return spec.fileExtension;
5760
- }
5761
- function resolveRuntimeSpec(runtime) {
5762
- if (typeof runtime !== "string" || runtime.length === 0) throw new UnsupportedRuntimeError(String(runtime), "Lambda function has no Runtime property. This branch is only reached for ZIP Lambdas; container-image Lambdas (Code.ImageUri) take a different code path that does not consult the Runtime property.");
5763
- const spec = SUPPORTED_RUNTIMES[runtime];
5764
- if (spec) return spec;
5765
- if (runtime === "go1.x") throw new UnsupportedRuntimeError(runtime, "Runtime 'go1.x' was deprecated by AWS Lambda on 2024-01-08 and is no longer available. Migrate to the OS-only runtime: build your Go program as a `bootstrap` binary and set the CDK runtime to `lambda.Runtime.PROVIDED_AL2023` (or `lambda.Runtime.PROVIDED_AL2`). See https://docs.aws.amazon.com/lambda/latest/dg/lambda-golang.html");
5766
- throw new UnsupportedRuntimeError(runtime, `Unknown runtime ${displayIdent(runtime)}. ${getEmbedConfig().cliName} invoke supports nodejs18.x / nodejs20.x / nodejs22.x / nodejs24.x / python3.11 / python3.12 / python3.13 / python3.14 / ruby3.2 / ruby3.3 / java8.al2 / java11 / java17 / java21 / dotnet6 / dotnet8 / provided.al2 / provided.al2023.`);
5767
- }
5768
- function resolveRuntimeCodeMountPath(runtime) {
5769
- resolveRuntimeSpec(runtime);
5770
- if (runtime === "provided.al2" || runtime === "provided.al2023") return "/var/runtime";
5771
- return "/var/task";
5772
- }
5773
-
5774
- //#endregion
5775
- //#region src/utils/docker-argv-redaction.ts
5776
- const REDACTED_ARGV_VALUE = "***";
5777
- const ARGV_VALUE_BEARING_FLAGS = /* @__PURE__ */ new Set([
5778
- "-e",
5779
- "--env",
5780
- "--opt",
5781
- "--label",
5782
- "--build-arg"
5783
- ]);
5784
- const ARGV_PARAM_LIST_FLAGS = /* @__PURE__ */ new Set(["--cache-from", "--cache-to"]);
5785
- const ARGV_PARAM_LIST_LOCATOR_PARAMS = /* @__PURE__ */ new Set([
5786
- "type",
5787
- "mode",
5788
- "compression",
5789
- "compression-level",
5790
- "force-compression",
5791
- "ignore-error",
5792
- "image-manifest",
5793
- "oci-mediatypes",
5794
- "timeout",
5795
- "ref",
5796
- "dest",
5797
- "src",
5798
- "digest",
5799
- "tag",
5800
- "region",
5801
- "bucket",
5802
- "name",
5803
- "prefix",
5804
- "manifests_prefix",
5805
- "blobs_prefix",
5806
- "use_path_style",
5807
- "upload_parallelism",
5808
- "touch_refresh",
5809
- "account_name",
5810
- "scope"
5811
- ]);
5812
- const ARGV_PARAM_LIST_URL_PARAMS = /* @__PURE__ */ new Set([
5813
- "account_url",
5814
- "endpoint_url",
5815
- "url",
5816
- "url_v2"
5817
- ]);
5818
- function redactUrlLocator(value) {
5819
- if (value === "") return value;
5820
- const authority = /^(?:[a-zA-Z][a-zA-Z0-9+.-]*:)?\/\//.exec(value);
5821
- if (authority === null) return REDACTED_ARGV_VALUE;
5822
- const prefix = authority[0];
5823
- let rest = value.slice(prefix.length);
5824
- const lastAt = rest.lastIndexOf("@");
5825
- if (lastAt >= 0) rest = `${REDACTED_ARGV_VALUE}${rest.slice(lastAt)}`;
5826
- else {
5827
- const host = rest.split(/[/?#]/)[0];
5828
- const ipv6 = /^\[[0-9A-Fa-f:.]+\]/.exec(host);
5829
- const bare = ipv6 ? host.slice(ipv6[0].length) : host;
5830
- if (/:(?!\d{1,5}$)/.test(bare)) return REDACTED_ARGV_VALUE;
5831
- }
5832
- for (const delimiter of ["?", "#"]) {
5833
- const at = rest.indexOf(delimiter);
5834
- if (at >= 0) rest = `${rest.slice(0, at)}${delimiter}${REDACTED_ARGV_VALUE}`;
5835
- }
5836
- return `${prefix}${rest}`;
5837
- }
5838
- function maskArgvFlagValue(flag, value) {
5839
- if (ARGV_VALUE_BEARING_FLAGS.has(flag)) {
5840
- const eqIdx = value.indexOf("=");
5841
- return eqIdx >= 0 ? `${value.substring(0, eqIdx)}=${REDACTED_ARGV_VALUE}` : void 0;
5842
- }
5843
- if (ARGV_PARAM_LIST_FLAGS.has(flag)) {
5844
- let masked = false;
5845
- const rawParts = value.split(",");
5846
- const parts = rawParts.map((part, index) => {
5847
- if (part === "") return part;
5848
- if (masked) return REDACTED_ARGV_VALUE;
5849
- const eqIdx = part.indexOf("=");
5850
- if (eqIdx < 0) {
5851
- if (index === 0) return part;
5852
- masked = true;
5853
- return REDACTED_ARGV_VALUE;
5854
- }
5855
- const name = part.substring(0, eqIdx);
5856
- const normalized = name.trim().toLowerCase();
5857
- if (ARGV_PARAM_LIST_URL_PARAMS.has(normalized)) {
5858
- if (rawParts.slice(index + 1).some((later) => later.includes("@"))) {
5859
- masked = true;
5860
- return `${name}=${REDACTED_ARGV_VALUE}`;
5861
- }
5862
- const rawUrl = part.substring(eqIdx + 1);
5863
- const safeUrl = redactUrlLocator(rawUrl);
5864
- if (safeUrl === rawUrl) return part;
5865
- masked = true;
5866
- return `${name}=${safeUrl}`;
5867
- }
5868
- if (ARGV_PARAM_LIST_LOCATOR_PARAMS.has(normalized)) return part;
5869
- masked = true;
5870
- return `${name}=${REDACTED_ARGV_VALUE}`;
5871
- });
5872
- return masked ? parts.join(",") : void 0;
5873
- }
5874
- }
5875
- function maskAttachedShortFlag(arg) {
5876
- if (arg.startsWith("--") || !arg.startsWith("-")) return void 0;
5877
- let chosen;
5878
- for (const flag of ARGV_VALUE_BEARING_FLAGS) {
5879
- if (flag.length !== 2 || !flag.startsWith("-") || flag[1] === "-") continue;
5880
- const at = arg.indexOf(flag[1], 1);
5881
- if (at < 0 || at === arg.length - 1) continue;
5882
- if (chosen === void 0 || at < chosen.at) chosen = {
5883
- at,
5884
- flag
5885
- };
5886
- }
5887
- if (chosen === void 0) return void 0;
5888
- const masked = maskArgvFlagValue(chosen.flag, arg.slice(chosen.at + 1));
5889
- return masked === void 0 ? void 0 : `${arg.slice(0, chosen.at + 1)}${masked}`;
5890
- }
5891
- function trailingShortFlagOfCluster(arg) {
5892
- if (arg.startsWith("--") || !arg.startsWith("-")) return void 0;
5893
- const last = arg[arg.length - 1];
5894
- for (const flag of ARGV_VALUE_BEARING_FLAGS) if (flag.length === 2 && flag.startsWith("-") && flag[1] !== "-" && flag[1] === last) return flag;
5895
- }
5896
- function redactDockerArgvValues(args) {
5897
- const out = [];
5898
- for (let i = 0; i < args.length; i++) {
5899
- const cur = args[i];
5900
- const joinedEq = cur.indexOf("=");
5901
- if (joinedEq > 0) {
5902
- const maskedJoined = maskArgvFlagValue(cur.substring(0, joinedEq), cur.substring(joinedEq + 1));
5903
- if (maskedJoined !== void 0) {
5904
- out.push(`${cur.substring(0, joinedEq)}=${maskedJoined}`);
5905
- continue;
5906
- }
5907
- }
5908
- const maskedAttached = maskAttachedShortFlag(cur);
5909
- if (maskedAttached !== void 0) {
5910
- out.push(maskedAttached);
5911
- continue;
5912
- }
5913
- const next = args[i + 1];
5914
- if (typeof next === "string") {
5915
- const maskedNext = maskArgvFlagValue(ARGV_VALUE_BEARING_FLAGS.has(cur) ? cur : trailingShortFlagOfCluster(cur) ?? cur, next);
5916
- if (maskedNext !== void 0) {
5917
- out.push(cur, maskedNext);
5918
- i++;
5919
- continue;
5920
- }
5921
- }
5922
- out.push(cur);
5923
- }
5924
- return out;
5925
- }
5926
- function describeExitWithoutArgv(err) {
5927
- const e = err;
5928
- if (typeof e?.signal === "string" && e.signal !== "") return `killed by ${e.signal}`;
5929
- if (typeof e?.code === "number") return `exited with code ${e.code}`;
5930
- if (typeof e?.code === "string" && e.code !== "") return `failed (${e.code})`;
5931
- return "failed with no output";
5932
- }
5933
-
5934
- //#endregion
5935
- //#region src/assets/asset-source-path.ts
5936
- function resolveAssetSourcePath(opts) {
5937
- const { manifestDir, value, assetOutdir, field, subject, action, wrapError } = opts;
5938
- const shownValue = displayUntrustedValue(value);
5939
- if (isAbsolute(value) && opts.absolute !== "fold") {
5940
- const absolute = resolve(value);
5941
- const escape = absoluteAssemblyPathEscape(assetOutdir, absolute);
5942
- if (escape !== void 0 && opts.absolute === "honour") throw wrapError(`${subject} has an absolute ${field}=${shownValue} which ` + renderAssemblyPathEscape(escape, assetOutdir, action));
5943
- if (escape !== void 0) {
5944
- const refusal = originScopeRefusal(absolute, assetOutdir);
5945
- if (refusal !== void 0) throw wrapError(`${subject} has an absolute ${field}=${shownValue} which ${refusal}. An absolute ${field} is accepted only as a cdk synth --no-staging source folder: a directory inside your project (the git work tree holding the output directory, or the current directory when it contains the output directory or is a git work-tree root), not under a credential or version-control directory. Refusing to ${action}.`);
5946
- warnAbsoluteOutsideAssembly(opts, absolute, escape);
5947
- return absolute;
5948
- }
5949
- if (namesTheSameDirectory(assetOutdir, absolute)) warnWholeAssemblyAsSource(opts, absolute);
5950
- return absolute;
5951
- }
5952
- const resolved = resolveAssemblyPath(manifestDir, value, { containWithin: assetOutdir });
5953
- if (resolved.contained) return resolved.path;
5954
- if (namesTheSameDirectory(assetOutdir, resolved.path)) {
5955
- warnWholeAssemblyAsSource(opts, resolved.path);
5956
- return resolved.path;
5957
- }
5958
- throw wrapError(`${subject} has ${field}=${shownValue} which ` + renderAssemblyPathEscape(resolved, assetOutdir, action));
5959
- }
5960
- function broadRootReason(root, assetOutdir) {
5961
- if (root === resolve("/")) return "names the filesystem root";
5962
- if (containsOrIs(root, realPath(homedir()))) return "names your home directory or a directory containing it";
5963
- if (containsOrIs(root, realPath(assetOutdir))) return "names a directory containing the app's output directory";
5964
- }
5965
- function originScopeRefusal(absolute, assetOutdir) {
5966
- const root = realPath(absolute);
5967
- const broad = broadRootReason(root, assetOutdir);
5968
- if (broad !== void 0) return broad;
5969
- const projects = projectRoots(assetOutdir);
5970
- let hidden;
5971
- let isProjectRoot = false;
5972
- for (const project of projects) {
5973
- const rel = relative(project, root);
5974
- if (rel === "") isProjectRoot = true;
5975
- if (rel === "" || rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) continue;
5976
- const dotted = rel.split(sep).find((c) => CREDENTIAL_DIR_NAMES.has(c.toLowerCase()));
5977
- if (dotted === void 0) return void 0;
5978
- hidden = dotted;
5979
- }
5980
- if (isProjectRoot) return "is your project root itself; name a folder inside it";
5981
- if (hidden !== void 0) return `passes through the credential / version-control directory ${displayUntrustedValue(hidden)} inside your project`;
5982
- const shown = projects.map((p) => displayUntrustedValue(p)).join(" or ");
5983
- return projects.length === 0 ? "is outside any usable project root (the current directory and the git work tree are too broad to scope it)" : `resolves to ${displayUntrustedValue(root)}, outside your project (${shown})`;
5984
- }
5985
- const CREDENTIAL_DIR_NAMES = /* @__PURE__ */ new Set([
5986
- ".git",
5987
- ".hg",
5988
- ".svn",
5989
- ".ssh",
5990
- ".aws",
5991
- ".gnupg",
5992
- ".docker",
5993
- ".kube",
5994
- ".config",
5995
- ".azure",
5996
- ".gcloud",
5997
- ".terraform",
5998
- ".npm",
5999
- ".pnpm-store",
6000
- ".yarn",
6001
- ".cache",
6002
- ".local"
6003
- ]);
6004
- function projectRoots(assetOutdir) {
6005
- const roots = [];
6006
- const usable = (p) => p !== resolve("/") && !containsOrIs(p, realPath(homedir()));
6007
- const cwd = realPath(process.cwd());
6008
- const outdir = realPath(assetOutdir);
6009
- if (usable(cwd) && (containsOrIs(cwd, outdir) || existsSync(join(cwd, ".git")))) roots.push(cwd);
6010
- let dir = outdir;
6011
- for (;;) {
6012
- if (existsSync(join(dir, ".git"))) {
6013
- if (usable(dir) && !roots.includes(dir)) roots.push(dir);
6014
- break;
6015
- }
6016
- const parent = dirname(dir);
6017
- if (parent === dir) break;
6018
- dir = parent;
6019
- }
6020
- return roots;
6021
- }
6022
- function containsOrIs(outer, inner) {
6023
- const rel = relative(outer, inner);
6024
- return rel === "" || rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
6025
- }
6026
- function realPath(p, hops = 0) {
6027
- const abs = resolve(p);
6028
- try {
6029
- return realpathSync.native(abs);
6030
- } catch {
6031
- const parent = dirname(abs);
6032
- if (parent === abs) return abs;
6033
- const realParent = realPath(parent, hops);
6034
- let link;
6035
- try {
6036
- link = readlinkSync(abs);
6037
- } catch {
6038
- link = void 0;
6039
- }
6040
- if (link !== void 0 && hops < 40) return realPath(resolve(realParent, link), hops + 1);
6041
- return join(realParent, basename(abs));
6042
- }
6043
- }
6044
- const warnedAbsoluteOutside = /* @__PURE__ */ new Set();
6045
- function warnAbsoluteOutsideAssembly(opts, absolute, escape) {
6046
- const logger = getLogger().child("assets");
6047
- const line = `${opts.subject} has an absolute ${opts.field} pointing outside the assembly: ` + displayUntrustedValue(absolute) + (escape.escape === "symlink" ? ` (through a symbolic link to ${displayUntrustedValue(escape.realPath)})` : "") + `. ${getEmbedConfig().productName} will ${opts.sink}. ` + (escape.escape === "lexical" ? "This is what cdk synth --no-staging emits, and is expected for it; if you did not synthesize with that flag, treat this assembly as untrusted." : "No CDK synth writes this, so treat this assembly as untrusted unless you made that link yourself.");
6048
- if (warnedAbsoluteOutside.has(line)) {
6049
- logger.debug(line);
6050
- return;
6051
- }
6052
- warnedAbsoluteOutside.add(line);
6053
- logger.warn(line);
6054
- }
6055
- const warnedWholeAssembly = /* @__PURE__ */ new Set();
6056
- function warnWholeAssemblyAsSource(opts, outdir) {
6057
- const logger = getLogger().child("assets");
6058
- const line = `${opts.subject} has ${opts.field} naming the assembly's output directory ITSELF: ${displayUntrustedValue(outdir)}. ${getEmbedConfig().productName} will ${opts.sink} — that is the WHOLE assembly, every template and every staged asset, not one asset directory. No CDK synth emits this, so treat this assembly as untrusted unless you wrote that path yourself.`;
6059
- if (warnedWholeAssembly.has(line)) {
6060
- logger.debug(line);
6061
- return;
6062
- }
6063
- warnedWholeAssembly.add(line);
6064
- logger.warn(line);
6065
- }
6066
-
6067
- //#endregion
6068
- //#region src/assets/docker-cache-option.ts
6069
- function cacheOptionToFlag(option) {
6070
- let flag = `type=${option.type}`;
6071
- if (option.params) for (const [k, v] of Object.entries(option.params)) flag += `,${k}=${v}`;
6072
- return flag;
6073
- }
6074
-
6075
- //#endregion
6076
- //#region src/assets/buildkit-passthrough-warnings.ts
6077
- function candidateHostPaths(value, opts) {
6078
- const out = [];
6079
- for (const part of value.split(",")) {
6080
- const eq = part.indexOf("=");
6081
- if (eq < 0) {
6082
- const bare = part.trim();
6083
- if (bare.length > 0) out.push({
6084
- path: bare,
6085
- write: opts.bareIsWrite
6086
- });
6087
- continue;
6088
- }
6089
- const key = part.slice(0, eq).trim().toLowerCase();
6090
- const v = part.slice(eq + 1).trim();
6091
- if (v.length === 0) continue;
6092
- if (key !== "src" && key !== "source" && key !== "dest") continue;
6093
- out.push({
6094
- path: v,
6095
- write: key === "dest"
6096
- });
6097
- }
6098
- return out;
6099
- }
6100
- function hostPathsOf(source) {
6101
- const refs = [];
6102
- if (source.dockerFile) refs.push({
6103
- field: "dockerFile",
6104
- where: "dockerFile",
6105
- path: source.dockerFile,
6106
- write: false
6107
- });
6108
- for (const [k, v] of Object.entries(source.dockerBuildContexts ?? {})) {
6109
- const rendered = `${k}=${v}`;
6110
- const contextPath = rendered.slice(rendered.indexOf("=") + 1).trim().replace(/^oci-layout:\/\//, "");
6111
- if (contextPath.length === 0) continue;
6112
- refs.push({
6113
- field: "dockerBuildContexts",
6114
- where: k,
6115
- path: contextPath,
6116
- write: false
6117
- });
6118
- }
6119
- const ssh = source.dockerBuildSsh ?? "";
6120
- const sshEq = ssh.indexOf("=");
6121
- (sshEq < 0 ? [] : ssh.slice(sshEq + 1).split(",")).forEach((entry, i) => {
6122
- const p = entry.trim();
6123
- if (p.length > 0) refs.push({
6124
- field: "dockerBuildSsh",
6125
- where: String(i),
6126
- path: p,
6127
- write: false
6128
- });
6129
- });
6130
- for (const [k, v] of Object.entries(source.dockerBuildSecrets ?? {})) for (const { path: p, write } of candidateHostPaths(`id=${k},${v}`, { bareIsWrite: false })) refs.push({
6131
- field: "dockerBuildSecrets",
6132
- where: k,
6133
- path: p,
6134
- write
6135
- });
6136
- (source.cacheFrom ?? []).forEach((c, i) => {
6137
- for (const { path: p, write } of candidateHostPaths(cacheOptionToFlag(c), { bareIsWrite: false })) refs.push({
6138
- field: "cacheFrom",
6139
- where: String(i),
6140
- path: p,
6141
- write
6142
- });
6143
- });
6144
- if (source.cacheTo) for (const { path: p, write } of candidateHostPaths(cacheOptionToFlag(source.cacheTo), { bareIsWrite: false })) refs.push({
6145
- field: "cacheTo",
6146
- where: "cacheTo",
6147
- path: p,
6148
- write
6149
- });
6150
- (source.dockerOutputs ?? []).forEach((o, i) => {
6151
- for (const { path: p, write } of candidateHostPaths(o, { bareIsWrite: true })) refs.push({
6152
- field: "dockerOutputs",
6153
- where: String(i),
6154
- path: p,
6155
- write
6156
- });
6157
- });
6158
- return refs;
6159
- }
6160
- const warnedPassthroughs = /* @__PURE__ */ new Set();
6161
- function warnEscapingBuildKitPaths(source, base, bound) {
6162
- const logger = getLogger().child("assets");
6163
- for (const ref of hostPathsOf(source)) {
6164
- const escape = assemblyPathEscape(base, bound, ref.path);
6165
- if (escape === void 0) continue;
6166
- const verb = ref.write ? "WRITE to" : "read";
6167
- const line = `Docker asset ${ref.field}` + (ref.where === ref.field ? "" : `[${displayUntrustedValue(ref.where)}]`) + ` names a host path outside the assembly, which ` + renderAssemblyPathEscape(escape, bound, "load", `${getEmbedConfig().productName} will ${verb} it during the image build, matching the CDK CLI — a pre-synthesized assembly is trusted input. If you did not produce this assembly, that is a host path it chose and the CloudFormation template does not show.`);
6168
- if (warnedPassthroughs.has(line)) {
6169
- logger.debug(line);
6170
- continue;
6171
- }
6172
- warnedPassthroughs.add(line);
6173
- logger.warn(line);
6174
- }
6175
- }
6176
-
6177
- //#endregion
6178
- //#region src/assets/docker-build.ts
6179
- const warnedExecutables = /* @__PURE__ */ new Set();
6180
- function warnManifestExecutable(cmd, executable, cwd) {
6181
- const logger = getLogger().child("docker-build");
6182
- const key = JSON.stringify([cwd, executable]);
6183
- if (warnedExecutables.has(key)) {
6184
- logger.debug(`source.executable already announced this process: ${displayUntrustedValue(cmd)} (cwd=${displayUntrustedValue(cwd)})`);
6185
- return;
6186
- }
6187
- warnedExecutables.add(key);
6188
- const argCount = executable.length - 1;
6189
- logger.warn(`Docker asset source.executable runs a command this asset manifest chose, on this machine: ${displayUntrustedValue(cmd)}` + (argCount > 0 ? ` (with ${argCount} argument(s); --verbose shows them)` : "") + `. ${getEmbedConfig().productName} runs it, matching the CDK CLI — a pre-synthesized assembly is trusted input. Note that this means running a local command against a pre-synthesized assembly DOES execute code from it, which the CloudFormation template does not show.`);
6190
- }
6191
- async function buildDockerImage(asset, cdkOutDir, options) {
6192
- const source = asset.source;
6193
- const logger = getLogger().child("docker-build");
6194
- const assetOutdir = options.assetOutdir ?? cdkOutDir;
6195
- const contextDirectory = (directory, sink) => resolveAssetSourcePath({
6196
- manifestDir: cdkOutDir,
6197
- value: directory,
6198
- assetOutdir,
6199
- absolute: "fold",
6200
- field: "source.directory",
6201
- subject: "Docker image asset",
6202
- action: "build it",
6203
- sink,
6204
- wrapError: (message) => new LocalInvokeBuildError(message)
6205
- });
6206
- if (source.executable && source.executable.length > 0) {
6207
- const [cmd, ...args] = source.executable;
6208
- if (!cmd) throw options.wrapError("asset source.executable[] is empty");
6209
- const cwd = source.directory ? contextDirectory(source.directory, "run this asset's source.executable with that directory as its working directory") : cdkOutDir;
6210
- logger.debug(`Building Docker image via executable: ${displayUntrustedValue(redactDockerArgvValues(source.executable).join(" "))} (cwd=${displayUntrustedValue(cwd)})`);
6211
- warnManifestExecutable(cmd, source.executable, cwd);
6212
- let result;
6213
- try {
6214
- result = await spawnStreaming(cmd, args, { cwd });
6215
- } catch (err) {
6216
- const e = err;
6217
- throw options.wrapError(displayToolOutput(e.stderr || e.message || String(err)));
6218
- }
6219
- const tag = result.stdout.trim();
6220
- if (!tag) throw options.wrapError(`docker build executable produced no output (expected the local image tag on stdout): ${displayUntrustedValue(cmd)}`);
6221
- return tag;
6222
- }
6223
- if (!source.directory) throw options.wrapError(`DockerImageAssetSource must set either 'directory' or 'executable' (fields present: ${displayUntrustedValue(Object.keys(source).join(", ") || "none")})`);
6224
- if (!options.tag) throw options.wrapError("buildDockerImage(directory mode) requires options.tag");
6225
- const buildArgs = buildDockerBuildCommand(source, options.tag, options.platform);
6226
- const contextDir = contextDirectory(source.directory, `send that directory to docker build as the context of an image ${getEmbedConfig().productName} then runs locally`);
6227
- buildArgs.push(".");
6228
- warnEscapingBuildKitPaths(source, contextDir, assetOutdir);
6229
- logger.debug(`${getDockerCmd()} ${redactDockerArgvValues(buildArgs).map((a) => displayUntrustedValue(a)).join(" ")} (cwd=${displayUntrustedValue(contextDir)})`);
6230
- try {
6231
- await runDockerStreaming(buildArgs, {
6232
- cwd: contextDir,
6233
- env: { BUILDX_NO_DEFAULT_ATTESTATIONS: "1" },
6234
- ...options.progressLabel !== void 0 && { progressLabel: options.progressLabel }
6235
- });
6236
- } catch (err) {
6237
- const e = err;
6238
- throw options.wrapError(displayToolOutput(e.stderr || e.message || String(err)));
6239
- }
6240
- return options.tag;
6241
- }
6242
- function buildDockerBuildCommand(source, tag, platformOverride) {
6243
- const args = [
6244
- "build",
6245
- "--tag",
6246
- tag
6247
- ];
6248
- if (source.dockerBuildArgs) for (const [k, v] of Object.entries(source.dockerBuildArgs)) args.push("--build-arg", `${k}=${v}`);
6249
- if (source.dockerBuildContexts) for (const [k, v] of Object.entries(source.dockerBuildContexts)) args.push("--build-context", `${k}=${v}`);
6250
- if (source.dockerBuildSecrets) for (const [k, v] of Object.entries(source.dockerBuildSecrets)) args.push("--secret", `id=${k},${v}`);
6251
- if (source.dockerBuildSsh) args.push("--ssh", source.dockerBuildSsh);
6252
- if (source.dockerBuildTarget) args.push("--target", source.dockerBuildTarget);
6253
- if (source.dockerFile) args.push("--file", source.dockerFile);
6254
- if (source.networkMode) args.push("--network", source.networkMode);
6255
- const platform = platformOverride ?? source.platform;
6256
- if (platform) args.push("--platform", platform);
6257
- if (source.dockerOutputs) for (const output of source.dockerOutputs) args.push(`--output=${output}`);
6258
- if (source.cacheFrom) for (const c of source.cacheFrom) args.push("--cache-from", cacheOptionToFlag(c));
6259
- if (source.cacheTo) args.push("--cache-to", cacheOptionToFlag(source.cacheTo));
6260
- if (source.cacheDisabled) args.push("--no-cache");
6261
- return args;
6262
- }
6263
-
6264
- //#endregion
6265
- //#region src/local/ecr-puller.ts
6266
- function parseEcrUri(imageUri) {
6267
- const host = parseEcrRegistryHost(imageUri);
6268
- if (!host) return void 0;
6269
- const canonicalUri = canonicalizeImageUriHost(imageUri);
6270
- const m = /^([^:]+):(.+)$/.exec(canonicalUri.slice(canonicalUri.indexOf("/") + 1));
6271
- if (!m) return void 0;
6272
- return {
6273
- accountId: host.accountId,
6274
- region: host.region,
6275
- repository: m[1],
6276
- tag: m[2],
6277
- canonicalUri,
6278
- registryHost: host.registryHost
6279
- };
6280
- }
6281
- const ASSUMED_ROLE_CACHE = /* @__PURE__ */ new Map();
6282
- const CALLER_IDENTITY_CACHE = /* @__PURE__ */ new Map();
6283
- const STS_CREDENTIAL_SAFETY_MARGIN_MS = 300 * 1e3;
6284
- function isCredentialFresh(creds) {
6285
- if (!creds.expiration) return false;
6286
- return creds.expiration.getTime() - Date.now() > STS_CREDENTIAL_SAFETY_MARGIN_MS;
6287
- }
6288
- async function pullEcrImage(imageUri, options) {
6289
- const logger = getLogger().child("ecr-puller");
6290
- const parsed = parseEcrUri(imageUri);
6291
- if (!parsed) throw new LocalInvokeBuildError(`Image URI ${displayUntrustedValue(imageUri)} is not an ECR URI. ${getEmbedConfig().cliName} invoke v1 only authenticates against ECR for the deployed-image fallback path.`);
6292
- const canonicalUri = parsed.canonicalUri;
6293
- const callerRegion = options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"];
6294
- if (options.skipPull) {
6295
- logger.info(`Skipping ECR pull (--no-pull). Verifying ${canonicalUri} is in local cache...`);
6296
- await verifyImageInLocalCache(canonicalUri);
6297
- return canonicalUri;
6298
- }
6299
- const callerIdentityKey = `${options.profile ?? "_noprofile"}|${callerRegion ?? "_unset"}`;
6300
- let callerAccount = CALLER_IDENTITY_CACHE.get(callerIdentityKey);
6301
- if (callerAccount === void 0) {
6302
- const sts = new STSClient(buildStsClientConfig({
6303
- region: callerRegion,
6304
- profile: options.profile
6305
- }));
6306
- try {
6307
- const identity = await sts.send(new GetCallerIdentityCommand({}));
6308
- if (!identity.Account) throw new LocalInvokeBuildError("STS GetCallerIdentity returned no Account. Verify your AWS credentials.");
6309
- callerAccount = identity.Account;
6310
- CALLER_IDENTITY_CACHE.set(callerIdentityKey, callerAccount);
6311
- } catch (err) {
6312
- if (err instanceof LocalInvokeBuildError) throw err;
6313
- throw new LocalInvokeBuildError(`STS GetCallerIdentity failed while preparing the ECR pull: ${describeAwsFailureForWarn(err, "STS GetCallerIdentity (ECR pull)")}. Verify your AWS credentials.`);
6314
- } finally {
6315
- sts.destroy();
6316
- }
6317
- }
6318
- const crossAccount = callerAccount !== parsed.accountId;
6319
- const crossRegion = callerRegion !== void 0 && callerRegion !== parsed.region;
6320
- let assumed;
6321
- if (options.ecrRoleArn) {
6322
- const cacheKey = `${options.profile ?? "_noprofile"}|${options.ecrRoleArn}|${callerRegion ?? "_unset"}`;
6323
- const cached = ASSUMED_ROLE_CACHE.get(cacheKey);
6324
- if (cached && isCredentialFresh(cached)) {
6325
- assumed = cached;
6326
- logger.debug(`Reusing cached AssumeRole credentials for ${options.ecrRoleArn}`);
6327
- } else {
6328
- assumed = await assumeRoleForEcr(options.ecrRoleArn, callerRegion, options.profile, logger);
6329
- ASSUMED_ROLE_CACHE.set(cacheKey, assumed);
6330
- logger.info(`Assumed role ${options.ecrRoleArn} for ECR pull (account=${parsed.accountId}, region=${parsed.region})`);
6331
- }
6332
- } else if (crossAccount) logger.info(`Cross-account ECR pull: image account ${parsed.accountId} != caller ${callerAccount}. Using the caller's credentials; pass --ecr-role-arn <arn> if AWS rejects with AccessDenied.`);
6333
- if (crossRegion) logger.info(`Cross-region ECR pull: image region ${parsed.region} != caller ${callerRegion ?? "(unset)"}. Authenticating against the image region directly.`);
6334
- const ecr = new ECRClient({
6335
- ...buildProxyClientConfig({ profile: options.profile }),
6336
- region: parsed.region,
6337
- ...assumed ? { credentials: assumed } : options.profile ? { profile: options.profile } : {}
6338
- });
6339
- try {
6340
- await ecrLogin(ecr, {
6341
- accountId: parsed.accountId,
6342
- region: parsed.region,
6343
- registryHost: parsed.registryHost
6344
- });
6345
- } finally {
6346
- ecr.destroy();
6347
- }
6348
- logger.info(`Pulling ${canonicalUri}...`);
6349
- try {
6350
- await runDockerForeground(["pull", canonicalUri]);
6351
- } catch (err) {
6352
- throw new LocalInvokeBuildError(`docker pull ${canonicalUri} failed: ${err.message}`);
6353
- }
6354
- return canonicalUri;
6355
- }
6356
- async function assumeRoleForEcr(roleArn, callerRegion, profile, logger) {
6357
- if (!isIamRoleArn(roleArn)) throw new LocalInvokeBuildError(refusedRoleArnMessage(roleArn));
6358
- logger.debug(`Assuming role ${roleArn} for ECR pull...`);
6359
- const sts = new STSClient(workloadStsClientConfig({
6360
- region: callerRegion,
6361
- profile
6362
- }));
6363
- try {
6364
- const creds = (await sts.send(new AssumeRoleCommand({
6365
- RoleArn: roleArn,
6366
- RoleSessionName: `${getEmbedConfig().resourceNamePrefix}-ecr-${Date.now()}`,
6367
- DurationSeconds: 3600
6368
- }))).Credentials;
6369
- if (!creds || !creds.AccessKeyId || !creds.SecretAccessKey || !creds.SessionToken) throw new LocalInvokeBuildError(`AssumeRole(${roleArn}) returned no usable credentials. Verify the role's trust policy allows your identity to assume it.`);
6370
- return {
6371
- accessKeyId: creds.AccessKeyId,
6372
- secretAccessKey: creds.SecretAccessKey,
6373
- sessionToken: creds.SessionToken,
6374
- ...creds.Expiration && { expiration: creds.Expiration }
6375
- };
6376
- } catch (err) {
6377
- if (err instanceof LocalInvokeBuildError) throw err;
6378
- const reason = describeAwsFailureForWarn(err, "STS AssumeRole (ECR pull)");
6379
- throw new LocalInvokeBuildError(`Failed to assume role ${flattenToOneLine(roleArn)} for ECR pull: ${reason}. Verify the role exists and its trust policy permits the caller's identity to assume it.`);
6380
- } finally {
6381
- sts.destroy();
6382
- }
6383
- }
6384
- async function ecrLogin(client, target) {
6385
- const { accountId, region, registryHost } = target;
6386
- getLogger().child("ecr-puller").debug(`ECR login (account=${accountId}, region=${region}, host=${registryHost})`);
6387
- const authData = (await client.send(new GetAuthorizationTokenCommand({})).catch((err) => {
6388
- throw new LocalInvokeBuildError(`ECR GetAuthorizationToken failed (account=${accountId}, region=${region}): ${describeAwsFailureForWarn(err, "ECR GetAuthorizationToken")}. Verify the credentials can call ecr:GetAuthorizationToken.`);
6389
- })).authorizationData?.[0];
6390
- if (!authData?.authorizationToken) throw new LocalInvokeBuildError("Failed to get ECR authorization token");
6391
- const [username, password] = Buffer.from(authData.authorizationToken, "base64").toString().split(":");
6392
- if (!username || password === void 0) throw new LocalInvokeBuildError("ECR authorization token has unexpected shape (missing username/password)");
6393
- const endpoint = `https://${registryHost}`;
6394
- try {
6395
- await runDockerStreaming([
6396
- "login",
6397
- "--username",
6398
- username,
6399
- "--password-stdin",
6400
- endpoint
6401
- ], { input: password });
6402
- } catch (err) {
6403
- const e = err;
6404
- throw new LocalInvokeBuildError(`ECR login failed: ${formatDockerLoginError(e.stderr || e.message || String(err), endpoint)}`);
6405
- }
6406
- }
6407
- async function verifyImageInLocalCache(imageUri) {
6408
- try {
6409
- await runDockerStreaming([
6410
- "image",
6411
- "inspect",
6412
- imageUri
6413
- ]);
6414
- } catch {
6415
- throw new LocalInvokeBuildError(`Image ${displayUntrustedValue(imageUri)} is not in the local docker cache and --no-pull was set. Either remove --no-pull (${getEmbedConfig().productName} will pull from ECR) or pre-pull the image manually with \`docker pull\`.`);
6416
- }
6417
- }
6418
- async function isImageInLocalCache(imageRef) {
6419
- try {
6420
- await runDockerStreaming([
6421
- "image",
6422
- "inspect",
6423
- imageRef
6424
- ]);
6425
- return true;
6426
- } catch {
6427
- return false;
6428
- }
6429
- }
6430
-
6431
- //#endregion
6432
- //#region src/local/docker-image-builder.ts
6433
- async function buildContainerImage(asset, cdkOutDir, options) {
6434
- const tag = computeLocalTag(asset.source);
6435
- const platform = architectureToPlatform(options.architecture);
6436
- const logger = getLogger().child("local-invoke-build");
6437
- if (options.noBuild === true) {
6438
- logger.info(`Skipping docker build (--no-build). Verifying ${tag} is in local registry...`);
6439
- if (!await isImageInLocalCache(tag)) throw new LocalInvokeBuildError(`image ${displayIdent(tag)} not in local registry and --no-build is set; remove --no-build or run \`docker build\` manually first.`);
6440
- logger.debug(`Local tag ${tag} is cached; skipping build.`);
6441
- return tag;
6442
- }
6443
- logger.info(`Building container image (platform=${platform})...`);
6444
- logger.debug(`Local tag: ${tag}`);
6445
- const actualTag = await buildDockerImage(asset, cdkOutDir, {
6446
- tag,
6447
- platform,
6448
- wrapError: (stderr) => new LocalInvokeBuildError(`docker build failed for container Lambda asset (${displayUntrustedValue(asset.source.directory ?? asset.source.executable?.[0] ?? "")}): ${stderr}`),
6449
- progressLabel: `Building container image (platform=${platform})`,
6450
- ...options.assetOutdir !== void 0 && { assetOutdir: options.assetOutdir }
6451
- });
6452
- if (actualTag !== tag) {
6453
- logger.debug(`Re-tagging executable-built image ${displayIdent(actualTag)} → ${displayIdent(tag)}`);
6454
- try {
6455
- await runDockerStreaming([
6456
- "tag",
6457
- actualTag,
6458
- tag
6459
- ]);
6460
- } catch (err) {
6461
- const e = err;
6462
- throw new LocalInvokeBuildError(`docker tag failed re-tagging ${displayIdent(actualTag)} → ${displayIdent(tag)}: ${displayToolOutput(e.stderr?.trim() || e.message || String(err))}`);
6463
- }
6464
- }
6465
- return tag;
6466
- }
6467
- function architectureToPlatform(architecture) {
6468
- return architecture === "arm64" ? "linux/arm64" : "linux/amd64";
6469
- }
6470
- function hostPlatform() {
6471
- return process.arch === "arm64" ? "linux/arm64" : "linux/amd64";
6472
- }
6473
- const warnedEmulatedPlatforms = /* @__PURE__ */ new Set();
6474
- function warnIfEmulatedPlatform(platform, opts = {}) {
6475
- if (!platform) return;
6476
- const host = hostPlatform();
6477
- if (platform === host) return;
6478
- if (warnedEmulatedPlatforms.has(platform)) return;
6479
- warnedEmulatedPlatforms.add(platform);
6480
- const logger = opts.logger ?? getLogger();
6481
- const what = opts.label ? `${displayIdent(opts.label)} ` : "";
6482
- logger.warn(`Running ${what}under ${platform} emulation on a ${host} host (the declared architecture differs from the host). Emulation is slower and some compiled binaries can fail under it. If the container does not run correctly, enable Rosetta for x86/amd64 emulation in your Docker engine settings, or build the function for ${host}.`);
6483
- }
6484
- function computeLocalTag(source) {
6485
- const hash = createHash("sha256");
6486
- pushField(hash, "directory", source.directory ?? "");
6487
- pushField(hash, "executable", (source.executable ?? []).join(" "));
6488
- pushField(hash, "dockerFile", source.dockerFile ?? "");
6489
- pushField(hash, "dockerBuildTarget", source.dockerBuildTarget ?? "");
6490
- pushField(hash, "networkMode", source.networkMode ?? "");
6491
- pushField(hash, "platform", source.platform ?? "");
6492
- pushField(hash, "dockerBuildSsh", source.dockerBuildSsh ?? "");
6493
- pushField(hash, "cacheDisabled", source.cacheDisabled ? "1" : "0");
6494
- pushMap(hash, "dockerBuildArgs", source.dockerBuildArgs);
6495
- pushMap(hash, "dockerBuildContexts", source.dockerBuildContexts);
6496
- pushMap(hash, "dockerBuildSecrets", source.dockerBuildSecrets);
6497
- pushField(hash, "dockerOutputs", (source.dockerOutputs ?? []).join(""));
6498
- pushField(hash, "cacheFrom", (source.cacheFrom ?? []).map((o) => JSON.stringify(o)).join(""));
6499
- pushField(hash, "cacheTo", source.cacheTo ? JSON.stringify(source.cacheTo) : "");
6500
- return `${getEmbedConfig().resourceNamePrefix}-invoke-${hash.digest("hex").slice(0, 16)}`;
6501
- }
6502
- function pushField(hash, name, value) {
6503
- hash.update(name);
6504
- hash.update("=");
6505
- hash.update(value);
6506
- hash.update("\0");
6507
- }
6508
- function pushMap(hash, name, value) {
6509
- hash.update(name);
6510
- hash.update("={");
6511
- if (value) for (const [k, v] of Object.entries(value)) {
6512
- hash.update(k);
6513
- hash.update("=");
6514
- hash.update(v);
6515
- hash.update(";");
6516
- }
6517
- hash.update("}\0");
6518
- }
6519
-
6520
- //#endregion
6521
- //#region src/local/docker-runner.ts
6522
- const execFileAsync$7 = promisify(execFile);
6523
- var DockerRunnerError = class DockerRunnerError extends Error {
6524
- constructor(message) {
6525
- super(message);
6526
- this.name = "DockerRunnerError";
6527
- Object.setPrototypeOf(this, DockerRunnerError.prototype);
6528
- }
6529
- };
6530
- async function pullImage(image, skipPull, platform) {
6531
- const logger = getLogger().child("docker");
6532
- if (skipPull) {
6533
- logger.debug(`Skipping docker pull for ${displayIdent(image)} (--no-pull)`);
6534
- return;
6535
- }
6536
- const platformArgs = platform ? ["--platform", platform] : [];
6537
- if (getLogger().getLevel() === "debug") {
6538
- logger.info(`Pulling ${displayIdent(image)}${platform ? ` (${displayIdent(platform)})` : ""}...`);
6539
- try {
6540
- await runDockerForeground([
6541
- "pull",
6542
- ...platformArgs,
6543
- image
6544
- ]);
6545
- } catch (err) {
6546
- const e = err;
6547
- throw new DockerRunnerError(`docker pull ${displayIdent(image)} failed: ${e.message}`);
6548
- }
4546
+ if (refLogicalId !== void 0) {
4547
+ if (resources[refLogicalId]?.Type !== "AWS::IAM::Role") return void 0;
4548
+ return `arn:aws:iam::${TASK_ROLE_ACCOUNT_PLACEHOLDER}:role/${refLogicalId}`;
4549
+ }
4550
+ if ("Fn::Join" in obj || "Fn::Sub" in obj) {
4551
+ if (!subContext) return void 0;
4552
+ const sub = substituteAgainstState(value, subContext);
4553
+ if (sub.kind === "literal" && typeof sub.value === "string" && sub.value.length > 0) return sub.value;
6549
4554
  return;
6550
4555
  }
6551
- logger.debug(`Pulling ${displayIdent(image)} (silent — pass --verbose to stream progress)`);
6552
- try {
6553
- await runDockerStreaming([
6554
- "pull",
6555
- ...platformArgs,
6556
- image
6557
- ], {
6558
- streamLive: false,
6559
- progressLabel: `Pulling ${displayIdent(image)}`
4556
+ }
4557
+ function pickString(value) {
4558
+ return typeof value === "string" && value.length > 0 ? value : void 0;
4559
+ }
4560
+ function pickStringArray$1(value) {
4561
+ if (!Array.isArray(value)) return void 0;
4562
+ const out = [];
4563
+ for (const v of value) if (typeof v === "string") out.push(v);
4564
+ return out;
4565
+ }
4566
+ function notFoundError$2(target, stack, resources) {
4567
+ const tasks = [];
4568
+ for (const [logicalId, resource] of Object.entries(resources)) {
4569
+ if (resource.Type !== "AWS::ECS::TaskDefinition") continue;
4570
+ const meta = resource.Metadata;
4571
+ const cdkPath = typeof meta?.["aws:cdk:path"] === "string" ? meta["aws:cdk:path"] : "";
4572
+ tasks.push({
4573
+ displayPath: cdkPath || logicalId,
4574
+ logicalId
6560
4575
  });
6561
- } catch (err) {
6562
- const e = err;
6563
- if (e.exitCode === void 0 || e.exitCode === null) throw new DockerRunnerError(`docker pull ${displayIdent(image)} failed: ${displayToolOutput(e.message ?? String(err))}`);
6564
- const detail = e.stderr?.trim() || e.stdout?.trim() || "(no output)";
6565
- throw new DockerRunnerError(`docker pull ${displayIdent(image)} exited with code ${e.exitCode}: ${displayToolOutput(detail)}`);
6566
4576
  }
6567
- }
6568
- async function runDetached(opts) {
6569
- const args = opts.autoRemove === false ? ["run", "-d"] : [
6570
- "run",
6571
- "-d",
6572
- "--rm"
6573
- ];
6574
- if (opts.name) args.push("--name", opts.name);
6575
- if (opts.network) args.push("--network", opts.network);
6576
- if (opts.platform) {
6577
- args.push("--platform", opts.platform);
6578
- warnIfEmulatedPlatform(opts.platform, opts.name ? { label: opts.name } : {});
4577
+ let msg = `target '${target}' did not match any ECS task definition in ${stack.stackName}.\n\n`;
4578
+ if (tasks.length === 0) msg += `Stack ${stack.stackName} has no AWS::ECS::TaskDefinition resources.`;
4579
+ else {
4580
+ const width = Math.max(...tasks.map((t) => t.displayPath.length));
4581
+ msg += `Available task definitions in ${stack.stackName}:\n`;
4582
+ for (const t of tasks) msg += ` ${t.displayPath.padEnd(width)} (${displayIdent(t.logicalId)})\n`;
6579
4583
  }
6580
- if (opts.extraHosts) for (const entry of opts.extraHosts) args.push("--add-host", `${entry.host}:${entry.ip}`);
6581
- const host = opts.host ?? "127.0.0.1";
6582
- args.push("-p", `${host}:${opts.hostPort}:${opts.containerPort ?? 8080}`);
6583
- if (opts.debugPort !== void 0) args.push("-p", `${host}:${opts.debugPort}:${opts.debugPort}`);
6584
- for (const extra of opts.extraPorts ?? []) args.push("-p", `${host}:${extra.hostPort}:${extra.containerPort}`);
6585
- for (const mount of opts.mounts) {
6586
- const ro = mount.readOnly ? ":ro" : "";
6587
- args.push("-v", `${mount.hostPath}:${mount.containerPath}${ro}`);
6588
- }
6589
- if (opts.extraMounts) for (const mount of opts.extraMounts) {
6590
- const ro = mount.readOnly ? ":ro" : "";
6591
- args.push("-v", `${mount.hostPath}:${mount.containerPath}${ro}`);
6592
- }
6593
- const sensitiveKeys = opts.sensitiveEnvKeys && opts.sensitiveEnvKeys.size > 0 ? /* @__PURE__ */ new Set([...SENSITIVE_ENV_KEYS, ...opts.sensitiveEnvKeys]) : SENSITIVE_ENV_KEYS;
6594
- const { passthrough: passthroughEnv, collisions } = appendEnvFlags(args, opts.env, sensitiveKeys);
6595
- if (opts.tmpfs) args.push("--tmpfs", `${opts.tmpfs.target}:rw,size=${opts.tmpfs.sizeMb}m`);
6596
- if (opts.workingDir) args.push("--workdir", opts.workingDir);
6597
- let entryPointTail = [];
6598
- if (opts.entryPoint && opts.entryPoint.length > 0) {
6599
- args.push("--entrypoint", opts.entryPoint[0]);
6600
- entryPointTail = opts.entryPoint.slice(1);
6601
- }
6602
- args.push(opts.image, ...entryPointTail, ...opts.cmd);
6603
- const logger = getLogger().child("docker");
6604
- logger.debug(`${getDockerCmd()} ${redactDockerArgvValues(args).map((a) => displayUntrustedValue(a)).join(" ")}`);
6605
- if (collisions.length > 0) logger.warn(describeRefusedSensitiveEnvKeys(`Container for image ${displayUntrustedValue(opts.image)}`, collisions));
6606
- const forwardedKeys = Object.keys(passthroughEnv);
6607
- const refusal = finchSecretArgvRefusal(forwardedKeys.filter((k) => opts.sensitiveEnvKeys?.has(k)), {
6608
- label: "Container for image",
6609
- name: opts.image
6610
- });
6611
- if (refusal !== void 0) throw new DockerRunnerError(refusal);
6612
- warnFinchArgvExposure(forwardedKeys);
4584
+ return new EcsTaskResolutionError(msg.trimEnd());
4585
+ }
4586
+ function checkVolumeHostPath(hostPath) {
6613
4587
  try {
6614
- const { stdout } = await execFileAsync$7(getDockerCmd(), args, {
6615
- maxBuffer: 10 * 1024 * 1024,
6616
- ...execEnvForSecrets(passthroughEnv)
6617
- });
6618
- return stdout.trim();
6619
- } catch (error) {
6620
- throw new DockerRunnerError(`docker run failed: ${displayToolOutput(error.stderr?.trim() || describeExitWithoutArgv(error))}`);
6621
- }
6622
- }
6623
- const PREFIX_CONTAINER_OUTPUT_ENV = "CDKL_PREFIX_CONTAINER_OUTPUT";
6624
- const MAX_HELD_LINE_CHARS = 64 * 1024;
6625
- function createPrefixedLineRelay(prefix, out) {
6626
- const decoder = new StringDecoder("utf8");
6627
- let pending = "";
6628
- const emit = (text) => {
6629
- let nl = text.indexOf("\n");
6630
- if (nl !== -1) nl += pending.length;
6631
- pending += text;
6632
- while (nl !== -1) {
6633
- out.write(`${prefix}${pending.slice(0, nl + 1)}`);
6634
- pending = pending.slice(nl + 1);
6635
- nl = pending.indexOf("\n");
6636
- }
6637
- while (pending.length >= MAX_HELD_LINE_CHARS) {
6638
- const high = pending.charCodeAt(MAX_HELD_LINE_CHARS - 1);
6639
- const cut = high >= 55296 && high <= 56319 ? MAX_HELD_LINE_CHARS - 1 : MAX_HELD_LINE_CHARS;
6640
- out.write(`${prefix}${pending.slice(0, cut)}\n`);
6641
- pending = pending.slice(cut);
4588
+ return existsSync(hostPath) && statSync(hostPath).isDirectory();
4589
+ } catch {
4590
+ return false;
4591
+ }
4592
+ }
4593
+ async function applyCrossStackResolverToTask(task, context) {
4594
+ if (!context.crossStackResolver) return;
4595
+ const { resolveDynamicReferences: _envOnly, ...secretContext } = context;
4596
+ const rawContainers = (task.resource.Properties ?? {})["ContainerDefinitions"];
4597
+ if (!Array.isArray(rawContainers)) return;
4598
+ for (let idx = 0; idx < task.containers.length; idx += 1) {
4599
+ const container = task.containers[idx];
4600
+ const raw = rawContainers[idx];
4601
+ if (!raw || typeof raw !== "object") continue;
4602
+ const c = raw;
4603
+ const containerName = pickString(c["Name"]) ?? container.name;
4604
+ const resolvedEnvKeys = /* @__PURE__ */ new Set();
4605
+ const resolvedSecretNames = /* @__PURE__ */ new Set();
4606
+ if (Array.isArray(c["Environment"])) for (const entry of c["Environment"]) {
4607
+ if (!entry || typeof entry !== "object") continue;
4608
+ const e = entry;
4609
+ const key = pickString(e["Name"]);
4610
+ const value = e["Value"];
4611
+ if (!key) continue;
4612
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") continue;
4613
+ if (Object.hasOwn(container.environment, key)) continue;
4614
+ if (!isCrossStackIntrinsic(value)) continue;
4615
+ const { result: sub, consumedSensitive } = await resolveWithSensitivityAsync(value, context);
4616
+ if (sub.kind === "literal") {
4617
+ defineOwnKey(container.environment, key, String(sub.value));
4618
+ resolvedEnvKeys.add(key);
4619
+ if (consumedSensitive && !container.sensitiveEnvKeys.includes(key)) container.sensitiveEnvKeys.push(key);
4620
+ }
6642
4621
  }
6643
- };
6644
- return {
6645
- push: (chunk) => emit(decoder.write(chunk)),
6646
- flush: () => {
6647
- emit(decoder.end());
6648
- if (pending.length > 0) {
6649
- out.write(`${prefix}${pending}\n`);
6650
- pending = "";
4622
+ if (Array.isArray(c["Secrets"])) for (const entry of c["Secrets"]) {
4623
+ if (!entry || typeof entry !== "object") continue;
4624
+ const e = entry;
4625
+ const sName = pickString(e["Name"]);
4626
+ const valueFromRaw = e["ValueFrom"];
4627
+ if (!sName) continue;
4628
+ if (typeof valueFromRaw === "string" && valueFromRaw.length > 0) continue;
4629
+ if (container.secrets.some((s) => s.name === sName)) continue;
4630
+ if (!isCrossStackIntrinsic(valueFromRaw)) continue;
4631
+ const sub = await substituteAgainstStateAsync(valueFromRaw, secretContext);
4632
+ if (sub.kind === "literal" && typeof sub.value === "string" && sub.value.length > 0) {
4633
+ container.secrets.push({
4634
+ name: sName,
4635
+ valueFrom: sub.value
4636
+ });
4637
+ resolvedSecretNames.add(sName);
6651
4638
  }
6652
4639
  }
6653
- };
6654
- }
6655
- function streamLogs(containerId, opts = {}) {
6656
- const proc = spawn(getDockerCmd(), [
6657
- "logs",
6658
- "-f",
6659
- containerId
6660
- ], { stdio: [
6661
- "ignore",
6662
- "pipe",
6663
- "pipe"
6664
- ] });
6665
- if (opts.onOutput) {
6666
- const tap = opts.onOutput;
6667
- proc.stdout?.on("data", (chunk) => tap(chunk));
6668
- proc.stderr?.on("data", (chunk) => tap(chunk));
6669
- }
6670
- let flush = () => void 0;
6671
- if (opts.prefix !== void 0 || process.env["CDKL_PREFIX_CONTAINER_OUTPUT"] === "1") {
6672
- const tag = opts.prefix ?? `[${flattenToOneLine(containerId.slice(0, 12)).replace(/[\]\s]/g, "_")}] `;
6673
- const stdoutRelay = createPrefixedLineRelay(tag, process.stdout);
6674
- const stderrRelay = createPrefixedLineRelay(tag, process.stderr);
6675
- proc.stdout?.on("data", (chunk) => stdoutRelay.push(chunk));
6676
- proc.stderr?.on("data", (chunk) => stderrRelay.push(chunk));
6677
- flush = () => {
6678
- stdoutRelay.flush();
6679
- stderrRelay.flush();
6680
- };
6681
- proc.on("close", () => flush());
6682
- } else {
6683
- proc.stdout?.on("data", (chunk) => process.stdout.write(chunk));
6684
- proc.stderr?.on("data", (chunk) => process.stderr.write(chunk));
4640
+ if (resolvedEnvKeys.size > 0 || resolvedSecretNames.size > 0) {
4641
+ container.warnings = container.warnings.filter((w) => {
4642
+ for (const k of resolvedEnvKeys) if (w.startsWith(`Environment ${displayIdent(k)} dropped:`)) return false;
4643
+ for (const k of resolvedSecretNames) if (w.startsWith(`Secret ${displayIdent(k)} dropped:`)) return false;
4644
+ return true;
4645
+ });
4646
+ task.warnings = task.warnings.filter((w) => {
4647
+ for (const k of resolvedEnvKeys) if (w.startsWith(`Container ${displayIdent(containerName)}: Environment ${displayIdent(k)} dropped:`)) return false;
4648
+ for (const k of resolvedSecretNames) if (w.startsWith(`Container ${displayIdent(containerName)}: Secret ${displayIdent(k)} dropped:`)) return false;
4649
+ return true;
4650
+ });
4651
+ }
6685
4652
  }
6686
- proc.on("error", () => {});
6687
- return () => {
6688
- flush();
6689
- if (!proc.killed) proc.kill("SIGTERM");
6690
- };
6691
4653
  }
6692
- async function removeContainer(containerId) {
6693
- if (!containerId) return;
6694
- const logger = getLogger().child("docker");
6695
- try {
6696
- await execFileAsync$7(getDockerCmd(), [
6697
- "rm",
6698
- "-f",
6699
- containerId
6700
- ]);
6701
- logger.debug(`Removed container ${containerId}`);
6702
- } catch (error) {
6703
- const err = error;
6704
- logger.debug(`docker rm -f ${containerId} failed: ${err.stderr || err.message || String(error)}`);
4654
+
4655
+ //#endregion
4656
+ //#region src/local/runtime-image.ts
4657
+ const SUPPORTED_RUNTIMES = {
4658
+ "nodejs18.x": {
4659
+ image: "public.ecr.aws/lambda/nodejs:18",
4660
+ fileExtension: ".js"
4661
+ },
4662
+ "nodejs20.x": {
4663
+ image: "public.ecr.aws/lambda/nodejs:20",
4664
+ fileExtension: ".js"
4665
+ },
4666
+ "nodejs22.x": {
4667
+ image: "public.ecr.aws/lambda/nodejs:22",
4668
+ fileExtension: ".js"
4669
+ },
4670
+ "nodejs24.x": {
4671
+ image: "public.ecr.aws/lambda/nodejs:24",
4672
+ fileExtension: ".js"
4673
+ },
4674
+ "python3.11": {
4675
+ image: "public.ecr.aws/lambda/python:3.11",
4676
+ fileExtension: ".py"
4677
+ },
4678
+ "python3.12": {
4679
+ image: "public.ecr.aws/lambda/python:3.12",
4680
+ fileExtension: ".py"
4681
+ },
4682
+ "python3.13": {
4683
+ image: "public.ecr.aws/lambda/python:3.13",
4684
+ fileExtension: ".py"
4685
+ },
4686
+ "python3.14": {
4687
+ image: "public.ecr.aws/lambda/python:3.14",
4688
+ fileExtension: ".py"
4689
+ },
4690
+ "ruby3.2": {
4691
+ image: "public.ecr.aws/lambda/ruby:3.2",
4692
+ fileExtension: ".rb"
4693
+ },
4694
+ "ruby3.3": {
4695
+ image: "public.ecr.aws/lambda/ruby:3.3",
4696
+ fileExtension: ".rb"
4697
+ },
4698
+ "java8.al2": {
4699
+ image: "public.ecr.aws/lambda/java:8.al2",
4700
+ fileExtension: null
4701
+ },
4702
+ java11: {
4703
+ image: "public.ecr.aws/lambda/java:11",
4704
+ fileExtension: null
4705
+ },
4706
+ java17: {
4707
+ image: "public.ecr.aws/lambda/java:17",
4708
+ fileExtension: null
4709
+ },
4710
+ java21: {
4711
+ image: "public.ecr.aws/lambda/java:21",
4712
+ fileExtension: null
4713
+ },
4714
+ dotnet6: {
4715
+ image: "public.ecr.aws/lambda/dotnet:6",
4716
+ fileExtension: null
4717
+ },
4718
+ dotnet8: {
4719
+ image: "public.ecr.aws/lambda/dotnet:8",
4720
+ fileExtension: null
4721
+ },
4722
+ "provided.al2": {
4723
+ image: "public.ecr.aws/lambda/provided:al2",
4724
+ fileExtension: null
4725
+ },
4726
+ "provided.al2023": {
4727
+ image: "public.ecr.aws/lambda/provided:al2023",
4728
+ fileExtension: null
6705
4729
  }
6706
- }
6707
- async function ensureDockerAvailable() {
6708
- const cmd = getDockerCmd();
6709
- try {
6710
- await execFileAsync$7(cmd, [
6711
- "version",
6712
- "--format",
6713
- "{{.Server.Version}}"
6714
- ]);
6715
- } catch (error) {
6716
- const err = error;
6717
- if (err.code === "ENOENT") throw new DockerRunnerError(`${cmd} is not installed or not on PATH. ${getEmbedConfig().cliName} invoke needs Docker (or a compatible CLI specified via CDK_DOCKER) — install it and retry.`);
6718
- throw new DockerRunnerError(`${cmd} daemon is not reachable: ${err.stderr?.trim() || err.message || String(error)}. Start Docker Desktop / the docker daemon and retry.`);
4730
+ };
4731
+ var UnsupportedRuntimeError = class UnsupportedRuntimeError extends Error {
4732
+ runtime;
4733
+ constructor(runtime, message) {
4734
+ super(message);
4735
+ this.runtime = runtime;
4736
+ this.name = "UnsupportedRuntimeError";
4737
+ Object.setPrototypeOf(this, UnsupportedRuntimeError.prototype);
6719
4738
  }
4739
+ };
4740
+ function resolveRuntimeImage(runtime) {
4741
+ return resolveRuntimeSpec(runtime).image;
6720
4742
  }
6721
- function pickFreePort() {
6722
- return new Promise((resolvePort, rejectPort) => {
6723
- const server = createServer$2();
6724
- server.unref();
6725
- server.on("error", rejectPort);
6726
- server.listen(0, "127.0.0.1", () => {
6727
- const address = server.address();
6728
- if (!address || typeof address === "string") {
6729
- server.close();
6730
- rejectPort(/* @__PURE__ */ new Error("Could not allocate a host port"));
6731
- return;
6732
- }
6733
- const port = address.port;
6734
- server.close(() => resolvePort(port));
6735
- });
6736
- });
6737
- }
6738
- const SENSITIVE_ENV_KEYS = /* @__PURE__ */ new Set([
6739
- "AWS_ACCESS_KEY_ID",
6740
- "AWS_SECRET_ACCESS_KEY",
6741
- "AWS_SESSION_TOKEN"
6742
- ]);
6743
- function appendEnvFlags(args, env, sensitiveKeys) {
6744
- const passthrough = {};
6745
- const collisions = [];
6746
- for (const [k, v] of Object.entries(env)) if (sensitiveKeys.has(k)) {
6747
- if (isMalformedEnvKey(k) || isDockerClientEnvKey(k)) {
6748
- collisions.push(k);
6749
- continue;
6750
- }
6751
- args.push("-e", k);
6752
- defineOwnKey(passthrough, k, v);
6753
- } else args.push("-e", `${k}=${v}`);
6754
- return {
6755
- passthrough,
6756
- collisions
6757
- };
4743
+ function resolveRuntimeFileExtension(runtime) {
4744
+ const spec = resolveRuntimeSpec(runtime);
4745
+ if (spec.fileExtension === null) throw new UnsupportedRuntimeError(runtime, `Inline 'Code.ZipFile' is not supported for runtime ${displayIdent(runtime)}. The Lambda Handler shape for this runtime names a compiled artifact (a JVM class, a .NET assembly, or — for the OS-only \`provided.*\` runtimes — an arbitrary \`bootstrap\` binary) that cannot be expressed as a single inline source file. Use \`lambda.Code.fromAsset(<dir>)\` with a directory containing the compiled output (.class hierarchy / JAR / DLL / native binary).`);
4746
+ return spec.fileExtension;
6758
4747
  }
6759
- function describeRefusedSensitiveEnvKeys(subject, keys) {
6760
- return `${subject}: sensitive env var(s) ${keys.map(displayUntrustedValue).join(", ")} share a name with a variable the container client reads (docker, or the CDK_DOCKER binary) or have a malformed name (empty, or containing '=' / NUL), and were NOT passed to the container at all (a colliding name would hijack that client; a malformed name cannot form a valid environment variable). Rename the variable if the container needs it.`;
4748
+ function resolveRuntimeSpec(runtime) {
4749
+ if (typeof runtime !== "string" || runtime.length === 0) throw new UnsupportedRuntimeError(String(runtime), "Lambda function has no Runtime property. This branch is only reached for ZIP Lambdas; container-image Lambdas (Code.ImageUri) take a different code path that does not consult the Runtime property.");
4750
+ const spec = SUPPORTED_RUNTIMES[runtime];
4751
+ if (spec) return spec;
4752
+ if (runtime === "go1.x") throw new UnsupportedRuntimeError(runtime, "Runtime 'go1.x' was deprecated by AWS Lambda on 2024-01-08 and is no longer available. Migrate to the OS-only runtime: build your Go program as a `bootstrap` binary and set the CDK runtime to `lambda.Runtime.PROVIDED_AL2023` (or `lambda.Runtime.PROVIDED_AL2`). See https://docs.aws.amazon.com/lambda/latest/dg/lambda-golang.html");
4753
+ throw new UnsupportedRuntimeError(runtime, `Unknown runtime ${displayIdent(runtime)}. ${getEmbedConfig().cliName} invoke supports nodejs18.x / nodejs20.x / nodejs22.x / nodejs24.x / python3.11 / python3.12 / python3.13 / python3.14 / ruby3.2 / ruby3.3 / java8.al2 / java11 / java17 / java21 / dotnet6 / dotnet8 / provided.al2 / provided.al2023.`);
6761
4754
  }
6762
- function execEnvForSecrets(passthrough) {
6763
- const keys = Object.keys(passthrough).filter((k) => !isMalformedEnvKey(k) && !isDockerClientEnvKey(k));
6764
- if (keys.length === 0) return {};
6765
- const env = { ...process.env };
6766
- for (const k of keys) defineOwnKey(env, k, passthrough[k]);
6767
- return { env };
4755
+ function resolveRuntimeCodeMountPath(runtime) {
4756
+ resolveRuntimeSpec(runtime);
4757
+ if (runtime === "provided.al2" || runtime === "provided.al2023") return "/var/runtime";
4758
+ return "/var/task";
6768
4759
  }
6769
4760
 
6770
4761
  //#endregion
@@ -12594,6 +10585,7 @@ async function localStartApiCommand(targets, options, extraStateProviders) {
12594
10585
  const normalizedAssumeRole = normalizeStartApiAssumeRole(options.assumeRole, options.assumeRoleAuto ?? false);
12595
10586
  if (normalizedAssumeRole === void 0) delete options.assumeRole;
12596
10587
  else options.assumeRole = normalizedAssumeRole;
10588
+ await activateWorkloadAwsWiring(options);
12597
10589
  await applyRoleArnIfSet({
12598
10590
  roleArn: options.roleArn,
12599
10591
  region: options.region,
@@ -13885,6 +11877,7 @@ function createLocalStartApiCommand(opts = {}) {
13885
11877
  return startApi;
13886
11878
  }
13887
11879
  function addStartApiSpecificOptions(cmd) {
11880
+ addAwsEndpointOptions(cmd);
13888
11881
  return cmd.addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--stack <name>", "Stack to start (single-stack apps auto-detect)")).addOption(new Option("--all-stacks", "Serve every stack's API in a multi-stack app (each API on its own port) instead of erroring out. Mutually exclusive with a positional target subset, --stack, and an explicit --from-cfn-stack <name>; the bare --from-cfn-stack flag stays compatible (binds each routed stack to its own CFn stack).").default(false)).addOption(new Option("--warm", "Pre-start one container per Lambda at server boot").default(false)).addOption(new Option("--per-lambda-concurrency <n>", "Pool size cap per Lambda (default 2, max 4)").default("2")).addOption(new Option("--no-pull", "Skip docker pull (cached image)")).addOption(new Option("--no-build", "Skip docker build on every container Lambda local-asset build (use the previously-built tag). Requires the deterministic tag to already be in the local registry; errors with an actionable message when missing. No-op for ZIP Lambdas and the IMAGE ECR-pull path. Compatible with --no-pull.")).addOption(new Option("--container-host <host>", "IP the host uses to bind/probe the RIE port (must be a numeric IP — `docker run -p <ip>:<port>:8080` rejects hostnames). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--debug-port-base <port>", "Reserve a contiguous --debug-port range (one per Lambda)")).addOption(new Option("--debug-port <port>", "Alias of --debug-port-base for parity with `cdkl invoke --debug-port`. Reserves a contiguous --debug-port range (one per Lambda) starting at <port>.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries on the container-Lambda ECR-pull fallback. Issues sts:AssumeRole via the default credential chain and uses the temporary credentials for ecr:GetAuthorizationToken + docker pull. Required when the caller does not have direct cross-account access to the target repository. Same-account / same-region pulls do not need this flag.")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--assume-role <arn-or-pair>", "Assume the Lambda's execution role and forward STS-issued temp creds. Two forms: (1) `--assume-role <arn>` sets a single global default ARN used for every routed Lambda; (2) `--assume-role <LogicalId>=<arn>` (repeatable) is a per-Lambda override (wins over the global default and over --assume-role-auto for the named Lambda). Pair with --assume-role-auto to auto-resolve every other Lambda. Precedence: per-Lambda > (--assume-role-auto OR global default) > unset (developer creds passed through).").argParser((raw, prev) => parseAssumeRoleToken(raw, prev))).addOption(new Option("--assume-role-auto", "Auto-resolve EACH routed Lambda's own execution role per-Lambda (literal ARN / Fn::GetAtt against template / --from-cfn-stack state). Slower boot — one STS call per Lambda — but the right shape when each Lambda's deployed role differs. Mutually exclusive with `--assume-role <arn>` (global default); errors at boot. Compatible with `--assume-role <LogicalId>=<arn>` per-Lambda overrides — the map wins for named Lambdas, auto-resolve handles the rest.").default(false)).addOption(new Option("--watch", "Hot-reload: re-synth + re-discover routes when the CDK app's source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). Off by default; the server keeps the previous version serving when synth fails mid-reload.").default(false)).addOption(new Option("--stage <name>", "Select an API Gateway Stage by its 'StageName'. Default: the first Stage attached to each API. Drives event.stageVariables for both REST v1 and HTTP API v2. NOTE: For HTTP API v2 routes, requestContext.stage is always '$default' regardless of this flag (AWS-side limitation — HTTP API only exposes one stage to the integration event); only event.stageVariables is affected for v2 routes. For REST v1 routes the selected StageName is also threaded into requestContext.stage.")).addOption(new Option("--api <id>", "DEPRECATED — use the positional <targets...> argument instead. Accepts a SINGLE identifier; for a subset pass multiple positional targets. Same accepted forms (bare logical id, stack-qualified, Construct path, ancestor prefix). Will be removed in a future major release.")).addOption(new Option("--layer-role-arn <arn>", "Role to sts:AssumeRole before calling lambda:GetLayerVersion on every literal-ARN entry in Properties.Layers (issue #448). Use only when the dev credentials cannot read the layer — typically cross-account layers. AWS-published public layers (e.g. Lambda Powertools) are readable from every account and need no role.")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in Lambda env vars with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the resolved stack name per routed stack; pass an explicit value when a single CFn stack should serve every routed stack. Fn::GetAtt is warn-and-dropped in v1 (CFn ListStackResources does not return per-attribute values).")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).addOption(new Option("--mtls-truststore <path>", `PEM-encoded CA bundle for client-certificate verification (mutual TLS). When set, the local server switches from HTTP to HTTPS and the TLS handshake rejects clients whose certificate doesn't chain to one of these CAs. Verified certs are surfaced on the Lambda event under requestContext.identity.clientCert (REST v1) / requestContext.authentication.clientCert (HTTP API v2). Must be set together with --mtls-cert + --mtls-key; partial flag sets are rejected. Generate a CA + server + client cert for local dev: openssl req -x509 -newkey rsa:2048 -nodes -keyout ca-key.pem -out ca.pem -subj "/CN=${getEmbedConfig().resourceNamePrefix}-ca" -days 365; openssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-csr.pem -subj "/CN=localhost"; openssl x509 -req -in server-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365; openssl req -newkey rsa:2048 -nodes -keyout client-key.pem -out client-csr.pem -subj "/CN=client"; openssl x509 -req -in client-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365; curl --cacert ca.pem --cert client-cert.pem --key client-key.pem https://localhost:<port>/...`)).addOption(new Option("--mtls-cert <path>", "PEM-encoded server certificate for mutual TLS. Self-signed is fine for local dev. Must be set together with --mtls-truststore + --mtls-key.")).addOption(new Option("--mtls-key <path>", "PEM-encoded server private key matching --mtls-cert. Must be set together with --mtls-truststore + --mtls-cert.")).addOption(new Option("--strict-sigv4", "Opt-in: DENY AWS_IAM SigV4 requests that cannot be cryptographically verified (foreign access-key-id — e.g. a federated / Cognito Identity Pool / cross-account signer — OR no local AWS credentials configured) instead of the default warn-and-pass. DEFAULT off: cdk-local warn-and-passes unverifiable IAM requests with a placeholder principalId so local dev exercises app logic without reproducing an auth boundary it cannot fully emulate. OAC-fronted Function URLs always warn-and-pass regardless.").default(false));
13889
11882
  }
13890
11883
 
@@ -13950,6 +11943,7 @@ async function localInvokeCommand(target, options, extraStateProviders) {
13950
11943
  getLogger().debug(`cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
13951
11944
  });
13952
11945
  try {
11946
+ await activateWorkloadAwsWiring(options);
13953
11947
  await applyRoleArnIfSet({
13954
11948
  roleArn: options.roleArn,
13955
11949
  region: options.region,
@@ -14564,6 +12558,7 @@ function createLocalInvokeCommand(opts = {}) {
14564
12558
  return invoke;
14565
12559
  }
14566
12560
  function addInvokeSpecificOptions(cmd) {
12561
+ addAwsEndpointOptions(cmd);
14567
12562
  return cmd.addOption(new Option("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option("--event-stdin", "Read event JSON from stdin").default(false)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--no-pull", "Skip docker pull. Semantics differ by code path: ZIP Lambdas skip pulling the public Lambda base image; Container Lambdas on the local-build path are a no-op (docker build does not refresh the FROM cache by default); Container Lambdas on the ECR-pull fallback skip docker pull AND error if the image is not in the local cache (re-run without --no-pull or pre-pull manually).")).addOption(new Option("--no-build", "Skip docker build on the IMAGE local-build path (use the previously-built tag). Requires the deterministic tag to already be in the local registry; errors with an actionable message when missing. No-op for ZIP Lambdas and the IMAGE ECR-pull path. Compatible with --no-pull.")).addOption(new Option("--debug-port <port>", "Node --inspect-brk port (default: off)")).addOption(new Option("--container-host <host>", "Host IP the host uses to bind the RIE port to. Must be a numeric IP (Docker rejects hostnames here). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--assume-role [arn]", "Assume the Lambda's deployed execution role and forward STS-issued temp credentials to the container so the handler runs with the deployed function's narrow permissions. Three forms: (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) auto-resolves the function's execution role ARN from state (requires an active state source); (3) `--no-assume-role` explicitly opts out. Off by default — when omitted, the developer's shell credentials are forwarded unchanged (SAM-compatible default). STS failures degrade to a warn + dev-creds fallback.")).addOption(new Option("--layer-role-arn <arn>", "Role to sts:AssumeRole before calling lambda:GetLayerVersion on every literal-ARN entry in Properties.Layers. Use only when the dev credentials cannot read the layer — typically cross-account layers. AWS-published public layers (e.g. Lambda Powertools) are readable from every account and need no role.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries. Issues sts:AssumeRole via the default credential chain and uses the temporary credentials for ecr:GetAuthorizationToken + docker pull. Required when the caller does not have direct cross-account access to the target repository. Same-account / same-region pulls do not need this flag.")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in env vars with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the resolved stack name; pass an explicit value when CFn stack name differs. Fn::GetAtt is warn-and-dropped in v1 (CFn ListStackResources does not return per-attribute values).")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).addOption(new Option("--response-file <path>", "Also write the raw Lambda response payload to this file. Lets a programmatic caller recover the response without parsing it out of stdout (where it interleaves with synth progress + streamed container logs). stdout output is unchanged."));
14568
12563
  }
14569
12564
 
@@ -15429,6 +13424,7 @@ async function localInvokeAgentCoreCommand(target, options, extraStateProviders)
15429
13424
  getLogger().debug(`cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
15430
13425
  });
15431
13426
  try {
13427
+ await activateWorkloadAwsWiring(options);
15432
13428
  await applyRoleArnIfSet({
15433
13429
  roleArn: options.roleArn,
15434
13430
  region: options.region,
@@ -16324,6 +14320,8 @@ async function softReloadAgentContainer(containerId, newAssetSourceDir) {
16324
14320
  }
16325
14321
  try {
16326
14322
  await execFileAsync$6(dockerCmd, ["restart", containerId]);
14323
+ const wiring = getActiveWorkloadAwsWiring();
14324
+ if (wiring) await attachLoopbackForwarder(containerId, wiring);
16327
14325
  } catch (err) {
16328
14326
  throw new CdkLocalError(`softReloadAgentContainer: docker restart of '${containerId}' failed: ${describeExecError(err)}.`, "LOCAL_INVOKE_AGENTCORE_WATCH_SOFT_RELOAD_RESTART_FAILED");
16329
14327
  }
@@ -16401,6 +14399,7 @@ function createLocalInvokeAgentCoreCommand(opts = {}) {
16401
14399
  return cmd;
16402
14400
  }
16403
14401
  function addInvokeAgentCoreSpecificOptions(cmd) {
14402
+ addAwsEndpointOptions(cmd);
16404
14403
  return cmd.addOption(new Option("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option("--event-stdin", "Read event JSON from stdin").default(false)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--session-id <id>", "AgentCore runtime session id header value (default: a random UUID)")).addOption(new Option("--ws", "Stream over the HTTP-protocol agent's bidirectional /ws WebSocket endpoint (on 8080) instead of POST /invocations: send --event as the first frame and print every received frame to stdout until the agent closes. When stdin is a TTY, additionally reads stdin lines as follow-up text frames (multi-turn REPL; Ctrl-D to end). When stdin is piped / redirected / non-TTY (CI), only the initial --event frame is sent (one-shot). Force one-shot in a TTY with `cdkl ... --ws </dev/null`. Ignored for an MCP runtime.").default(false)).addOption(new Option("--bearer-token <jwt>", "Bearer JWT this command SUPPLIES (the supplier role) when the runtime declares a customJwtAuthorizer — `cdkl invoke-agentcore` is the local-dev client making the outbound call, so it always presents this token to its own invocation. Verified against the runtime's OIDC discovery URL (signature / issuer / expiry / audience) before the container starts, then forwarded to /invocations as Authorization: Bearer <jwt>. Contrast with `cdkl start-alb --bearer-token`, where the role is reversed — the ALB front-door RECEIVES inbound requests and injects this token only as a default when an inbound request has none (default-when-missing).")).addOption(new Option("--no-verify-auth", "Skip inbound JWT verification even when the runtime declares a customJwtAuthorizer (local-dev escape hatch). A --bearer-token, if given, is still forwarded.")).addOption(new Option("--sigv4", "Sign the /invocations POST with AWS SigV4 (service bedrock-agentcore) using the resolved credentials, matching the cloud default when the runtime declares no customJwtAuthorizer. Opt-in: default unsigned. Mutually exclusive with --bearer-token; ignored on a JWT-protected runtime.").default(false)).addOption(new Option("--platform <platform>", "docker --platform for the agent container (linux/amd64 or linux/arm64). Defaults to linux/arm64 because the cloud AgentCore Runtime requires arm64. Override to linux/amd64 only when iterating against an amd64 dev container locally; note the image will not run on the cloud runtime as-is.").choices(["linux/amd64", "linux/arm64"]).default("linux/arm64")).addOption(new Option("--no-pull", "Skip docker pull (use cached image) — no-op for the local-build path")).addOption(new Option("--no-build", "Skip docker build on the local-asset path (use the previously-built tag). No-op for the ECR / registry pull paths.")).addOption(new Option("--container-host <host>", "Host IP the host uses to bind the agent port to. Must be a numeric IP (Docker rejects hostnames here). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--timeout <ms>", "Per-request timeout in milliseconds. Applied to POST /invocations, POST /mcp, and the /ws open-to-close window. Raise this for long-running agent calls that exceed the default.").default(12e4).argParser(parseTimeoutMs)).addOption(new Option("--assume-role [arn]", "Assume the runtime's execution role and forward STS-issued temp credentials to the container so the agent runs with the deployed role. Three forms: (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) uses the runtime's RoleArn when it is a literal ARN; (3) `--no-assume-role` opts out. Off by default — the developer's shell credentials are forwarded unchanged.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries. Same-account / same-region pulls do not need this flag.")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in env vars with the deployed physical IDs / exports. Bare form uses the resolved stack name; pass an explicit value when the CFn stack name differs.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).addOption(new Option("--watch", "Re-synth and reload the agent container on CDK source changes. Only meaningful with the long-running --ws session path; single-shot POST /invocations, MCP, and A2A invocations run once and exit, so --watch is logged as a no-op WARN for them and the single shot proceeds. The active /ws socket is closed cleanly on every reload firing so the next session connects to the rebuilt container — the honest local-dev semantic.").default(false));
16405
14404
  }
16406
14405
 
@@ -17106,7 +15105,8 @@ async function runEcsTask(task, options, state) {
17106
15105
  });
17107
15106
  dockerCmds.set(container.name, {
17108
15107
  args: built.args,
17109
- sensitiveEnv: built.sensitiveEnv
15108
+ sensitiveEnv: built.sensitiveEnv,
15109
+ loopbackPorts: built.loopbackPorts
17110
15110
  });
17111
15111
  if (built.collisions.length > 0) logger.warn(describeRefusedSensitiveEnvKeys(`Container ${displayUntrustedValue(container.name)}`, built.collisions));
17112
15112
  for (const ep of built.publishedEndpoints) state.publishedEndpoints.push(ep);
@@ -17115,7 +15115,9 @@ async function runEcsTask(task, options, state) {
17115
15115
  for (const containerName of startOrder) {
17116
15116
  const container = task.containers.find((c) => c.name === containerName);
17117
15117
  await awaitDependencies(container, startedByName);
17118
- const { args, sensitiveEnv } = dockerCmds.get(container.name);
15118
+ const { args, sensitiveEnv, loopbackPorts } = dockerCmds.get(container.name);
15119
+ const forwarderWiring = getActiveWorkloadAwsWiring();
15120
+ if (loopbackPorts.length > 0 && forwarderWiring) await prepareLoopbackForwarder(forwarderWiring);
17119
15121
  logger.info(`Starting container ${displayIdent(container.name)} (image=${displayIdent(imagePlan.get(container.name))})`);
17120
15122
  let id;
17121
15123
  warnFinchArgvExposure(Object.keys(sensitiveEnv));
@@ -17137,6 +15139,8 @@ async function runEcsTask(task, options, state) {
17137
15139
  id,
17138
15140
  container
17139
15141
  });
15142
+ const wiring = getActiveWorkloadAwsWiring();
15143
+ if (wiring) await attachLoopbackForwarder(id, wiring, loopbackPorts);
17140
15144
  if (!options.detach) state.logStoppers.push(attachContainerLogStreamer(`[${displayIdent(container.name)}] `, id));
17141
15145
  }
17142
15146
  if (options.detach) return {
@@ -17460,7 +15464,10 @@ function buildDockerRunArgs(opts) {
17460
15464
  args.push("-p", `${containerHost}::${pm.containerPort}/${pm.protocol}`);
17461
15465
  }
17462
15466
  }
17463
- if (opts.profileCredentialsFile) args.push("-v", `${opts.profileCredentialsFile.hostPath}:${opts.profileCredentialsFile.containerPath}:ro`);
15467
+ const wiring = getActiveWorkloadAwsWiring();
15468
+ const profileCredentialsFile = wiring?.mode === "emulator" ? void 0 : opts.profileCredentialsFile;
15469
+ if (profileCredentialsFile) args.push("-v", `${profileCredentialsFile.hostPath}:${profileCredentialsFile.containerPath}:ro`);
15470
+ for (const m of wiring?.mounts ?? []) if (!container.mountPoints.some((mp) => mp.containerPath === m.containerPath)) args.push("-v", `${m.hostPath}:${m.containerPath}:ro`);
17464
15471
  for (const mp of container.mountPoints) {
17465
15472
  const v = volumeByName.get(mp.sourceVolume);
17466
15473
  if (!v) continue;
@@ -17474,7 +15481,7 @@ function buildDockerRunArgs(opts) {
17474
15481
  args.push("-v", `${name}:${mp.containerPath}${ro}`);
17475
15482
  }
17476
15483
  }
17477
- const finalEnv = {};
15484
+ let finalEnv = {};
17478
15485
  const metaEnv = buildMetadataEnv({
17479
15486
  containerName: container.name,
17480
15487
  ...roleArn !== void 0 && { roleArn },
@@ -17482,10 +15489,11 @@ function buildDockerRunArgs(opts) {
17482
15489
  ...opts.sidecarIp !== void 0 && { sidecarIp: opts.sidecarIp }
17483
15490
  });
17484
15491
  Object.assign(finalEnv, metaEnv);
17485
- if (opts.profileCredentialsFile) {
17486
- finalEnv["AWS_SHARED_CREDENTIALS_FILE"] = opts.profileCredentialsFile.containerPath;
17487
- finalEnv["AWS_PROFILE"] = opts.profileCredentialsFile.profileName;
15492
+ if (profileCredentialsFile) {
15493
+ finalEnv["AWS_SHARED_CREDENTIALS_FILE"] = profileCredentialsFile.containerPath;
15494
+ finalEnv["AWS_PROFILE"] = profileCredentialsFile.profileName;
17488
15495
  }
15496
+ if (wiring?.mode === "forward") for (const [k, v] of Object.entries(wiring.env)) defineOwnKey(finalEnv, k, v);
17489
15497
  for (const [k, v] of Object.entries(container.environment)) defineOwnKey(finalEnv, k, v);
17490
15498
  for (const s of secrets) defineOwnKey(finalEnv, s.name, s.value);
17491
15499
  const overrides = opts.envOverrides;
@@ -17493,6 +15501,10 @@ function buildDockerRunArgs(opts) {
17493
15501
  applyEnvOverrideMap(finalEnv, overrides["Parameters"]);
17494
15502
  applyEnvOverrideMap(finalEnv, overrides[container.name]);
17495
15503
  }
15504
+ if (wiring) finalEnv = applyWorkloadAwsWiringToEnv(finalEnv, wiring.mode === "emulator" ? wiring : {
15505
+ ...wiring,
15506
+ env: {}
15507
+ });
17496
15508
  const sensitiveEnvKeys = new Set(SENSITIVE_ENV_KEYS);
17497
15509
  for (const s of secrets) sensitiveEnvKeys.add(s.name);
17498
15510
  for (const s of container.secrets) sensitiveEnvKeys.add(s.name);
@@ -17522,7 +15534,8 @@ function buildDockerRunArgs(opts) {
17522
15534
  args,
17523
15535
  sensitiveEnv,
17524
15536
  collisions,
17525
- publishedEndpoints
15537
+ publishedEndpoints,
15538
+ loopbackPorts: wiring ? effectiveLoopbackPorts(finalEnv, wiring) : []
17526
15539
  };
17527
15540
  }
17528
15541
  function shellJoin(parts) {
@@ -18334,7 +16347,7 @@ async function softReloadReplica(args) {
18334
16347
  const defaultDockerInspectWorkdirImpl = async (containerId) => {
18335
16348
  const { execFile } = await import("node:child_process");
18336
16349
  const { promisify } = await import("node:util");
18337
- const { getDockerCmd } = await import("./docker-cmd-CoZdbeos.js").then((n) => n.t);
16350
+ const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
18338
16351
  const { stdout } = await promisify(execFile)(getDockerCmd(), [
18339
16352
  "inspect",
18340
16353
  "--format",
@@ -18347,7 +16360,7 @@ let dockerInspectWorkdirImpl = defaultDockerInspectWorkdirImpl;
18347
16360
  const defaultDockerCpImpl = async (src, dst) => {
18348
16361
  const { execFile } = await import("node:child_process");
18349
16362
  const { promisify } = await import("node:util");
18350
- const { getDockerCmd } = await import("./docker-cmd-CoZdbeos.js").then((n) => n.t);
16363
+ const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
18351
16364
  await promisify(execFile)(getDockerCmd(), [
18352
16365
  "cp",
18353
16366
  src,
@@ -18358,14 +16371,20 @@ let dockerCpImpl = defaultDockerCpImpl;
18358
16371
  const defaultDockerStopImpl = async (containerId) => {
18359
16372
  const { execFile } = await import("node:child_process");
18360
16373
  const { promisify } = await import("node:util");
18361
- const { getDockerCmd } = await import("./docker-cmd-CoZdbeos.js").then((n) => n.t);
16374
+ const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
18362
16375
  await promisify(execFile)(getDockerCmd(), ["stop", containerId]);
18363
16376
  };
18364
16377
  const defaultDockerStartImpl = async (containerId) => {
18365
16378
  const { execFile } = await import("node:child_process");
18366
16379
  const { promisify } = await import("node:util");
18367
- const { getDockerCmd } = await import("./docker-cmd-CoZdbeos.js").then((n) => n.t);
16380
+ const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
18368
16381
  await promisify(execFile)(getDockerCmd(), ["start", containerId]);
16382
+ const { getActiveWorkloadAwsWiring } = await import("./workload-aws-wiring-BIxf0jtl.js").then((n) => n.b);
16383
+ const wiring = getActiveWorkloadAwsWiring();
16384
+ if (wiring) {
16385
+ const { attachLoopbackForwarder } = await import("./docker-runner-CnXQIUjd.js").then((n) => n.o);
16386
+ await attachLoopbackForwarder(containerId, wiring);
16387
+ }
18369
16388
  };
18370
16389
  let dockerStopImpl = defaultDockerStopImpl;
18371
16390
  let dockerStartImpl = defaultDockerStartImpl;
@@ -18425,7 +16444,7 @@ async function attachToSharedNetwork(containerId, plan, withAliases) {
18425
16444
  const defaultDockerNetworkConnectImpl = async (networkName, containerId, opts) => {
18426
16445
  const { execFile } = await import("node:child_process");
18427
16446
  const { promisify } = await import("node:util");
18428
- const { getDockerCmd } = await import("./docker-cmd-CoZdbeos.js").then((n) => n.t);
16447
+ const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
18429
16448
  const args = ["network", "connect"];
18430
16449
  if (opts.ip) args.push("--ip", opts.ip);
18431
16450
  for (const a of opts.aliases) args.push("--alias", a);
@@ -18436,7 +16455,7 @@ let dockerNetworkConnectImpl = defaultDockerNetworkConnectImpl;
18436
16455
  const defaultDockerInspectPublishesHostPortsImpl = async (containerId) => {
18437
16456
  const { execFile } = await import("node:child_process");
18438
16457
  const { promisify } = await import("node:util");
18439
- const { getDockerCmd } = await import("./docker-cmd-CoZdbeos.js").then((n) => n.t);
16458
+ const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
18440
16459
  const { stdout } = await promisify(execFile)(getDockerCmd(), [
18441
16460
  "inspect",
18442
16461
  "--format",
@@ -18475,7 +16494,7 @@ async function disconnectOldFromSharedNetwork(oldInstance, opts = {}) {
18475
16494
  const defaultDockerNetworkDisconnectImpl = async (networkName, containerId) => {
18476
16495
  const { execFile } = await import("node:child_process");
18477
16496
  const { promisify } = await import("node:util");
18478
- const { getDockerCmd } = await import("./docker-cmd-CoZdbeos.js").then((n) => n.t);
16497
+ const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
18479
16498
  await promisify(execFile)(getDockerCmd(), [
18480
16499
  "network",
18481
16500
  "disconnect",
@@ -18566,7 +16585,7 @@ const LISTEN_PROBE_SCRIPT = [
18566
16585
  async function dockerExecListenProbe(containerId, port, timeoutMs = 1e4) {
18567
16586
  const { execFile } = await import("node:child_process");
18568
16587
  const { promisify } = await import("node:util");
18569
- const { getDockerCmd } = await import("./docker-cmd-CoZdbeos.js").then((n) => n.t);
16588
+ const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
18570
16589
  try {
18571
16590
  await promisify(execFile)(getDockerCmd(), [
18572
16591
  "exec",
@@ -18720,7 +16739,7 @@ function pickEssentialContainerId(instance, service) {
18720
16739
  const defaultWaitForExitImpl = async (containerId) => {
18721
16740
  const { execFile } = await import("node:child_process");
18722
16741
  const { promisify } = await import("node:util");
18723
- const { getDockerCmd } = await import("./docker-cmd-CoZdbeos.js").then((n) => n.t);
16742
+ const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
18724
16743
  const { stdout } = await promisify(execFile)(getDockerCmd(), ["wait", containerId], { maxBuffer: 1024 * 1024 });
18725
16744
  const code = parseInt(stdout.trim(), 10);
18726
16745
  return Number.isFinite(code) ? code : -1;
@@ -18730,7 +16749,7 @@ const EXIT_LOG_TAIL_LINES = 50;
18730
16749
  const defaultReadContainerLogsImpl = async (containerId) => {
18731
16750
  const { execFile } = await import("node:child_process");
18732
16751
  const { promisify } = await import("node:util");
18733
- const { getDockerCmd } = await import("./docker-cmd-CoZdbeos.js").then((n) => n.t);
16752
+ const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
18734
16753
  const { stdout, stderr } = await promisify(execFile)(getDockerCmd(), [
18735
16754
  "logs",
18736
16755
  "--tail",
@@ -20923,6 +18942,7 @@ async function runEcsServiceEmulator(targets, options, strategy, extraStateProvi
20923
18942
  }
20924
18943
  }, (err) => getLogger().warn(`service cleanup failed: ${err instanceof Error ? err.message : String(err)}`));
20925
18944
  try {
18945
+ await activateWorkloadAwsWiring(options);
20926
18946
  await applyRoleArnIfSet({
20927
18947
  roleArn: options.roleArn,
20928
18948
  region: options.region,
@@ -21832,7 +19852,10 @@ function resolveShadowReadyTimeoutMs(options, envPrefix, env = process.env) {
21832
19852
  return DEFAULT_SHADOW_READY_TIMEOUT_MS;
21833
19853
  }
21834
19854
  async function resolveSharedSidecarCredentials(options) {
19855
+ const wiring = getActiveWorkloadAwsWiring();
19856
+ if (wiring?.mode === "emulator") return wiring.emulatorCredentials;
21835
19857
  if (options.profile) return resolveProfileCredentials(options.profile);
19858
+ return resolveHostDefaultCredentials();
21836
19859
  }
21837
19860
  async function resolveAndBuildImageOverrides(args) {
21838
19861
  const { perTarget, stacks, options, extraStateProviders, logger } = args;
@@ -21921,6 +19944,7 @@ function resolveEcsAssumeRoleOption(options) {
21921
19944
  }
21922
19945
  }
21923
19946
  function addCommonEcsServiceOptions(cmd) {
19947
+ addAwsEndpointOptions(cmd);
21924
19948
  cmd.addOption(ecsClusterOption()).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"ContainerName\":{\"KEY\":\"VALUE\"}, \"Parameters\":{}})")).addOption(new Option("--container-host <ip>", "Host IP to bind published container ports to. Must be a numeric IP (Docker rejects hostnames here)").default("127.0.0.1"));
21925
19949
  addEcsAssumeRoleOptions(cmd);
21926
19950
  cmd.addOption(new Option("--no-pull", "Skip docker pull for every container image and the metadata sidecar")).addOption(new Option("--no-build", "Skip docker build on the local CDK-asset path for every container (use the previously-built tag). Requires the deterministic tag to already be in the local registry; errors with an actionable message when missing. No-op for ECR-pull / public-registry images. Per-container --image-override mappings take precedence (the override tag is used as-is, --no-build does not apply). Compatible with --no-pull.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries.")).addOption(new Option("--platform <platform>", "Force docker --platform (linux/amd64 or linux/arm64). Default: inferred from task RuntimePlatform.CpuArchitecture")).addOption(new Option("--max-tasks <n>", `Hard cap on local replica count. Caps the template DesiredCount so local dev machines don't run an unbounded number of containers. Cannot exceed ${83} due to the per-replica link-local /24 subnet allocator's range.`).default(3).argParser(parseMaxTasks)).addOption(new Option("--restart-policy <policy>", "How to react when an essential container exits. 'on-failure' (default) restarts only on non-zero exit; 'always' restarts on every exit; 'none' shuts the replica down and runs the service degraded.").default("on-failure").argParser(parseRestartPolicy)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", `Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in container env vars / secrets / image URIs with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (\`cdk deploy\`). Bare form uses the ${getEmbedConfig().binaryName} stack name; pass an explicit value when the CFn stack name differs. Fn::GetAtt in container Environment[].Value is warn-and-dropped: CFn ListStackResources does not return per-attribute values, and unlike Lambda (where \`cdkl invoke --from-cfn-stack\` recovers Fn::GetAtt from the deployed function via lambda:GetFunctionConfiguration), no ECS-side equivalent resolves attributes off a deployed task / service.`)).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).addOption(new Option("--no-logs", "Disable foreground streaming of each replica container stdout/stderr. By default every booted replica streams its docker logs to the host terminal with a [svc=<service> r=<replica-index> c=<container>] prefix (parity with `run-task`). Pass --no-logs for multi-replica / multi-service runs whose interleaved log volume is unreadable; `docker logs -f <id>` in a separate terminal stays available.")).addOption(new Option("--shadow-ready-timeout <ms>", `Issue #265 — milliseconds the \`--watch\` rolling primitive waits for a shadow replica's first essential-container port to accept a TCP connection before swapping Cloud Map + front-door registrations off the old replica. Defaults to 60000 (60s) which covers realistic prod-shaped Node app cold-starts (TS->JS compile, full node_modules graph, framework boot, DB pool init). Bump higher when the reload log surfaces "TCP probe <ip>:<port> did not accept within <N>ms" — typical for Java / heavy ORM init / \`--inspect-brk\` attach pauses. Honored by --watch on \`${getEmbedConfig().binaryName} start-service\` and \`${getEmbedConfig().binaryName} start-alb\`. Env var: \`${getEmbedConfig().envPrefix}_SHADOW_READY_TIMEOUT_MS\` (flag wins over env).`).argParser(parseShadowReadyTimeout));
@@ -21963,6 +19987,7 @@ async function localRunTaskCommand(target, options, extraStateProviders) {
21963
19987
  await cleanupPromise;
21964
19988
  };
21965
19989
  try {
19990
+ await activateWorkloadAwsWiring(options);
21966
19991
  await applyRoleArnIfSet({
21967
19992
  roleArn: options.roleArn,
21968
19993
  region: options.region,
@@ -22216,8 +20241,11 @@ function readEnvOverridesFile(filePath) {
22216
20241
  return parsed;
22217
20242
  }
22218
20243
  async function resolveSidecarCredentials(options, assumedCredentials) {
20244
+ const wiring = getActiveWorkloadAwsWiring();
20245
+ if (wiring?.mode === "emulator") return wiring.emulatorCredentials;
22219
20246
  if (assumedCredentials) return assumedCredentials;
22220
20247
  if (options.profile) return resolveProfileCredentials(options.profile);
20248
+ return resolveHostDefaultCredentials();
22221
20249
  }
22222
20250
  function createLocalRunTaskCommand(opts = {}) {
22223
20251
  setEmbedConfig(opts.embedConfig);
@@ -22277,6 +20305,7 @@ async function resolveRunTaskImageOverride(args) {
22277
20305
  return { pinnedUncovered: pinned && uncovered.length > 0 };
22278
20306
  }
22279
20307
  function addRunTaskSpecificOptions(cmd) {
20308
+ addAwsEndpointOptions(cmd);
22280
20309
  cmd.addOption(ecsClusterOption()).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"ContainerName\":{\"KEY\":\"VALUE\"}, \"Parameters\":{}})")).addOption(new Option("--container-host <ip>", "Host IP to bind published container ports to. Must be a numeric IP (Docker rejects hostnames here)").default("127.0.0.1")).addOption(new Option("--host-port <containerPort=hostPort...>", "Publish a container port on a specific host port (e.g. 80=8080); repeatable. Default: host port == container port. Use this on macOS to map a privileged container port (< 1024) to a non-privileged host port and avoid the Docker Desktop admin-password prompt."));
22281
20310
  addEcsAssumeRoleOptions(cmd);
22282
20311
  cmd.addOption(new Option("--no-pull", "Skip docker pull for every container image and the metadata sidecar")).addOption(new Option("--no-build", "Skip docker build on every CDK-asset container (use the previously-built tag). Requires the deterministic tag to already be in the local registry; errors with an actionable message when missing. No-op for ECR-pull / public-registry containers. Compatible with --no-pull.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries. Issues sts:AssumeRole via the default credential chain and uses the temporary credentials for ecr:GetAuthorizationToken + docker pull. Required when the caller does not have direct cross-account access to the target repository. Same-account / same-region pulls do not need this flag.")).addOption(new Option("--platform <platform>", "Force docker --platform (linux/amd64 or linux/arm64). Default: inferred from task RuntimePlatform.CpuArchitecture")).addOption(new Option("--keep-running", "Don't docker rm -f the user containers on task exit (network + sidecar are still torn down). Use when you want to docker exec into a stopped container for post-mortems.").default(false)).addOption(new Option("--detach", "Start the containers in the background and exit (skip log streaming + auto teardown). Useful in CI smoke tests; caller manages container lifecycle.").default(false)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", `Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in container env vars / secrets / image URIs with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (\`cdk deploy\`). Bare form uses the ${getEmbedConfig().binaryName} stack name; pass an explicit value when the CFn stack name differs. Fn::GetAtt in container Environment[].Value is warn-and-dropped: CFn ListStackResources does not return per-attribute values, and unlike Lambda (where \`cdkl invoke --from-cfn-stack\` recovers Fn::GetAtt from the deployed function via lambda:GetFunctionConfiguration), no ECS-side equivalent resolves attributes off a deployed task / service.`)).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region."));
@@ -26163,6 +24192,7 @@ async function localStartCloudFrontCommand(target, options, extraStateProviders,
26163
24192
  if (options.verbose) logger.setLevel("debug");
26164
24193
  const originOverrides = parseOriginOverrides(options.origin);
26165
24194
  const tlsRequested = options.tls === true || options.tlsCert !== void 0 || options.tlsKey !== void 0;
24195
+ await activateWorkloadAwsWiring(options);
26166
24196
  await applyRoleArnIfSet({
26167
24197
  roleArn: options.roleArn,
26168
24198
  region: options.region,
@@ -26331,6 +24361,7 @@ function createLocalStartCloudFrontCommand(opts = {}) {
26331
24361
  return cmd;
26332
24362
  }
26333
24363
  function addStartCloudFrontSpecificOptions(cmd) {
24364
+ addAwsEndpointOptions(cmd);
26334
24365
  return cmd.addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--origin <originId=dir>", "Point a distribution origin at a local directory (repeatable). Use when cdk-local cannot resolve the origin's BucketDeployment source automatically (content uploaded out of band, or a non-CDK bucket).").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--kvs-file <key=file.json>", "Back a CloudFront Function's KeyValueStore reads (cf.kvs().get()) with a local JSON map (repeatable). The key is a KeyValueStore handle — its AWS::CloudFront::KeyValueStore resource logical id, its construct path, or its bare construct id; the file is a flat { \"key\": \"value\" } object. The AWS-free alternative to --from-cfn-stack, which instead reads the deployed store via the GetKey API.").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--tls", "Terminate real TLS (HTTPS). Uses --tls-cert / --tls-key when supplied, else an auto-generated self-signed cert.").default(false)).addOption(new Option("--tls-cert <path>", "PEM server certificate for --tls (implies --tls).")).addOption(new Option("--tls-key <path>", "PEM server private key for --tls (implies --tls).")).addOption(new Option("--no-pull", "Skip 'docker pull' for a Lambda Function URL / Web Function origin's base image (use the locally cached image).")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Bind to a deployed CloudFormation stack (ListStackResources). Resolves an S3 origin that has no local BucketDeployment source to its deployed bucket and serves it from real S3 on demand (the front/back-split case: files uploaded out of band), and resolves a Lambda Function URL / Lambda@Edge function's or a Web Function origin revision's env vars to the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the resolved stack name; pass a value when the CFn stack name differs.")).addOption(new Option("--cache-origin", "For a deployed-S3 origin (served from real S3 under --from-cfn-stack): keep fetched objects in memory for the session instead of re-reading on every request. Faster repeat reads / fewer S3 GETs, but an out-of-band S3 content change is not reflected until a --watch reload (which clears the cache) or a restart. Off by default (every request re-reads, always current). Not CloudFront CDN caching.").default(false)).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).addOption(new Option("--assume-role [arn]", "Assume a Lambda Function URL origin's (or a Web Function origin revision's) execution role and forward STS-issued temp credentials into its container so the handler runs with the deployed permissions. Three forms: `--assume-role <arn>` (explicit ARN); `--assume-role` (bare, auto-resolves from state — requires --from-cfn-stack); `--no-assume-role` (opt out). Off by default (the dev shell credentials are forwarded).")).addOption(new Option("--env-vars <file>", "JSON env-var overrides for the Lambda Function URL and Lambda Web Function endpoint origins (SAM-compatible, the same file as the other commands: {\"Parameters\": {...}} for every origin, {\"<LogicalId or construct path>\": {\"KEY\": \"VALUE\"}} for one — the backing function, or the Web Function revision the endpoint serves; a null value removes the variable). Not applied to Lambda@Edge functions, which cannot carry environment variables in AWS.")).addOption(new Option("--watch", "Hot-reload: re-synth + re-resolve the distribution when the CDK app's source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). The server keeps the previous version serving when synth fails mid-reload.").default(false));
26335
24366
  }
26336
24367
 
@@ -26719,6 +24750,7 @@ async function localStartAgentCoreCommand(target, options, extraStateProviders,
26719
24750
  await profileCredsFile.dispose();
26720
24751
  } catch {}
26721
24752
  };
24753
+ await activateWorkloadAwsWiring(options);
26722
24754
  await applyRoleArnIfSet({
26723
24755
  roleArn: options.roleArn,
26724
24756
  region: options.region,
@@ -26966,6 +24998,7 @@ function createLocalStartAgentCoreCommand(opts = {}) {
26966
24998
  return cmd;
26967
24999
  }
26968
25000
  function addStartAgentCoreSpecificOptions(cmd) {
25001
+ addAwsEndpointOptions(cmd);
26969
25002
  return cmd.addOption(new Option("--port <n>", "Serve bind port the client connects to (HTTP contract + /ws on the same port). Default 0 (OS-assigned).").default(0).argParser(parsePort$2)).addOption(new Option("--host <ip>", "Serve bind host. Default 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--session-id <id>", "Pin one AgentCore runtime session id header value for every forwarded request / /ws connection (default: a fresh random UUID each, so each is its own session).")).addOption(new Option("--bearer-token <jwt>", "Bearer JWT to present when the runtime declares a customJwtAuthorizer. Verified against the runtime's OIDC discovery URL before the container starts, then injected as Authorization: Bearer <jwt> on every forwarded request and the container /ws upgrade.")).addOption(new Option("--no-verify-auth", "Skip inbound JWT verification even when the runtime declares a customJwtAuthorizer (local-dev escape hatch). A --bearer-token, if given, is still forwarded.")).addOption(new Option("--sigv4", "Sign each forwarded request with AWS SigV4 (service bedrock-agentcore) when the runtime declares NO customJwtAuthorizer, so the warm container sees the same Authorization / X-Amz-* headers the cloud receives. Mutually exclusive with --bearer-token; ignored (with a warning) when a customJwtAuthorizer is declared.")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--platform <platform>", "docker --platform for the agent container (linux/amd64 or linux/arm64). Defaults to linux/arm64 because the cloud AgentCore Runtime requires arm64.").choices(["linux/amd64", "linux/arm64"]).default("linux/arm64")).addOption(new Option("--watch", "Re-synth + reload the warm container in place on a CDK source change, keeping the serve up. A per-firing classifier picks rebuild (boot a fresh container, re-point the serve) vs soft-reload (docker cp + docker restart the same container) — the same pattern as start-service / invoke-agentcore --ws --watch.")).addOption(new Option("--no-pull", "Skip docker pull (use cached image) — no-op for the local-build path")).addOption(new Option("--no-build", "Skip docker build on the local-asset path (use the previously-built tag). No-op for the ECR / registry pull paths.")).addOption(new Option("--container-host <host>", "Host IP used to bind the agent container port. Must be a numeric IP. Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--timeout <ms>", "Maximum time in milliseconds to wait for the container to become ready (the GET /ping readiness deadline). Default 120000.").default(12e4).argParser(parseTimeoutMs)).addOption(new Option("--assume-role [arn]", "Assume the runtime's execution role and forward STS-issued temp credentials to the container. (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) uses the runtime's literal RoleArn; (3) `--no-assume-role` opts out. Off by default.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries.")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack and substitute Ref / Fn::ImportValue in env vars / image URIs with the deployed physical IDs / exports. Bare form uses the resolved stack name.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region."));
26970
25003
  }
26971
25004
 
@@ -26980,6 +25013,7 @@ async function localStartWebFunctionCommand(target, options, extraStateProviders
26980
25013
  const logger = getLogger();
26981
25014
  if (options.verbose) logger.setLevel("debug");
26982
25015
  const forever = () => new Promise(() => void 0);
25016
+ await activateWorkloadAwsWiring(options);
26983
25017
  await applyRoleArnIfSet({
26984
25018
  roleArn: options.roleArn,
26985
25019
  region: options.region,
@@ -27078,6 +25112,7 @@ function createLocalStartWebFunctionCommand(opts = {}) {
27078
25112
  return cmd;
27079
25113
  }
27080
25114
  function addStartWebFunctionSpecificOptions(cmd) {
25115
+ addAwsEndpointOptions(cmd);
27081
25116
  return cmd.addOption(new Option("--revision <logicalId>", "Serve this WebFunctionRevision (logical ID) instead of the one the endpoint weights pick.")).addOption(new Option("--port <n>", "Local port to serve on. Default 0 (OS-assigned).").default(0).argParser(parsePort$1)).addOption(new Option("--host <ip>", "Address to publish the port on.").default("127.0.0.1")).addOption(new Option("--platform <platform>", "docker --platform for the server container. Defaults to the runtime's cloud architecture (linux/arm64 for nodejs24.x).").choices(["linux/amd64", "linux/arm64"])).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"RevisionLogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--no-pull", "Skip docker pull of the runtime base image (use the cached image)")).addOption(new Option("--timeout <ms>", "Maximum time in milliseconds to wait for the server to answer HTTP. Default 60000.").default(6e4).argParser(parseTimeoutMs)).addOption(new Option("--assume-role [arn]", "Assume the revision's execution role and forward STS-issued temp credentials to the container. (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) uses the revision's ServiceConfig.ExecutionRoleArn: a literal ARN as written, or the Fn::GetAtt / Ref CDK synthesizes resolved against --from-cfn-stack deployed state; (3) `--no-assume-role` opts out. Off by default.")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack and substitute Ref / Fn::ImportValue in env vars with the deployed physical IDs / exports. Bare form uses the resolved stack name.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region."));
27082
25117
  }
27083
25118
 
@@ -28088,6 +26123,7 @@ async function localStartMicrovmCommand(target, options, extraStateProviders, ho
28088
26123
  disposeMicrovmCodeArtifact(artifact);
28089
26124
  };
28090
26125
  const teardown = () => teardownPromise ??= doTeardown();
26126
+ await activateWorkloadAwsWiring(options);
28091
26127
  await applyRoleArnIfSet({
28092
26128
  roleArn: options.roleArn,
28093
26129
  region: options.region,
@@ -28267,6 +26303,7 @@ function createLocalStartMicrovmCommand(opts = {}) {
28267
26303
  return cmd;
28268
26304
  }
28269
26305
  function addStartMicrovmSpecificOptions(cmd) {
26306
+ addAwsEndpointOptions(cmd);
28270
26307
  return cmd.addOption(new Option("--count <n>", "Number of independent MicroVMs to run, each with its own URL.").default(1).argParser(parseCount)).addOption(new Option("--run-hook-payload <string>", "The runHookPayload string delivered to each MicroVM's /run hook (max 16 KB).")).addOption(new Option("--run-hook-payload-file <path>", "Read the runHookPayload from a file (mutually exclusive with --run-hook-payload).")).addOption(new Option("--port <n>", "Local port of the first MicroVM; MicroVM i listens on <n>+i. Default 0 (OS-assigned).").default(0).argParser(parsePort)).addOption(new Option("--host <ip>", "Address the MicroVM URLs listen on.").default("127.0.0.1")).addOption(new Option("--platform <platform>", "docker --platform for the build and the containers. Defaults to the image's CpuConfigurations architecture.").choices(["linux/amd64", "linux/arm64"])).addOption(new Option("--proxy-port <port>", "An extra container port X-aws-proxy-port may route to (repeatable). 8080, Hooks.Port and the image's EXPOSE ports are always routable.").argParser(parseProxyPort)).addOption(new Option("--auto-resume", "Resume a suspended MicroVM on its next request instead of answering 503 (autoResumeEnabled).")).addOption(new Option("--no-build-cache", "Build the image with docker build --no-cache.")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"MicrovmImageLogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--timeout <ms>", "Default deadline in milliseconds for each hook without its own <Hook>TimeoutInSeconds (/terminate defaults to 10000), and for the app to answer HTTP when there is no /ready hook. Default 60000.").default(6e4).argParser(parseTimeoutMs)).addOption(new Option("--assume-role <arn>", "Assume this role (the MicroVM's execution role, a run-microvm parameter rather than part of the template) and forward STS-issued temp credentials to the containers. Off by default: the shell credentials are forwarded.")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack and substitute Ref / Fn::ImportValue in env vars with the deployed physical IDs / exports. Bare form uses the resolved stack name.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region."));
28271
26308
  }
28272
26309
 
@@ -33599,5 +31636,5 @@ function addStudioSpecificOptions(cmd) {
33599
31636
  }
33600
31637
 
33601
31638
  //#endregion
33602
- export { postHook as $, deployedFillMayBeSecret as $a, parseConnectionsPath as $i, addImageOverrideOptions as $n, addStartApiSpecificOptions as $r, classifyS3Error as $t, microvmFidelityWarnings as A, discoverWebSocketApisOrThrow as Aa, applyCorsResponseHeaders as Ai, stripCloudFrontImport as An, A2A_CONTAINER_PORT as Ar, readContainerLogTail as At, MICROVM_WS_BASE_PROTOCOL as B, AGENTCORE_MCP_PROTOCOL as Ba, evaluateResponseParameters as Bi, createLocalStartAlbCommand as Bn, AGENTCORE_SESSION_ID_HEADER as Br, parseWebFunctionBuildConfig as Bt, addListSpecificOptions as C, resolveSsmParameters as Ca, verifyJwtViaDiscovery as Ci, WEB_FUNCTION_REVISION_TYPE as Cn, setShadowReadyTimeoutMs as Cr, parseKvsFileOverrides as Ct, buildMicrovmLambdaView as D, listTargets as Da, invokeRequestAuthorizer as Di, compileCloudFrontFunction as Dn, createLocalInvokeAgentCoreCommand as Dr, WEB_FUNCTION_CONTAINER_PORT as Dt, addStartMicrovmSpecificOptions as E, countTargets as Ea, evaluateCachedLambdaPolicy as Ei, resolveWebFunctionTarget as En, addInvokeAgentCoreSpecificOptions as Er, RecentOutput as Et, microvmImageTag as F, pickRefLogicalId as Fa, matchRoute as Fi, findFileAssetForObjectKey as Fn, MCP_PROTOCOL_VERSION as Fr, buildNodeEntryFileStart as Ft, startMicrovmFrontDoor as G, derivePseudoParametersFromRegion as Ga, HOST_DOCKER_INTERNAL_GATEWAY as Gi, addStartServiceSpecificOptions as Gn, SUPPORTED_CODE_RUNTIMES as Gr, readWebFunctionServiceConfig as Gt, PROXY_PORT_HEADER as H, AgentCoreResolutionError as Ha, selectIntegrationResponse as Hi, resolveAlbTarget as Hn, waitForAgentCoreHttpReady as Hr, WEB_FUNCTION_HTTP_ENDPOINT_ENV as Ht, planMicrovmPorts as I, resolveLambdaArnIntrinsic as Ia, translateLambdaResponse as Ii, isBucketDeploymentResource as In, mcpInvokeOnce as Ir, defaultWebFunctionPlatform as It, MICROVM_HOOK_PATH_PREFIX as J, tryResolveImageFnJoin as Ja, resolveHostGatewayExtraHosts as Ji, addRunTaskSpecificOptions as Jn, renderCodeDockerfile as Jr, idFromArn as Jt, stripMicrovmProxyHeaders as K, formatStateRemedy as Ka, HOST_GATEWAY_MIN_VERSION as Ki, createLocalStartServiceCommand as Kn, buildAgentCoreCodeImage as Kr, webFunctionAssumeRole as Kt, readExposedPorts as L, AGENTCORE_A2A_PROTOCOL as La, applyAuthorizerOverlay as Li, resolveBucketDeploymentObjectKey as Ln, parseSseForJsonRpc as Lr, resolveWebFunctionRuntime as Lt, DEFAULT_TERMINATE_HOOK_TIMEOUT_MS as M, parseSelectionExpressionPath as Ma, buildCorsConfigFromCloudFrontChain as Mi, createLocalFileKvsDataSource as Mn, a2aInvokeOnce as Mr, waitForWebFunctionReady as Mt, LocalMicrovm as N, webSocketApiMatchesIdentifier as Na, isFunctionUrlOacFronted as Ni, createUnboundCloudFrontModule as Nn, MCP_CONTAINER_PORT as Nr, watchContainerExit as Nt, createLocalStartMicrovmCommand as O, availableWebSocketApiIdentifiers as Oa, invokeTokenAuthorizer as Oi, runViewerRequest as On, bridgeAgentCoreWs as Or, containerFailure as Ot, buildMicrovmImage as P, discoverRoutes as Pa, matchPreflight as Pi, bucketDeploymentSourceObjectKeys as Pn, MCP_PATH as Pr, WEB_FUNCTION_RUNTIMES as Pt, pollBuildHook as Q, containsDynamicReference as Qa, handleConnectionsRequest as Qi, addEcsAssumeRoleOptions as Qn, createLocalInvokeCommand as Qr, resolveDeployedOriginBucket as Qt, setContainerPaused as R, AGENTCORE_AGUI_PROTOCOL as Ra, buildHttpApiV2Event as Ri, addAlbSpecificOptions as Rn, AGENTCORE_SIGV4_SERVICE as Rr, supportedWebFunctionRuntimes as Rt, StudioEventBus as S, collectSsmParameterRefs as Sa, verifyJwtAuthorizer as Si, WEB_FUNCTION_ENDPOINT_TYPE as Sn, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as Sr, normalizeKvsFileKeys as St, formatTargetListing as T, resolveSingleTarget as Ta, computeRequestIdentityHash as Ti, WebFunctionResolutionError as Tn, attachContainerLogStreamer as Tr, resolveCloudFrontTarget as Tt, rewriteUpgradeResponseHead as U, pickAgentCoreCandidateStack as Ua, tryParseStatus as Ui, isApplicationLoadBalancer as Un, waitForAgentCorePing as Ur, buildWebFunctionLambdaView as Ut, MicrovmStateError as V, AGENTCORE_RUNTIME_TYPE as Va, pickResponseTemplate as Vi, parseLbPortOverrides as Vn, invokeAgentCore as Vr, resolveWebFunctionArtifact as Vt, selectTargetPort as W, resolveAgentCoreTarget as Wa, VtlEvaluationError as Wi, resolveAlbFrontDoor as Wn, downloadAndExtractS3Bundle as Wr, finalizeWebFunctionEnv as Wt, callRuntimeHook as X, DynamicReferenceResolutionError as Xa, ConnectionRegistry as Xi, MAX_TASKS_SUBNET_RANGE_CAP as Xn, classifySourceChange as Xr, createDeployedKvsDataSource as Xt, MicrovmHookError as Y, LocalInvokeBuildError as Ya, bufferToBody as Yi, createLocalRunTaskCommand as Yn, toCmdArgv as Yr, resolveKvsModulesForDistribution as Yt, generateMicrovmId as Z, DynamicReferenceResolver as Za, buildMgmtEndpointEnvUrl as Zi, addCommonEcsServiceOptions as Zn, addInvokeSpecificOptions as Zr, resolveDeployedKvsArnByName as Zt, filterStudioTargetGroups as _, rejectExplicitCfnStackWithMultipleStacks as _a, defaultCredentialsLoader as _i, pickKvsLogicalIdFromArn as _n, isProxyEnvConfigured as _o, isLocalCdkAssetImage as _r, attachAgentCoreWsBridge as _t, createLocalStudioCommand as a, resolveRuntimeCodeMountPath as aa, attachStageContext as ai, serveLambdaUrlOrigin as an, withoutKeys as ao, resolveSharedSidecarCredentials as ar, disposeMicrovmCodeArtifact as at, renderStudioHtml as b, resolveCfnStackName as ba, createJwksCache as bi, pickWebFunctionEndpointLogicalIdFromOrigin as bn, CloudMapRegistry as br, addStartCloudFrontSpecificOptions as bt, startStudioProxy as c, EcsTaskResolutionError as ca, resolveEnvVars$1 as ci, buildEdgeRequestEvent as cn, deployAccountStsClientConfig as co, buildImageOverrideTag as cr, resolveMicrovmImageTarget as ct, createStudioDispatcher as d, substituteAgainstStateAsync as da, filterRoutesByApiIdentifiers as di, httpHeadersToEdge as dn, resetWorkloadIdentity as do, mergeForService as dr, createLocalStartWebFunctionCommand as dt, buildConnectEvent as ea, createLocalStartApiCommand as ei, createS3OriginReader as en, firstUsableRegion as eo, buildEcsImageResolutionContext$1 as er, runHookBody as et, filterStudioCustomResources as f, substituteEnvVarsFromState as fa, groupRoutesByServer as fi, CLOUDFRONT_DISTRIBUTION_TYPE as fn, workloadClientConfig as fo, parseImageOverrideFlags as fr, addStartAgentCoreSpecificOptions as ft, annotatePinnedEcsTargets as g, isCfnFlagPresent as ga, resolveServiceIntegrationParameters as gi, pickFunctionUrlLogicalIdFromOrigin as gn, buildProxyClientConfig as go, imageOverrideKeyAliases as gr, startAgentCoreHttpServer as gt, annotateEcsTaskPinnedTargets as h, createLocalStateProvider as ha, resolveSelectionExpression as hi, isCloudFrontDistribution as hn, resolveProfileCredentials as ho, describePinnedImageUri as hr, selectServeInboundAuth as ht, coerceStopRequest as i, buildContainerImage as ia, createFileWatcher as ii, serveFromStaticOrigin as in, resolveDynamicReferencesInEnv as io, resolveEcsAssumeRoleOption as ir, MicrovmResolutionError as it, readRunHookPayload as j, filterWebSocketApisByIdentifiers as ja, buildCorsConfigByApiId as ji, createCloudFrontModule as jn, A2A_PATH as jr, startWebFunctionContainer as jt, finalizeMicrovmEnv as k, discoverWebSocketApis as ka, attachAuthorizers as ki, runViewerResponse as kn, invokeAgentCoreWs as kr, planWebFunctionContainer as kt, relayServeRequest as l, assertEcsTaskImagesResolvable as la, availableApiIdentifiers as li, buildEdgeResponseEvent as ln, readEnvCallerCredentials as lo, canonicalizeImageOverrideKeys as lr, s3KeyOfUri as lt, annotateAlbPinnedBackingServices as m, LocalStateSourceError as ma, startApiServer as mi, extractKvsAssociations as mn, buildStsClientConfig as mo, runImageOverrideBuilds as mr, buildAgentCoreServeAuthCheck as mt, coerceRunRequest as n, buildMessageEvent as na, resolveApiTargetSubset as ni, startCloudFrontServer as nn, keysOverriddenBy as no, parseMaxTasks as nr, MICROVM_DEFAULT_INGRESS_PORT as nt, resolveServeBaseUrl as o, resolveRuntimeFileExtension as oa, buildStageMap as oi, applyEdgeRequestResult as on, SECOND_ASSUME_MESSAGE as oo, runEcsServiceEmulator as or, readMicrovmImageConfig as ot, isCustomResourceLambdaTarget as p, substituteEnvVarsFromStateAsync as pa, readMtlsMaterialsFromDisk as pi, describeS3OriginDomain as pn, workloadStsClientConfig as po, resolveImageOverrides as pr, createLocalStartAgentCoreCommand as pt, MAX_RUN_HOOK_PAYLOAD_BYTES as q, substituteImagePlaceholders as qa, probeHostGatewaySupport as qi, serviceStrategy as qn, computeCodeImageTag as qr, webFunctionFidelityWarnings as qt, coerceServeRequest as r, architectureToPlatform as ra, createAuthorizerCache as ri, resolveErrorResponseCandidates as rn, parseDynamicReference as ro, parseRestartPolicy as rr, MICROVM_IMAGE_TYPE as rt, createStudioServeManager as s, resolveRuntimeImage as sa, materializeLayerFromArn as si, applyEdgeResponseResult as sn, assumedRoleRecorded as so, ImageOverrideError as sr, resolveMicrovmCodeArtifact as st, addStudioSpecificOptions as t, buildDisconnectEvent as ta, createWatchPredicates as ti, matchBehavior as tn, keysNotFromTemplate as to, ecsClusterOption as tr, waitForAppAnswer as tt, reinvoke as u, substituteAgainstState as ua, filterRoutesByApiIdentifier as ui, edgeHeadersToHttp as un, recordAssumedRole as uo, enforceImageOverrideOrphans as ur, addStartWebFunctionSpecificOptions as ut, startStudioServer as v, resolveCfnFallbackRegion as va, buildCognitoJwksUrl as vi, pickLambdaEdgeFunctionLogicalId as vn, listPinnedTargets as vr, startAgentCoreWsBridge as vt, createLocalListCommand as w, resolveWatchConfig as wa, buildMethodArn as wi, WEB_FUNCTION_TYPE as wn, getContainerNetworkIp as wr, parseOriginOverrides as wt, createStudioStore as x, CfnLocalStateProvider as xa, verifyCognitoJwt as xi, resolveCloudFrontDistribution as xn, DEFAULT_SHADOW_READY_TIMEOUT_MS as xr, createLocalStartCloudFrontCommand as xt, toStudioTargetGroups as y, resolveCfnRegion as ya, buildJwksUrlFromIssuer as yi, pickTargetFunctionLogicalId as yn, buildCloudMapIndex as yr, LocalStartCloudFrontError as yt, MICROVM_CONTROL_PATH as z, AGENTCORE_HTTP_PROTOCOL as za, buildRestV1Event as zi, albStrategy as zn, signAgentCoreInvocation as zr, disposeWebFunctionArtifact as zt };
33603
- //# sourceMappingURL=local-studio-Ur6enHho.js.map
31639
+ export { postHook as $, addAwsEndpointOptions as $a, parseConnectionsPath as $i, addImageOverrideOptions as $n, addStartApiSpecificOptions as $r, classifyS3Error as $t, microvmFidelityWarnings as A, parseSelectionExpressionPath as Aa, applyCorsResponseHeaders as Ai, stripCloudFrontImport as An, A2A_CONTAINER_PORT as Ar, readContainerLogTail as At, MICROVM_WS_BASE_PROTOCOL as B, AgentCoreResolutionError as Ba, evaluateResponseParameters as Bi, createLocalStartAlbCommand as Bn, AGENTCORE_SESSION_ID_HEADER as Br, parseWebFunctionBuildConfig as Bt, addListSpecificOptions as C, resolveSingleTarget as Ca, verifyJwtViaDiscovery as Ci, WEB_FUNCTION_REVISION_TYPE as Cn, setShadowReadyTimeoutMs as Cr, parseKvsFileOverrides as Ct, buildMicrovmLambdaView as D, discoverWebSocketApis as Da, invokeRequestAuthorizer as Di, compileCloudFrontFunction as Dn, createLocalInvokeAgentCoreCommand as Dr, WEB_FUNCTION_CONTAINER_PORT as Dt, addStartMicrovmSpecificOptions as E, availableWebSocketApiIdentifiers as Ea, evaluateCachedLambdaPolicy as Ei, resolveWebFunctionTarget as En, addInvokeAgentCoreSpecificOptions as Er, RecentOutput as Et, microvmImageTag as F, AGENTCORE_A2A_PROTOCOL as Fa, matchRoute as Fi, findFileAssetForObjectKey as Fn, MCP_PROTOCOL_VERSION as Fr, buildNodeEntryFileStart as Ft, startMicrovmFrontDoor as G, containsDynamicReference as Ga, HOST_DOCKER_INTERNAL_GATEWAY as Gi, addStartServiceSpecificOptions as Gn, SUPPORTED_CODE_RUNTIMES as Gr, readWebFunctionServiceConfig as Gt, PROXY_PORT_HEADER as H, resolveAgentCoreTarget as Ha, selectIntegrationResponse as Hi, resolveAlbTarget as Hn, waitForAgentCoreHttpReady as Hr, WEB_FUNCTION_HTTP_ENDPOINT_ENV as Ht, planMicrovmPorts as I, AGENTCORE_AGUI_PROTOCOL as Ia, translateLambdaResponse as Ii, isBucketDeploymentResource as In, mcpInvokeOnce as Ir, defaultWebFunctionPlatform as It, MICROVM_HOOK_PATH_PREFIX as J, keysNotFromTemplate as Ja, resolveHostGatewayExtraHosts as Ji, addRunTaskSpecificOptions as Jn, renderCodeDockerfile as Jr, idFromArn as Jt, stripMicrovmProxyHeaders as K, deployedFillMayBeSecret as Ka, HOST_GATEWAY_MIN_VERSION as Ki, createLocalStartServiceCommand as Kn, buildAgentCoreCodeImage as Kr, webFunctionAssumeRole as Kt, readExposedPorts as L, AGENTCORE_HTTP_PROTOCOL as La, applyAuthorizerOverlay as Li, resolveBucketDeploymentObjectKey as Ln, parseSseForJsonRpc as Lr, resolveWebFunctionRuntime as Lt, DEFAULT_TERMINATE_HOOK_TIMEOUT_MS as M, discoverRoutes as Ma, buildCorsConfigFromCloudFrontChain as Mi, createLocalFileKvsDataSource as Mn, a2aInvokeOnce as Mr, waitForWebFunctionReady as Mt, LocalMicrovm as N, pickRefLogicalId as Na, isFunctionUrlOacFronted as Ni, createUnboundCloudFrontModule as Nn, MCP_CONTAINER_PORT as Nr, watchContainerExit as Nt, createLocalStartMicrovmCommand as O, discoverWebSocketApisOrThrow as Oa, invokeTokenAuthorizer as Oi, runViewerRequest as On, bridgeAgentCoreWs as Or, containerFailure as Ot, buildMicrovmImage as P, resolveLambdaArnIntrinsic as Pa, matchPreflight as Pi, bucketDeploymentSourceObjectKeys as Pn, MCP_PATH as Pr, WEB_FUNCTION_RUNTIMES as Pt, pollBuildHook as Q, withoutKeys as Qa, handleConnectionsRequest as Qi, addEcsAssumeRoleOptions as Qn, createLocalInvokeCommand as Qr, resolveDeployedOriginBucket as Qt, setContainerPaused as R, AGENTCORE_MCP_PROTOCOL as Ra, buildHttpApiV2Event as Ri, addAlbSpecificOptions as Rn, AGENTCORE_SIGV4_SERVICE as Rr, supportedWebFunctionRuntimes as Rt, StudioEventBus as S, resolveWatchConfig as Sa, verifyJwtAuthorizer as Si, WEB_FUNCTION_ENDPOINT_TYPE as Sn, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as Sr, normalizeKvsFileKeys as St, formatTargetListing as T, listTargets as Ta, computeRequestIdentityHash as Ti, WebFunctionResolutionError as Tn, attachContainerLogStreamer as Tr, resolveCloudFrontTarget as Tt, rewriteUpgradeResponseHead as U, DynamicReferenceResolutionError as Ua, tryParseStatus as Ui, isApplicationLoadBalancer as Un, waitForAgentCorePing as Ur, buildWebFunctionLambdaView as Ut, MicrovmStateError as V, pickAgentCoreCandidateStack as Va, pickResponseTemplate as Vi, parseLbPortOverrides as Vn, invokeAgentCore as Vr, resolveWebFunctionArtifact as Vt, selectTargetPort as W, DynamicReferenceResolver as Wa, VtlEvaluationError as Wi, resolveAlbFrontDoor as Wn, downloadAndExtractS3Bundle as Wr, finalizeWebFunctionEnv as Wt, callRuntimeHook as X, parseDynamicReference as Xa, ConnectionRegistry as Xi, MAX_TASKS_SUBNET_RANGE_CAP as Xn, classifySourceChange as Xr, createDeployedKvsDataSource as Xt, MicrovmHookError as Y, keysOverriddenBy as Ya, bufferToBody as Yi, createLocalRunTaskCommand as Yn, toCmdArgv as Yr, resolveKvsModulesForDistribution as Yt, generateMicrovmId as Z, resolveDynamicReferencesInEnv as Za, buildMgmtEndpointEnvUrl as Zi, addCommonEcsServiceOptions as Zn, addInvokeSpecificOptions as Zr, resolveDeployedKvsArnByName as Zt, filterStudioTargetGroups as _, resolveCfnRegion as _a, defaultCredentialsLoader as _i, pickKvsLogicalIdFromArn as _n, isLocalCdkAssetImage as _r, attachAgentCoreWsBridge as _t, createLocalStudioCommand as a, resolveRuntimeImage as aa, attachStageContext as ai, serveLambdaUrlOrigin as an, resolveSharedSidecarCredentials as ar, disposeMicrovmCodeArtifact as at, renderStudioHtml as b, collectSsmParameterRefs as ba, createJwksCache as bi, pickWebFunctionEndpointLogicalIdFromOrigin as bn, CloudMapRegistry as br, addStartCloudFrontSpecificOptions as bt, startStudioProxy as c, substituteAgainstState as ca, resolveEnvVars$1 as ci, buildEdgeRequestEvent as cn, buildImageOverrideTag as cr, resolveMicrovmImageTarget as ct, createStudioDispatcher as d, substituteEnvVarsFromStateAsync as da, filterRoutesByApiIdentifiers as di, httpHeadersToEdge as dn, mergeForService as dr, createLocalStartWebFunctionCommand as dt, buildConnectEvent as ea, createLocalStartApiCommand as ei, createS3OriginReader as en, awsEndpointOptions as eo, buildEcsImageResolutionContext$1 as er, runHookBody as et, filterStudioCustomResources as f, LocalStateSourceError as fa, groupRoutesByServer as fi, CLOUDFRONT_DISTRIBUTION_TYPE as fn, parseImageOverrideFlags as fr, addStartAgentCoreSpecificOptions as ft, annotatePinnedEcsTargets as g, resolveCfnFallbackRegion as ga, resolveServiceIntegrationParameters as gi, pickFunctionUrlLogicalIdFromOrigin as gn, imageOverrideKeyAliases as gr, startAgentCoreHttpServer as gt, annotateEcsTaskPinnedTargets as h, rejectExplicitCfnStackWithMultipleStacks as ha, resolveSelectionExpression as hi, isCloudFrontDistribution as hn, describePinnedImageUri as hr, selectServeInboundAuth as ht, coerceStopRequest as i, resolveRuntimeFileExtension as ia, createFileWatcher as ii, serveFromStaticOrigin as in, resolveEcsAssumeRoleOption as ir, MicrovmResolutionError as it, readRunHookPayload as j, webSocketApiMatchesIdentifier as ja, buildCorsConfigByApiId as ji, createCloudFrontModule as jn, A2A_PATH as jr, startWebFunctionContainer as jt, finalizeMicrovmEnv as k, filterWebSocketApisByIdentifiers as ka, attachAuthorizers as ki, runViewerResponse as kn, invokeAgentCoreWs as kr, planWebFunctionContainer as kt, relayServeRequest as l, substituteAgainstStateAsync as la, availableApiIdentifiers as li, buildEdgeResponseEvent as ln, canonicalizeImageOverrideKeys as lr, s3KeyOfUri as lt, annotateAlbPinnedBackingServices as m, isCfnFlagPresent as ma, startApiServer as mi, extractKvsAssociations as mn, runImageOverrideBuilds as mr, buildAgentCoreServeAuthCheck as mt, coerceRunRequest as n, buildMessageEvent as na, resolveApiTargetSubset as ni, startCloudFrontServer as nn, parseMaxTasks as nr, MICROVM_DEFAULT_INGRESS_PORT as nt, resolveServeBaseUrl as o, EcsTaskResolutionError as oa, buildStageMap as oi, applyEdgeRequestResult as on, runEcsServiceEmulator as or, readMicrovmImageConfig as ot, isCustomResourceLambdaTarget as p, createLocalStateProvider as pa, readMtlsMaterialsFromDisk as pi, describeS3OriginDomain as pn, resolveImageOverrides as pr, createLocalStartAgentCoreCommand as pt, MAX_RUN_HOOK_PAYLOAD_BYTES as q, firstUsableRegion as qa, probeHostGatewaySupport as qi, serviceStrategy as qn, computeCodeImageTag as qr, webFunctionFidelityWarnings as qt, coerceServeRequest as r, resolveRuntimeCodeMountPath as ra, createAuthorizerCache as ri, resolveErrorResponseCandidates as rn, parseRestartPolicy as rr, MICROVM_IMAGE_TYPE as rt, createStudioServeManager as s, assertEcsTaskImagesResolvable as sa, materializeLayerFromArn as si, applyEdgeResponseResult as sn, ImageOverrideError as sr, resolveMicrovmCodeArtifact as st, addStudioSpecificOptions as t, buildDisconnectEvent as ta, createWatchPredicates as ti, matchBehavior as tn, ecsClusterOption as tr, waitForAppAnswer as tt, reinvoke as u, substituteEnvVarsFromState as ua, filterRoutesByApiIdentifier as ui, edgeHeadersToHttp as un, enforceImageOverrideOrphans as ur, addStartWebFunctionSpecificOptions as ut, startStudioServer as v, resolveCfnStackName as va, buildCognitoJwksUrl as vi, pickLambdaEdgeFunctionLogicalId as vn, listPinnedTargets as vr, startAgentCoreWsBridge as vt, createLocalListCommand as w, countTargets as wa, buildMethodArn as wi, WEB_FUNCTION_TYPE as wn, getContainerNetworkIp as wr, parseOriginOverrides as wt, createStudioStore as x, resolveSsmParameters as xa, verifyCognitoJwt as xi, resolveCloudFrontDistribution as xn, DEFAULT_SHADOW_READY_TIMEOUT_MS as xr, createLocalStartCloudFrontCommand as xt, toStudioTargetGroups as y, CfnLocalStateProvider as ya, buildJwksUrlFromIssuer as yi, pickTargetFunctionLogicalId as yn, buildCloudMapIndex as yr, LocalStartCloudFrontError as yt, MICROVM_CONTROL_PATH as z, AGENTCORE_RUNTIME_TYPE as za, buildRestV1Event as zi, albStrategy as zn, signAgentCoreInvocation as zr, disposeWebFunctionArtifact as zt };
31640
+ //# sourceMappingURL=local-studio-DNWiPLme.js.map