cdk-local 0.160.0 → 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.
- package/README.md +5 -1
- package/dist/assembly-path-R96uhMm1.js +208 -0
- package/dist/assembly-path-R96uhMm1.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{docker-cmd-CoZdbeos.js → docker-cmd-Cjg3jGYF.js} +5 -223
- package/dist/docker-cmd-Cjg3jGYF.js.map +1 -0
- package/dist/docker-runner-CnXQIUjd.js +1810 -0
- package/dist/docker-runner-CnXQIUjd.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +141 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +5 -3
- package/dist/{local-studio-D1XHJoJZ.js → local-studio-DNWiPLme.js} +506 -2229
- package/dist/local-studio-DNWiPLme.js.map +1 -0
- package/dist/{local-studio-DgWD3_iK.d.ts → local-studio-DYKegdhd.d.ts} +18 -2
- package/dist/local-studio-DYKegdhd.d.ts.map +1 -0
- package/dist/rolldown-runtime-w6R9maHv.js +18 -0
- package/dist/workload-aws-wiring-BIxf0jtl.js +916 -0
- package/dist/workload-aws-wiring-BIxf0jtl.js.map +1 -0
- package/package.json +1 -1
- package/dist/docker-cmd-CoZdbeos.js.map +0 -1
- package/dist/local-studio-D1XHJoJZ.js.map +0 -1
- package/dist/local-studio-DgWD3_iK.d.ts.map +0 -1
|
@@ -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";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
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";
|
|
6
|
+
import { chmodSync, cpSync, createWriteStream, existsSync, lstatSync, mkdirSync, mkdtempSync, promises, readFileSync, readdirSync, readlinkSync, realpathSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { Command, InvalidArgumentError, Option } from "commander";
|
|
8
|
-
import {
|
|
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 {
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
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
|
|
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/
|
|
1273
|
-
function
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
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
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
|
|
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 {
|
|
@@ -5635,1136 +4622,140 @@ async function applyCrossStackResolverToTask(task, context) {
|
|
|
5635
4622
|
if (Array.isArray(c["Secrets"])) for (const entry of c["Secrets"]) {
|
|
5636
4623
|
if (!entry || typeof entry !== "object") continue;
|
|
5637
4624
|
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
|
-
}
|
|
6549
|
-
return;
|
|
6550
|
-
}
|
|
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)}`
|
|
6560
|
-
});
|
|
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
|
-
}
|
|
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 } : {});
|
|
6579
|
-
}
|
|
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);
|
|
6613
|
-
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);
|
|
6642
|
-
}
|
|
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 = "";
|
|
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
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
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
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
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
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
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
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
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
|
|
6760
|
-
|
|
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
|
|
6763
|
-
|
|
6764
|
-
if (
|
|
6765
|
-
|
|
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
|
|
@@ -6850,6 +4841,10 @@ function extractHashFromImageUri(imageUri) {
|
|
|
6850
4841
|
//#endregion
|
|
6851
4842
|
//#region src/local/rie-client.ts
|
|
6852
4843
|
const INVOKE_PATH = "/2015-03-31/functions/function/invocations";
|
|
4844
|
+
const NOT_AN_RIE_STATUS = /* @__PURE__ */ new Set([404, 405]);
|
|
4845
|
+
function notAnRieError(url, status) {
|
|
4846
|
+
return /* @__PURE__ */ new Error(`The container answered the invoke at ${url} with HTTP ${status}, which the Lambda Runtime Interface Emulator never sends for that path: something else is listening on the container's port 8080 (the function's own server?). Check the container logs.`);
|
|
4847
|
+
}
|
|
6853
4848
|
async function waitForRieReady(host, port, timeoutMs = 5e3) {
|
|
6854
4849
|
const deadline = Date.now() + timeoutMs;
|
|
6855
4850
|
let lastError;
|
|
@@ -6910,6 +4905,7 @@ async function invokeRie(host, port, event, timeoutMs) {
|
|
|
6910
4905
|
clearTimeout(timer);
|
|
6911
4906
|
}
|
|
6912
4907
|
const raw = await response.text();
|
|
4908
|
+
if (NOT_AN_RIE_STATUS.has(response.status)) throw notAnRieError(url, response.status);
|
|
6913
4909
|
let payload = raw;
|
|
6914
4910
|
try {
|
|
6915
4911
|
payload = JSON.parse(raw);
|
|
@@ -6965,6 +4961,11 @@ async function invokeRieStreaming(host, port, event, timeoutMs) {
|
|
|
6965
4961
|
if (err.name === "AbortError") throw new Error(`RIE streaming invoke at ${url} timed out after ${timeoutMs}ms. The handler may be hung; check container logs.`);
|
|
6966
4962
|
throw err;
|
|
6967
4963
|
}
|
|
4964
|
+
if (NOT_AN_RIE_STATUS.has(response.status)) {
|
|
4965
|
+
clearTimeout(timer);
|
|
4966
|
+
await response.body?.cancel().catch(() => void 0);
|
|
4967
|
+
throw notAnRieError(url, response.status);
|
|
4968
|
+
}
|
|
6968
4969
|
if (!response.body) {
|
|
6969
4970
|
clearTimeout(timer);
|
|
6970
4971
|
throw new Error(`RIE streaming invoke at ${url} returned no response body.`);
|
|
@@ -8856,11 +6857,11 @@ function createContainerPool(specs, options) {
|
|
|
8856
6857
|
} else containerId = await runDetached({
|
|
8857
6858
|
image: spec.image,
|
|
8858
6859
|
mounts: [],
|
|
8859
|
-
...spec.
|
|
6860
|
+
extraMounts: [...spec.rieMount ? [spec.rieMount] : [], ...spec.profileCredentialsFile ? [{
|
|
8860
6861
|
hostPath: spec.profileCredentialsFile.hostPath,
|
|
8861
6862
|
containerPath: spec.profileCredentialsFile.containerPath,
|
|
8862
6863
|
readOnly: true
|
|
8863
|
-
}]
|
|
6864
|
+
}] : []],
|
|
8864
6865
|
env: spec.env,
|
|
8865
6866
|
...spec.sensitiveEnvKeys !== void 0 && { sensitiveEnvKeys: spec.sensitiveEnvKeys },
|
|
8866
6867
|
cmd: spec.command,
|
|
@@ -9077,6 +7078,209 @@ function clampConcurrency(input) {
|
|
|
9077
7078
|
return Math.min(MAX_PER_LAMBDA_CONCURRENCY, Math.max(MIN_PER_LAMBDA_CONCURRENCY, Math.trunc(input)));
|
|
9078
7079
|
}
|
|
9079
7080
|
|
|
7081
|
+
//#endregion
|
|
7082
|
+
//#region src/utils/cache-home.ts
|
|
7083
|
+
function userCacheHome(env = process.env, home = homedir) {
|
|
7084
|
+
const product = getEmbedConfig().productName.replace(/[^A-Za-z0-9._-]/g, "-").replace(/^\.*$/, "-");
|
|
7085
|
+
const xdg = env["XDG_CACHE_HOME"];
|
|
7086
|
+
if (xdg !== void 0 && isAbsolute(xdg)) return join(xdg, product);
|
|
7087
|
+
let dir;
|
|
7088
|
+
try {
|
|
7089
|
+
dir = home();
|
|
7090
|
+
} catch {
|
|
7091
|
+
return;
|
|
7092
|
+
}
|
|
7093
|
+
return isAbsolute(dir) ? join(dir, ".cache", product) : void 0;
|
|
7094
|
+
}
|
|
7095
|
+
|
|
7096
|
+
//#endregion
|
|
7097
|
+
//#region src/local/rie-mount.ts
|
|
7098
|
+
const RIE_CONTAINER_PATH = "/var/rapid/aws-lambda-rie";
|
|
7099
|
+
const RIE_SOURCE_IMAGE = "public.ecr.aws/lambda/provided:al2023";
|
|
7100
|
+
const RIE_SOURCE_PATH = "/usr/local/bin/aws-lambda-rie";
|
|
7101
|
+
const RIE_BASENAME = "aws-lambda-rie";
|
|
7102
|
+
const ELF_MACHINE_BY_PLATFORM = {
|
|
7103
|
+
"linux/amd64": 62,
|
|
7104
|
+
"linux/arm64": 183
|
|
7105
|
+
};
|
|
7106
|
+
function rieCacheDirectory(env = process.env) {
|
|
7107
|
+
const root = userCacheHome(env);
|
|
7108
|
+
return root === void 0 ? void 0 : join(root, "lambda-rie");
|
|
7109
|
+
}
|
|
7110
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
7111
|
+
const warnedNoBinary = /* @__PURE__ */ new Set();
|
|
7112
|
+
async function resolveRieWrap(input) {
|
|
7113
|
+
const logger = getLogger().child("rie");
|
|
7114
|
+
let program;
|
|
7115
|
+
try {
|
|
7116
|
+
const own = nonEmpty(input.entryPoint) && nonEmpty(input.command) ? {
|
|
7117
|
+
entrypoint: [],
|
|
7118
|
+
cmd: []
|
|
7119
|
+
} : await inspectImageEntrypointCmd(input.image);
|
|
7120
|
+
const entryPoint = nonEmpty(input.entryPoint) ? [...input.entryPoint] : own.entrypoint;
|
|
7121
|
+
const cmd = nonEmpty(input.command) ? [...input.command] : own.cmd;
|
|
7122
|
+
program = [...entryPoint, ...cmd];
|
|
7123
|
+
} catch (err) {
|
|
7124
|
+
logger.warn(`Could not read the ENTRYPOINT / CMD of image ${displayUntrustedValue(input.image)} (${messageOf(err)}), so no Lambda Runtime Interface Emulator is mounted into it; it runs as built.`);
|
|
7125
|
+
return;
|
|
7126
|
+
}
|
|
7127
|
+
const ownRie = program.find(isRieExecutable);
|
|
7128
|
+
if (ownRie !== void 0) {
|
|
7129
|
+
logger.debug(`Image ${displayUntrustedValue(input.image)} already runs ${displayUntrustedValue(ownRie)}; not mounting another RIE`);
|
|
7130
|
+
return;
|
|
7131
|
+
}
|
|
7132
|
+
let hostPath;
|
|
7133
|
+
try {
|
|
7134
|
+
hostPath = await ensureRieBinary(input.platform, input.skipPull === true);
|
|
7135
|
+
} catch (err) {
|
|
7136
|
+
if (!warnedNoBinary.has(input.platform)) {
|
|
7137
|
+
warnedNoBinary.add(input.platform);
|
|
7138
|
+
logger.warn(`Could not mount the Lambda Runtime Interface Emulator into ${displayUntrustedValue(input.platform)} container-image functions (${messageOf(err)}). They run as built, so only images that ship their own emulator (the AWS Lambda base images do) can be invoked.`);
|
|
7139
|
+
} else logger.debug(`RIE mount skipped for ${displayUntrustedValue(input.image)}: ${messageOf(err)}`);
|
|
7140
|
+
return;
|
|
7141
|
+
}
|
|
7142
|
+
return {
|
|
7143
|
+
mount: {
|
|
7144
|
+
hostPath,
|
|
7145
|
+
containerPath: RIE_CONTAINER_PATH,
|
|
7146
|
+
readOnly: true
|
|
7147
|
+
},
|
|
7148
|
+
entryPoint: [RIE_CONTAINER_PATH],
|
|
7149
|
+
cmd: program
|
|
7150
|
+
};
|
|
7151
|
+
}
|
|
7152
|
+
function isRieExecutable(path) {
|
|
7153
|
+
return basename(path).startsWith(RIE_BASENAME);
|
|
7154
|
+
}
|
|
7155
|
+
function messageOf(err) {
|
|
7156
|
+
return displayToolOutput(err instanceof Error ? err.message : String(err));
|
|
7157
|
+
}
|
|
7158
|
+
function nonEmpty(v) {
|
|
7159
|
+
return v !== void 0 && v.length > 0;
|
|
7160
|
+
}
|
|
7161
|
+
async function inspectImageEntrypointCmd(image) {
|
|
7162
|
+
let stdout;
|
|
7163
|
+
try {
|
|
7164
|
+
({stdout} = await runDockerStreaming([
|
|
7165
|
+
"image",
|
|
7166
|
+
"inspect",
|
|
7167
|
+
"--format",
|
|
7168
|
+
"{{json .Config}}",
|
|
7169
|
+
image
|
|
7170
|
+
], { streamLive: false }));
|
|
7171
|
+
} catch (err) {
|
|
7172
|
+
throw new Error(`docker image inspect failed: ${messageOf(err)}`);
|
|
7173
|
+
}
|
|
7174
|
+
const config = JSON.parse(stdout.trim());
|
|
7175
|
+
return {
|
|
7176
|
+
entrypoint: stringArray(config?.Entrypoint),
|
|
7177
|
+
cmd: stringArray(config?.Cmd)
|
|
7178
|
+
};
|
|
7179
|
+
}
|
|
7180
|
+
function stringArray(v) {
|
|
7181
|
+
return Array.isArray(v) && v.every((s) => typeof s === "string") ? v : [];
|
|
7182
|
+
}
|
|
7183
|
+
async function ensureRieBinary(platform, skipPull) {
|
|
7184
|
+
const machine = ELF_MACHINE_BY_PLATFORM[platform];
|
|
7185
|
+
if (machine === void 0) throw new Error(`unsupported platform '${platform}'`);
|
|
7186
|
+
const root = rieCacheDirectory();
|
|
7187
|
+
if (root === void 0) throw new Error("no cache directory (HOME is not set)");
|
|
7188
|
+
const target = join(root, platform.replace("/", "-"), RIE_BASENAME);
|
|
7189
|
+
if (!isMountableHostPath(target)) throw new Error(`the cache path ${displayUntrustedValue(target)} contains ':'`);
|
|
7190
|
+
let run = inFlight.get(target);
|
|
7191
|
+
if (run === void 0) {
|
|
7192
|
+
run = (async () => {
|
|
7193
|
+
if (await isRegularFile(target) && await isElfFor(target, machine)) return target;
|
|
7194
|
+
await extractRie(platform, target, machine, skipPull);
|
|
7195
|
+
return target;
|
|
7196
|
+
})();
|
|
7197
|
+
inFlight.set(target, run);
|
|
7198
|
+
run.catch(() => inFlight.delete(target));
|
|
7199
|
+
}
|
|
7200
|
+
return run;
|
|
7201
|
+
}
|
|
7202
|
+
function isMountableHostPath(path, pathApi = nodePath) {
|
|
7203
|
+
return !path.slice(pathApi.parse(path).root.length).includes(":");
|
|
7204
|
+
}
|
|
7205
|
+
async function isRegularFile(path) {
|
|
7206
|
+
try {
|
|
7207
|
+
return (await promises.lstat(path)).isFile();
|
|
7208
|
+
} catch {
|
|
7209
|
+
return false;
|
|
7210
|
+
}
|
|
7211
|
+
}
|
|
7212
|
+
async function isElfFor(path, machine) {
|
|
7213
|
+
let handle;
|
|
7214
|
+
try {
|
|
7215
|
+
handle = await promises.open(path, "r");
|
|
7216
|
+
const header = Buffer.alloc(20);
|
|
7217
|
+
const { bytesRead } = await handle.read(header, 0, 20, 0);
|
|
7218
|
+
return bytesRead === 20 && header.readUInt32BE(0) === 2135247942 && header.readUInt16LE(18) === machine;
|
|
7219
|
+
} catch {
|
|
7220
|
+
return false;
|
|
7221
|
+
} finally {
|
|
7222
|
+
await handle?.close().catch(() => void 0);
|
|
7223
|
+
}
|
|
7224
|
+
}
|
|
7225
|
+
async function extractRie(platform, target, machine, skipPull) {
|
|
7226
|
+
getLogger().child("rie").info(skipPull ? `Copying the Lambda Runtime Interface Emulator for ${platform} out of the local ${RIE_SOURCE_IMAGE} image (one time)...` : `Fetching the Lambda Runtime Interface Emulator for ${platform} from ${RIE_SOURCE_IMAGE} (one time)...`);
|
|
7227
|
+
const dir = dirname(target);
|
|
7228
|
+
await promises.mkdir(dir, {
|
|
7229
|
+
recursive: true,
|
|
7230
|
+
mode: 448
|
|
7231
|
+
});
|
|
7232
|
+
if (!skipPull) try {
|
|
7233
|
+
await runDockerStreaming([
|
|
7234
|
+
"pull",
|
|
7235
|
+
"--platform",
|
|
7236
|
+
platform,
|
|
7237
|
+
RIE_SOURCE_IMAGE
|
|
7238
|
+
], { streamLive: false });
|
|
7239
|
+
} catch (err) {
|
|
7240
|
+
throw new Error(`docker pull failed: ${messageOf(err)}`);
|
|
7241
|
+
}
|
|
7242
|
+
const createArgs = [
|
|
7243
|
+
"create",
|
|
7244
|
+
"--name",
|
|
7245
|
+
`${getEmbedConfig().resourceNamePrefix}-rie-extract-${process.pid}-${randomBytes(4).toString("hex")}`,
|
|
7246
|
+
...skipPull ? ["--pull", "never"] : [],
|
|
7247
|
+
"--platform",
|
|
7248
|
+
platform,
|
|
7249
|
+
RIE_SOURCE_IMAGE
|
|
7250
|
+
];
|
|
7251
|
+
let containerId;
|
|
7252
|
+
try {
|
|
7253
|
+
containerId = (await runDockerStreaming(createArgs, { streamLive: false })).stdout.trim();
|
|
7254
|
+
} catch (err) {
|
|
7255
|
+
throw new Error(`docker create failed: ${messageOf(err)}` + (skipPull ? ` (--no-pull: pull ${RIE_SOURCE_IMAGE} once, or run ${getEmbedConfig().binaryName} without --no-pull)` : ""));
|
|
7256
|
+
}
|
|
7257
|
+
const tmp = join(dir, `.${RIE_BASENAME}.${process.pid}.${randomBytes(4).toString("hex")}`);
|
|
7258
|
+
try {
|
|
7259
|
+
try {
|
|
7260
|
+
await runDockerStreaming([
|
|
7261
|
+
"cp",
|
|
7262
|
+
`${containerId}:${RIE_SOURCE_PATH}`,
|
|
7263
|
+
tmp
|
|
7264
|
+
], { streamLive: false });
|
|
7265
|
+
} catch (err) {
|
|
7266
|
+
throw new Error(`docker cp failed: ${messageOf(err)}`);
|
|
7267
|
+
}
|
|
7268
|
+
if (!await isRegularFile(tmp) || !await isElfFor(tmp, machine)) throw new Error(`the copied ${RIE_SOURCE_PATH} is not a ${platform} executable`);
|
|
7269
|
+
await promises.chmod(tmp, 493);
|
|
7270
|
+
await promises.rename(tmp, target);
|
|
7271
|
+
} finally {
|
|
7272
|
+
await promises.rm(tmp, {
|
|
7273
|
+
force: true,
|
|
7274
|
+
recursive: true
|
|
7275
|
+
}).catch(() => void 0);
|
|
7276
|
+
await runDockerStreaming([
|
|
7277
|
+
"rm",
|
|
7278
|
+
"-f",
|
|
7279
|
+
containerId
|
|
7280
|
+
], { streamLive: false }).catch(() => void 0);
|
|
7281
|
+
}
|
|
7282
|
+
}
|
|
7283
|
+
|
|
9080
7284
|
//#endregion
|
|
9081
7285
|
//#region src/local/api-gateway-event.ts
|
|
9082
7286
|
const MOCK_ACCOUNT_ID = "123456789012";
|
|
@@ -12337,8 +10541,8 @@ function getContainerAwsCredentialsPath() {
|
|
|
12337
10541
|
async function writeProfileCredentialsFile(profileName, creds) {
|
|
12338
10542
|
if (profileName === "") throw new Error("writeProfileCredentialsFile: profile name must not be empty.");
|
|
12339
10543
|
if (/[\r\n[\]]/.test(profileName)) throw new Error(`writeProfileCredentialsFile: profile name ${displayUntrustedValue(profileName)} contains a forbidden character (any of CR, LF, '[', ']' would corrupt the INI file or the docker -e env var).`);
|
|
12340
|
-
const dir = await mkdtemp(
|
|
12341
|
-
const hostPath =
|
|
10544
|
+
const dir = await mkdtemp(nodePath.join(tmpdir(), `${getEmbedConfig().productName}-profile-creds-`));
|
|
10545
|
+
const hostPath = nodePath.join(dir, "credentials");
|
|
12342
10546
|
const lines = [
|
|
12343
10547
|
`[${profileName}]`,
|
|
12344
10548
|
`aws_access_key_id = ${creds.accessKeyId}`,
|
|
@@ -12381,6 +10585,7 @@ async function localStartApiCommand(targets, options, extraStateProviders) {
|
|
|
12381
10585
|
const normalizedAssumeRole = normalizeStartApiAssumeRole(options.assumeRole, options.assumeRoleAuto ?? false);
|
|
12382
10586
|
if (normalizedAssumeRole === void 0) delete options.assumeRole;
|
|
12383
10587
|
else options.assumeRole = normalizedAssumeRole;
|
|
10588
|
+
await activateWorkloadAwsWiring(options);
|
|
12384
10589
|
await applyRoleArnIfSet({
|
|
12385
10590
|
roleArn: options.roleArn,
|
|
12386
10591
|
region: options.region,
|
|
@@ -12791,8 +10996,8 @@ async function localStartApiCommand(targets, options, extraStateProviders) {
|
|
|
12791
10996
|
}
|
|
12792
10997
|
function createWatchPredicates(args) {
|
|
12793
10998
|
const { watchRoot, output, watchConfig } = args;
|
|
12794
|
-
const toRel = (abs) =>
|
|
12795
|
-
const outputRel = toRel(
|
|
10999
|
+
const toRel = (abs) => nodePath.relative(watchRoot, abs).split(nodePath.sep).join("/");
|
|
11000
|
+
const outputRel = toRel(nodePath.resolve(watchRoot, output));
|
|
12796
11001
|
const excludePatterns = [
|
|
12797
11002
|
...outputRel !== "" && !outputRel.startsWith("..") ? [outputRel] : [],
|
|
12798
11003
|
"node_modules",
|
|
@@ -13159,13 +11364,24 @@ async function buildContainerSpec(args) {
|
|
|
13159
11364
|
containerPath: profileCredsFile.containerPath
|
|
13160
11365
|
} }
|
|
13161
11366
|
};
|
|
11367
|
+
const rie = await resolveRieWrap({
|
|
11368
|
+
image: imageRef,
|
|
11369
|
+
platform,
|
|
11370
|
+
entryPoint: lambda.imageConfig.entryPoint,
|
|
11371
|
+
command: lambda.imageConfig.command,
|
|
11372
|
+
skipPull
|
|
11373
|
+
});
|
|
13162
11374
|
return {
|
|
13163
11375
|
kind: "image",
|
|
13164
11376
|
lambda,
|
|
13165
11377
|
image: imageRef,
|
|
13166
11378
|
platform,
|
|
13167
|
-
command: lambda.imageConfig.command ?? [],
|
|
13168
|
-
...
|
|
11379
|
+
command: rie ? rie.cmd : lambda.imageConfig.command ?? [],
|
|
11380
|
+
...rie && {
|
|
11381
|
+
entryPoint: rie.entryPoint,
|
|
11382
|
+
rieMount: rie.mount
|
|
11383
|
+
},
|
|
11384
|
+
...!rie && lambda.imageConfig.entryPoint !== void 0 && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
|
|
13169
11385
|
...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory },
|
|
13170
11386
|
env: dockerEnv,
|
|
13171
11387
|
...sensitiveEnvKeys && { sensitiveEnvKeys },
|
|
@@ -13198,7 +11414,7 @@ async function resolveContainerImageForStartApi(lambda, skipPull, profile, optio
|
|
|
13198
11414
|
async function resolveLocalBuildPlan$1(lambda) {
|
|
13199
11415
|
const manifestPath = lambda.stack.assetManifestPath;
|
|
13200
11416
|
if (!manifestPath) return void 0;
|
|
13201
|
-
const cdkOutDir =
|
|
11417
|
+
const cdkOutDir = nodePath.dirname(manifestPath);
|
|
13202
11418
|
const manifest = await new AssetManifestLoader().loadStackManifest(lambda.stack, cdkOutDir);
|
|
13203
11419
|
if (!manifest) return void 0;
|
|
13204
11420
|
const entry = getDockerImageBySourceHash(manifest, lambda.imageUri);
|
|
@@ -13228,7 +11444,7 @@ async function materializeLambdaLayers$1(layers, layerTmpDirs, layerRoleArn) {
|
|
|
13228
11444
|
});
|
|
13229
11445
|
}
|
|
13230
11446
|
if (flat.length === 1) return flat[0].assetPath;
|
|
13231
|
-
const dir = mkdtempSync(
|
|
11447
|
+
const dir = mkdtempSync(nodePath.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-start-api-layers-`));
|
|
13232
11448
|
try {
|
|
13233
11449
|
for (const layer of flat) copyLayerTreeLastWins(layer.assetPath, dir);
|
|
13234
11450
|
} catch (error) {
|
|
@@ -13369,10 +11585,10 @@ function materializeInlineCode$2(handler, source, fileExtension, tmpDirsOut) {
|
|
|
13369
11585
|
const lastDot = handler.lastIndexOf(".");
|
|
13370
11586
|
if (lastDot <= 0) throw new Error(`Handler ${displayUntrustedValue(handler)} is malformed: expected '<modulePath>.<exportName>'.`);
|
|
13371
11587
|
const modulePath = handler.substring(0, lastDot);
|
|
13372
|
-
const dir = mkdtempSync(
|
|
11588
|
+
const dir = mkdtempSync(nodePath.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-start-api-`));
|
|
13373
11589
|
tmpDirsOut.add(dir);
|
|
13374
|
-
const filePath =
|
|
13375
|
-
mkdirSync(
|
|
11590
|
+
const filePath = nodePath.join(dir, `${modulePath}${fileExtension}`);
|
|
11591
|
+
mkdirSync(nodePath.dirname(filePath), { recursive: true });
|
|
13376
11592
|
writeFileSync(filePath, source, "utf-8");
|
|
13377
11593
|
return dir;
|
|
13378
11594
|
}
|
|
@@ -13661,6 +11877,7 @@ function createLocalStartApiCommand(opts = {}) {
|
|
|
13661
11877
|
return startApi;
|
|
13662
11878
|
}
|
|
13663
11879
|
function addStartApiSpecificOptions(cmd) {
|
|
11880
|
+
addAwsEndpointOptions(cmd);
|
|
13664
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));
|
|
13665
11882
|
}
|
|
13666
11883
|
|
|
@@ -13726,6 +11943,7 @@ async function localInvokeCommand(target, options, extraStateProviders) {
|
|
|
13726
11943
|
getLogger().debug(`cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
13727
11944
|
});
|
|
13728
11945
|
try {
|
|
11946
|
+
await activateWorkloadAwsWiring(options);
|
|
13729
11947
|
await applyRoleArnIfSet({
|
|
13730
11948
|
roleArn: options.roleArn,
|
|
13731
11949
|
region: options.region,
|
|
@@ -13896,7 +12114,7 @@ function materializeLambdaLayers(layers) {
|
|
|
13896
12114
|
containerPath: "/opt",
|
|
13897
12115
|
readOnly: true
|
|
13898
12116
|
} };
|
|
13899
|
-
const tmpDir = mkdtempSync(
|
|
12117
|
+
const tmpDir = mkdtempSync(nodePath.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-invoke-layers-`));
|
|
13900
12118
|
try {
|
|
13901
12119
|
for (const layer of layers) copyLayerTreeLastWins(layer.assetPath, tmpDir);
|
|
13902
12120
|
} catch (error) {
|
|
@@ -13936,13 +12154,21 @@ async function resolveContainerImagePlan$1(lambda, options) {
|
|
|
13936
12154
|
});
|
|
13937
12155
|
}
|
|
13938
12156
|
const tmpfs = resolveTmpfsForLambda(lambda);
|
|
12157
|
+
const rie = await resolveRieWrap({
|
|
12158
|
+
image: imageRef,
|
|
12159
|
+
platform,
|
|
12160
|
+
entryPoint: lambda.imageConfig.entryPoint,
|
|
12161
|
+
command: lambda.imageConfig.command,
|
|
12162
|
+
skipPull: options.pull === false
|
|
12163
|
+
});
|
|
13939
12164
|
return {
|
|
13940
12165
|
image: imageRef,
|
|
13941
12166
|
mounts: [],
|
|
13942
|
-
extraMounts: [],
|
|
13943
|
-
cmd: lambda.imageConfig.command ?? [],
|
|
12167
|
+
extraMounts: rie ? [rie.mount] : [],
|
|
12168
|
+
cmd: rie ? rie.cmd : lambda.imageConfig.command ?? [],
|
|
13944
12169
|
platform,
|
|
13945
|
-
...
|
|
12170
|
+
...rie && { entryPoint: rie.entryPoint },
|
|
12171
|
+
...!rie && lambda.imageConfig.entryPoint && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
|
|
13946
12172
|
...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory },
|
|
13947
12173
|
...tmpfs !== void 0 && { tmpfs }
|
|
13948
12174
|
};
|
|
@@ -14233,9 +12459,9 @@ function materializeInlineCode$1(handler, source, fileExtension) {
|
|
|
14233
12459
|
const lastDot = handler.lastIndexOf(".");
|
|
14234
12460
|
if (lastDot <= 0) throw new Error(`Handler ${displayUntrustedValue(handler)} is malformed: expected '<modulePath>.<exportName>'.`);
|
|
14235
12461
|
const modulePath = handler.substring(0, lastDot);
|
|
14236
|
-
const dir = mkdtempSync(
|
|
14237
|
-
const filePath =
|
|
14238
|
-
mkdirSync(
|
|
12462
|
+
const dir = mkdtempSync(nodePath.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-invoke-`));
|
|
12463
|
+
const filePath = nodePath.join(dir, `${modulePath}${fileExtension}`);
|
|
12464
|
+
mkdirSync(nodePath.dirname(filePath), { recursive: true });
|
|
14239
12465
|
writeFileSync(filePath, source, "utf-8");
|
|
14240
12466
|
return dir;
|
|
14241
12467
|
}
|
|
@@ -14332,6 +12558,7 @@ function createLocalInvokeCommand(opts = {}) {
|
|
|
14332
12558
|
return invoke;
|
|
14333
12559
|
}
|
|
14334
12560
|
function addInvokeSpecificOptions(cmd) {
|
|
12561
|
+
addAwsEndpointOptions(cmd);
|
|
14335
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."));
|
|
14336
12563
|
}
|
|
14337
12564
|
|
|
@@ -15197,6 +13424,7 @@ async function localInvokeAgentCoreCommand(target, options, extraStateProviders)
|
|
|
15197
13424
|
getLogger().debug(`cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
15198
13425
|
});
|
|
15199
13426
|
try {
|
|
13427
|
+
await activateWorkloadAwsWiring(options);
|
|
15200
13428
|
await applyRoleArnIfSet({
|
|
15201
13429
|
roleArn: options.roleArn,
|
|
15202
13430
|
region: options.region,
|
|
@@ -16092,6 +14320,8 @@ async function softReloadAgentContainer(containerId, newAssetSourceDir) {
|
|
|
16092
14320
|
}
|
|
16093
14321
|
try {
|
|
16094
14322
|
await execFileAsync$6(dockerCmd, ["restart", containerId]);
|
|
14323
|
+
const wiring = getActiveWorkloadAwsWiring();
|
|
14324
|
+
if (wiring) await attachLoopbackForwarder(containerId, wiring);
|
|
16095
14325
|
} catch (err) {
|
|
16096
14326
|
throw new CdkLocalError(`softReloadAgentContainer: docker restart of '${containerId}' failed: ${describeExecError(err)}.`, "LOCAL_INVOKE_AGENTCORE_WATCH_SOFT_RELOAD_RESTART_FAILED");
|
|
16097
14327
|
}
|
|
@@ -16169,6 +14399,7 @@ function createLocalInvokeAgentCoreCommand(opts = {}) {
|
|
|
16169
14399
|
return cmd;
|
|
16170
14400
|
}
|
|
16171
14401
|
function addInvokeAgentCoreSpecificOptions(cmd) {
|
|
14402
|
+
addAwsEndpointOptions(cmd);
|
|
16172
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));
|
|
16173
14404
|
}
|
|
16174
14405
|
|
|
@@ -16874,7 +15105,8 @@ async function runEcsTask(task, options, state) {
|
|
|
16874
15105
|
});
|
|
16875
15106
|
dockerCmds.set(container.name, {
|
|
16876
15107
|
args: built.args,
|
|
16877
|
-
sensitiveEnv: built.sensitiveEnv
|
|
15108
|
+
sensitiveEnv: built.sensitiveEnv,
|
|
15109
|
+
loopbackPorts: built.loopbackPorts
|
|
16878
15110
|
});
|
|
16879
15111
|
if (built.collisions.length > 0) logger.warn(describeRefusedSensitiveEnvKeys(`Container ${displayUntrustedValue(container.name)}`, built.collisions));
|
|
16880
15112
|
for (const ep of built.publishedEndpoints) state.publishedEndpoints.push(ep);
|
|
@@ -16883,7 +15115,9 @@ async function runEcsTask(task, options, state) {
|
|
|
16883
15115
|
for (const containerName of startOrder) {
|
|
16884
15116
|
const container = task.containers.find((c) => c.name === containerName);
|
|
16885
15117
|
await awaitDependencies(container, startedByName);
|
|
16886
|
-
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);
|
|
16887
15121
|
logger.info(`Starting container ${displayIdent(container.name)} (image=${displayIdent(imagePlan.get(container.name))})`);
|
|
16888
15122
|
let id;
|
|
16889
15123
|
warnFinchArgvExposure(Object.keys(sensitiveEnv));
|
|
@@ -16905,6 +15139,8 @@ async function runEcsTask(task, options, state) {
|
|
|
16905
15139
|
id,
|
|
16906
15140
|
container
|
|
16907
15141
|
});
|
|
15142
|
+
const wiring = getActiveWorkloadAwsWiring();
|
|
15143
|
+
if (wiring) await attachLoopbackForwarder(id, wiring, loopbackPorts);
|
|
16908
15144
|
if (!options.detach) state.logStoppers.push(attachContainerLogStreamer(`[${displayIdent(container.name)}] `, id));
|
|
16909
15145
|
}
|
|
16910
15146
|
if (options.detach) return {
|
|
@@ -17228,7 +15464,10 @@ function buildDockerRunArgs(opts) {
|
|
|
17228
15464
|
args.push("-p", `${containerHost}::${pm.containerPort}/${pm.protocol}`);
|
|
17229
15465
|
}
|
|
17230
15466
|
}
|
|
17231
|
-
|
|
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`);
|
|
17232
15471
|
for (const mp of container.mountPoints) {
|
|
17233
15472
|
const v = volumeByName.get(mp.sourceVolume);
|
|
17234
15473
|
if (!v) continue;
|
|
@@ -17242,7 +15481,7 @@ function buildDockerRunArgs(opts) {
|
|
|
17242
15481
|
args.push("-v", `${name}:${mp.containerPath}${ro}`);
|
|
17243
15482
|
}
|
|
17244
15483
|
}
|
|
17245
|
-
|
|
15484
|
+
let finalEnv = {};
|
|
17246
15485
|
const metaEnv = buildMetadataEnv({
|
|
17247
15486
|
containerName: container.name,
|
|
17248
15487
|
...roleArn !== void 0 && { roleArn },
|
|
@@ -17250,10 +15489,11 @@ function buildDockerRunArgs(opts) {
|
|
|
17250
15489
|
...opts.sidecarIp !== void 0 && { sidecarIp: opts.sidecarIp }
|
|
17251
15490
|
});
|
|
17252
15491
|
Object.assign(finalEnv, metaEnv);
|
|
17253
|
-
if (
|
|
17254
|
-
finalEnv["AWS_SHARED_CREDENTIALS_FILE"] =
|
|
17255
|
-
finalEnv["AWS_PROFILE"] =
|
|
15492
|
+
if (profileCredentialsFile) {
|
|
15493
|
+
finalEnv["AWS_SHARED_CREDENTIALS_FILE"] = profileCredentialsFile.containerPath;
|
|
15494
|
+
finalEnv["AWS_PROFILE"] = profileCredentialsFile.profileName;
|
|
17256
15495
|
}
|
|
15496
|
+
if (wiring?.mode === "forward") for (const [k, v] of Object.entries(wiring.env)) defineOwnKey(finalEnv, k, v);
|
|
17257
15497
|
for (const [k, v] of Object.entries(container.environment)) defineOwnKey(finalEnv, k, v);
|
|
17258
15498
|
for (const s of secrets) defineOwnKey(finalEnv, s.name, s.value);
|
|
17259
15499
|
const overrides = opts.envOverrides;
|
|
@@ -17261,6 +15501,10 @@ function buildDockerRunArgs(opts) {
|
|
|
17261
15501
|
applyEnvOverrideMap(finalEnv, overrides["Parameters"]);
|
|
17262
15502
|
applyEnvOverrideMap(finalEnv, overrides[container.name]);
|
|
17263
15503
|
}
|
|
15504
|
+
if (wiring) finalEnv = applyWorkloadAwsWiringToEnv(finalEnv, wiring.mode === "emulator" ? wiring : {
|
|
15505
|
+
...wiring,
|
|
15506
|
+
env: {}
|
|
15507
|
+
});
|
|
17264
15508
|
const sensitiveEnvKeys = new Set(SENSITIVE_ENV_KEYS);
|
|
17265
15509
|
for (const s of secrets) sensitiveEnvKeys.add(s.name);
|
|
17266
15510
|
for (const s of container.secrets) sensitiveEnvKeys.add(s.name);
|
|
@@ -17290,7 +15534,8 @@ function buildDockerRunArgs(opts) {
|
|
|
17290
15534
|
args,
|
|
17291
15535
|
sensitiveEnv,
|
|
17292
15536
|
collisions,
|
|
17293
|
-
publishedEndpoints
|
|
15537
|
+
publishedEndpoints,
|
|
15538
|
+
loopbackPorts: wiring ? effectiveLoopbackPorts(finalEnv, wiring) : []
|
|
17294
15539
|
};
|
|
17295
15540
|
}
|
|
17296
15541
|
function shellJoin(parts) {
|
|
@@ -18102,7 +16347,7 @@ async function softReloadReplica(args) {
|
|
|
18102
16347
|
const defaultDockerInspectWorkdirImpl = async (containerId) => {
|
|
18103
16348
|
const { execFile } = await import("node:child_process");
|
|
18104
16349
|
const { promisify } = await import("node:util");
|
|
18105
|
-
const { getDockerCmd } = await import("./docker-cmd-
|
|
16350
|
+
const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
|
|
18106
16351
|
const { stdout } = await promisify(execFile)(getDockerCmd(), [
|
|
18107
16352
|
"inspect",
|
|
18108
16353
|
"--format",
|
|
@@ -18115,7 +16360,7 @@ let dockerInspectWorkdirImpl = defaultDockerInspectWorkdirImpl;
|
|
|
18115
16360
|
const defaultDockerCpImpl = async (src, dst) => {
|
|
18116
16361
|
const { execFile } = await import("node:child_process");
|
|
18117
16362
|
const { promisify } = await import("node:util");
|
|
18118
|
-
const { getDockerCmd } = await import("./docker-cmd-
|
|
16363
|
+
const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
|
|
18119
16364
|
await promisify(execFile)(getDockerCmd(), [
|
|
18120
16365
|
"cp",
|
|
18121
16366
|
src,
|
|
@@ -18126,14 +16371,20 @@ let dockerCpImpl = defaultDockerCpImpl;
|
|
|
18126
16371
|
const defaultDockerStopImpl = async (containerId) => {
|
|
18127
16372
|
const { execFile } = await import("node:child_process");
|
|
18128
16373
|
const { promisify } = await import("node:util");
|
|
18129
|
-
const { getDockerCmd } = await import("./docker-cmd-
|
|
16374
|
+
const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
|
|
18130
16375
|
await promisify(execFile)(getDockerCmd(), ["stop", containerId]);
|
|
18131
16376
|
};
|
|
18132
16377
|
const defaultDockerStartImpl = async (containerId) => {
|
|
18133
16378
|
const { execFile } = await import("node:child_process");
|
|
18134
16379
|
const { promisify } = await import("node:util");
|
|
18135
|
-
const { getDockerCmd } = await import("./docker-cmd-
|
|
16380
|
+
const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
|
|
18136
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
|
+
}
|
|
18137
16388
|
};
|
|
18138
16389
|
let dockerStopImpl = defaultDockerStopImpl;
|
|
18139
16390
|
let dockerStartImpl = defaultDockerStartImpl;
|
|
@@ -18193,7 +16444,7 @@ async function attachToSharedNetwork(containerId, plan, withAliases) {
|
|
|
18193
16444
|
const defaultDockerNetworkConnectImpl = async (networkName, containerId, opts) => {
|
|
18194
16445
|
const { execFile } = await import("node:child_process");
|
|
18195
16446
|
const { promisify } = await import("node:util");
|
|
18196
|
-
const { getDockerCmd } = await import("./docker-cmd-
|
|
16447
|
+
const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
|
|
18197
16448
|
const args = ["network", "connect"];
|
|
18198
16449
|
if (opts.ip) args.push("--ip", opts.ip);
|
|
18199
16450
|
for (const a of opts.aliases) args.push("--alias", a);
|
|
@@ -18204,7 +16455,7 @@ let dockerNetworkConnectImpl = defaultDockerNetworkConnectImpl;
|
|
|
18204
16455
|
const defaultDockerInspectPublishesHostPortsImpl = async (containerId) => {
|
|
18205
16456
|
const { execFile } = await import("node:child_process");
|
|
18206
16457
|
const { promisify } = await import("node:util");
|
|
18207
|
-
const { getDockerCmd } = await import("./docker-cmd-
|
|
16458
|
+
const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
|
|
18208
16459
|
const { stdout } = await promisify(execFile)(getDockerCmd(), [
|
|
18209
16460
|
"inspect",
|
|
18210
16461
|
"--format",
|
|
@@ -18243,7 +16494,7 @@ async function disconnectOldFromSharedNetwork(oldInstance, opts = {}) {
|
|
|
18243
16494
|
const defaultDockerNetworkDisconnectImpl = async (networkName, containerId) => {
|
|
18244
16495
|
const { execFile } = await import("node:child_process");
|
|
18245
16496
|
const { promisify } = await import("node:util");
|
|
18246
|
-
const { getDockerCmd } = await import("./docker-cmd-
|
|
16497
|
+
const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
|
|
18247
16498
|
await promisify(execFile)(getDockerCmd(), [
|
|
18248
16499
|
"network",
|
|
18249
16500
|
"disconnect",
|
|
@@ -18334,7 +16585,7 @@ const LISTEN_PROBE_SCRIPT = [
|
|
|
18334
16585
|
async function dockerExecListenProbe(containerId, port, timeoutMs = 1e4) {
|
|
18335
16586
|
const { execFile } = await import("node:child_process");
|
|
18336
16587
|
const { promisify } = await import("node:util");
|
|
18337
|
-
const { getDockerCmd } = await import("./docker-cmd-
|
|
16588
|
+
const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
|
|
18338
16589
|
try {
|
|
18339
16590
|
await promisify(execFile)(getDockerCmd(), [
|
|
18340
16591
|
"exec",
|
|
@@ -18488,7 +16739,7 @@ function pickEssentialContainerId(instance, service) {
|
|
|
18488
16739
|
const defaultWaitForExitImpl = async (containerId) => {
|
|
18489
16740
|
const { execFile } = await import("node:child_process");
|
|
18490
16741
|
const { promisify } = await import("node:util");
|
|
18491
|
-
const { getDockerCmd } = await import("./docker-cmd-
|
|
16742
|
+
const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
|
|
18492
16743
|
const { stdout } = await promisify(execFile)(getDockerCmd(), ["wait", containerId], { maxBuffer: 1024 * 1024 });
|
|
18493
16744
|
const code = parseInt(stdout.trim(), 10);
|
|
18494
16745
|
return Number.isFinite(code) ? code : -1;
|
|
@@ -18498,7 +16749,7 @@ const EXIT_LOG_TAIL_LINES = 50;
|
|
|
18498
16749
|
const defaultReadContainerLogsImpl = async (containerId) => {
|
|
18499
16750
|
const { execFile } = await import("node:child_process");
|
|
18500
16751
|
const { promisify } = await import("node:util");
|
|
18501
|
-
const { getDockerCmd } = await import("./docker-cmd-
|
|
16752
|
+
const { getDockerCmd } = await import("./docker-cmd-Cjg3jGYF.js").then((n) => n.t);
|
|
18502
16753
|
const { stdout, stderr } = await promisify(execFile)(getDockerCmd(), [
|
|
18503
16754
|
"logs",
|
|
18504
16755
|
"--tail",
|
|
@@ -19854,9 +18105,9 @@ function materializeInlineCode(handler, source, fileExtension) {
|
|
|
19854
18105
|
const lastDot = handler.lastIndexOf(".");
|
|
19855
18106
|
if (lastDot <= 0) throw new Error(`Handler ${displayIdent(handler)} is malformed: expected '<modulePath>.<exportName>'.`);
|
|
19856
18107
|
const modulePath = handler.substring(0, lastDot);
|
|
19857
|
-
const dir = mkdtempSync(
|
|
19858
|
-
const filePath =
|
|
19859
|
-
mkdirSync(
|
|
18108
|
+
const dir = mkdtempSync(nodePath.join(tmpdir(), `${getEmbedConfig().resourceNamePrefix}-alb-lambda-`));
|
|
18109
|
+
const filePath = nodePath.join(dir, `${modulePath}${fileExtension}`);
|
|
18110
|
+
mkdirSync(nodePath.dirname(filePath), { recursive: true });
|
|
19860
18111
|
writeFileSync(filePath, source, "utf-8");
|
|
19861
18112
|
return dir;
|
|
19862
18113
|
}
|
|
@@ -19896,7 +18147,7 @@ async function resolveContainerImagePlan(lambda, opts) {
|
|
|
19896
18147
|
let imageRef;
|
|
19897
18148
|
let localBuilt = false;
|
|
19898
18149
|
if (manifestPath) {
|
|
19899
|
-
const cdkOutDir =
|
|
18150
|
+
const cdkOutDir = nodePath.dirname(manifestPath);
|
|
19900
18151
|
const manifest = await new AssetManifestLoader().loadStackManifest(lambda.stack, cdkOutDir);
|
|
19901
18152
|
const entry = manifest ? getDockerImageBySourceHash(manifest, lambda.imageUri) : void 0;
|
|
19902
18153
|
if (entry) {
|
|
@@ -19916,12 +18167,20 @@ async function resolveContainerImagePlan(lambda, opts) {
|
|
|
19916
18167
|
...opts.ecrRoleArn !== void 0 && { ecrRoleArn: opts.ecrRoleArn }
|
|
19917
18168
|
});
|
|
19918
18169
|
}
|
|
18170
|
+
const rie = await resolveRieWrap({
|
|
18171
|
+
image: imageRef,
|
|
18172
|
+
platform,
|
|
18173
|
+
entryPoint: lambda.imageConfig.entryPoint,
|
|
18174
|
+
command: lambda.imageConfig.command,
|
|
18175
|
+
skipPull: opts.skipPull === true
|
|
18176
|
+
});
|
|
19919
18177
|
return {
|
|
19920
18178
|
image: imageRef,
|
|
19921
|
-
mounts: [],
|
|
19922
|
-
cmd: lambda.imageConfig.command ?? [],
|
|
18179
|
+
mounts: rie ? [rie.mount] : [],
|
|
18180
|
+
cmd: rie ? rie.cmd : lambda.imageConfig.command ?? [],
|
|
19923
18181
|
platform,
|
|
19924
|
-
...
|
|
18182
|
+
...rie && { entryPoint: rie.entryPoint },
|
|
18183
|
+
...!rie && lambda.imageConfig.entryPoint && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
|
|
19925
18184
|
...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory }
|
|
19926
18185
|
};
|
|
19927
18186
|
}
|
|
@@ -20683,6 +18942,7 @@ async function runEcsServiceEmulator(targets, options, strategy, extraStateProvi
|
|
|
20683
18942
|
}
|
|
20684
18943
|
}, (err) => getLogger().warn(`service cleanup failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
20685
18944
|
try {
|
|
18945
|
+
await activateWorkloadAwsWiring(options);
|
|
20686
18946
|
await applyRoleArnIfSet({
|
|
20687
18947
|
roleArn: options.roleArn,
|
|
20688
18948
|
region: options.region,
|
|
@@ -21592,7 +19852,10 @@ function resolveShadowReadyTimeoutMs(options, envPrefix, env = process.env) {
|
|
|
21592
19852
|
return DEFAULT_SHADOW_READY_TIMEOUT_MS;
|
|
21593
19853
|
}
|
|
21594
19854
|
async function resolveSharedSidecarCredentials(options) {
|
|
19855
|
+
const wiring = getActiveWorkloadAwsWiring();
|
|
19856
|
+
if (wiring?.mode === "emulator") return wiring.emulatorCredentials;
|
|
21595
19857
|
if (options.profile) return resolveProfileCredentials(options.profile);
|
|
19858
|
+
return resolveHostDefaultCredentials();
|
|
21596
19859
|
}
|
|
21597
19860
|
async function resolveAndBuildImageOverrides(args) {
|
|
21598
19861
|
const { perTarget, stacks, options, extraStateProviders, logger } = args;
|
|
@@ -21681,6 +19944,7 @@ function resolveEcsAssumeRoleOption(options) {
|
|
|
21681
19944
|
}
|
|
21682
19945
|
}
|
|
21683
19946
|
function addCommonEcsServiceOptions(cmd) {
|
|
19947
|
+
addAwsEndpointOptions(cmd);
|
|
21684
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"));
|
|
21685
19949
|
addEcsAssumeRoleOptions(cmd);
|
|
21686
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));
|
|
@@ -21723,6 +19987,7 @@ async function localRunTaskCommand(target, options, extraStateProviders) {
|
|
|
21723
19987
|
await cleanupPromise;
|
|
21724
19988
|
};
|
|
21725
19989
|
try {
|
|
19990
|
+
await activateWorkloadAwsWiring(options);
|
|
21726
19991
|
await applyRoleArnIfSet({
|
|
21727
19992
|
roleArn: options.roleArn,
|
|
21728
19993
|
region: options.region,
|
|
@@ -21976,8 +20241,11 @@ function readEnvOverridesFile(filePath) {
|
|
|
21976
20241
|
return parsed;
|
|
21977
20242
|
}
|
|
21978
20243
|
async function resolveSidecarCredentials(options, assumedCredentials) {
|
|
20244
|
+
const wiring = getActiveWorkloadAwsWiring();
|
|
20245
|
+
if (wiring?.mode === "emulator") return wiring.emulatorCredentials;
|
|
21979
20246
|
if (assumedCredentials) return assumedCredentials;
|
|
21980
20247
|
if (options.profile) return resolveProfileCredentials(options.profile);
|
|
20248
|
+
return resolveHostDefaultCredentials();
|
|
21981
20249
|
}
|
|
21982
20250
|
function createLocalRunTaskCommand(opts = {}) {
|
|
21983
20251
|
setEmbedConfig(opts.embedConfig);
|
|
@@ -22037,6 +20305,7 @@ async function resolveRunTaskImageOverride(args) {
|
|
|
22037
20305
|
return { pinnedUncovered: pinned && uncovered.length > 0 };
|
|
22038
20306
|
}
|
|
22039
20307
|
function addRunTaskSpecificOptions(cmd) {
|
|
20308
|
+
addAwsEndpointOptions(cmd);
|
|
22040
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."));
|
|
22041
20310
|
addEcsAssumeRoleOptions(cmd);
|
|
22042
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."));
|
|
@@ -25923,6 +24192,7 @@ async function localStartCloudFrontCommand(target, options, extraStateProviders,
|
|
|
25923
24192
|
if (options.verbose) logger.setLevel("debug");
|
|
25924
24193
|
const originOverrides = parseOriginOverrides(options.origin);
|
|
25925
24194
|
const tlsRequested = options.tls === true || options.tlsCert !== void 0 || options.tlsKey !== void 0;
|
|
24195
|
+
await activateWorkloadAwsWiring(options);
|
|
25926
24196
|
await applyRoleArnIfSet({
|
|
25927
24197
|
roleArn: options.roleArn,
|
|
25928
24198
|
region: options.region,
|
|
@@ -26091,6 +24361,7 @@ function createLocalStartCloudFrontCommand(opts = {}) {
|
|
|
26091
24361
|
return cmd;
|
|
26092
24362
|
}
|
|
26093
24363
|
function addStartCloudFrontSpecificOptions(cmd) {
|
|
24364
|
+
addAwsEndpointOptions(cmd);
|
|
26094
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));
|
|
26095
24366
|
}
|
|
26096
24367
|
|
|
@@ -26479,6 +24750,7 @@ async function localStartAgentCoreCommand(target, options, extraStateProviders,
|
|
|
26479
24750
|
await profileCredsFile.dispose();
|
|
26480
24751
|
} catch {}
|
|
26481
24752
|
};
|
|
24753
|
+
await activateWorkloadAwsWiring(options);
|
|
26482
24754
|
await applyRoleArnIfSet({
|
|
26483
24755
|
roleArn: options.roleArn,
|
|
26484
24756
|
region: options.region,
|
|
@@ -26726,6 +24998,7 @@ function createLocalStartAgentCoreCommand(opts = {}) {
|
|
|
26726
24998
|
return cmd;
|
|
26727
24999
|
}
|
|
26728
25000
|
function addStartAgentCoreSpecificOptions(cmd) {
|
|
25001
|
+
addAwsEndpointOptions(cmd);
|
|
26729
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."));
|
|
26730
25003
|
}
|
|
26731
25004
|
|
|
@@ -26740,6 +25013,7 @@ async function localStartWebFunctionCommand(target, options, extraStateProviders
|
|
|
26740
25013
|
const logger = getLogger();
|
|
26741
25014
|
if (options.verbose) logger.setLevel("debug");
|
|
26742
25015
|
const forever = () => new Promise(() => void 0);
|
|
25016
|
+
await activateWorkloadAwsWiring(options);
|
|
26743
25017
|
await applyRoleArnIfSet({
|
|
26744
25018
|
roleArn: options.roleArn,
|
|
26745
25019
|
region: options.region,
|
|
@@ -26838,6 +25112,7 @@ function createLocalStartWebFunctionCommand(opts = {}) {
|
|
|
26838
25112
|
return cmd;
|
|
26839
25113
|
}
|
|
26840
25114
|
function addStartWebFunctionSpecificOptions(cmd) {
|
|
25115
|
+
addAwsEndpointOptions(cmd);
|
|
26841
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."));
|
|
26842
25117
|
}
|
|
26843
25118
|
|
|
@@ -27848,6 +26123,7 @@ async function localStartMicrovmCommand(target, options, extraStateProviders, ho
|
|
|
27848
26123
|
disposeMicrovmCodeArtifact(artifact);
|
|
27849
26124
|
};
|
|
27850
26125
|
const teardown = () => teardownPromise ??= doTeardown();
|
|
26126
|
+
await activateWorkloadAwsWiring(options);
|
|
27851
26127
|
await applyRoleArnIfSet({
|
|
27852
26128
|
roleArn: options.roleArn,
|
|
27853
26129
|
region: options.region,
|
|
@@ -28027,6 +26303,7 @@ function createLocalStartMicrovmCommand(opts = {}) {
|
|
|
28027
26303
|
return cmd;
|
|
28028
26304
|
}
|
|
28029
26305
|
function addStartMicrovmSpecificOptions(cmd) {
|
|
26306
|
+
addAwsEndpointOptions(cmd);
|
|
28030
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."));
|
|
28031
26308
|
}
|
|
28032
26309
|
|
|
@@ -33359,5 +31636,5 @@ function addStudioSpecificOptions(cmd) {
|
|
|
33359
31636
|
}
|
|
33360
31637
|
|
|
33361
31638
|
//#endregion
|
|
33362
|
-
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 };
|
|
33363
|
-
//# sourceMappingURL=local-studio-
|
|
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
|