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.
@@ -0,0 +1,916 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-w6R9maHv.js";
2
+ import { c as getEmbedConfig, t as getLogger } from "./logger-Co5XVwco.js";
3
+ import { r as displayUntrustedValue, u as describeCredentialLoadFailure } from "./assembly-path-R96uhMm1.js";
4
+ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
5
+ import { Agent, get, request } from "node:http";
6
+ import { Agent as Agent$1, get as get$1, request as request$1 } from "node:https";
7
+ import { rootCertificates } from "node:tls";
8
+ import { brotliDecompressSync, gunzipSync, inflateSync } from "node:zlib";
9
+ import { NodeHttpHandler } from "@smithy/node-http-handler";
10
+ import { Agent as Agent$2 } from "agent-base";
11
+ import { HttpProxyAgent } from "http-proxy-agent";
12
+ import { HttpsProxyAgent } from "https-proxy-agent";
13
+ import { getProxyForUrl } from "proxy-from-env";
14
+ import * as path$1 from "node:path";
15
+ import { homedir, tmpdir } from "node:os";
16
+
17
+ //#region src/utils/url-authority.ts
18
+ const IPV6_LITERAL_CHARS = /^[0-9A-Fa-f:.]+$/;
19
+ function formatHostForAuthority(host) {
20
+ const inner = host.length > 1 && host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
21
+ if (!inner.includes(":")) return host;
22
+ const zoneAt = inner.indexOf("%");
23
+ const literal = zoneAt === -1 ? inner : inner.slice(0, zoneAt);
24
+ if (!IPV6_LITERAL_CHARS.test(literal)) return host;
25
+ return `[${literal}]`;
26
+ }
27
+ function formatAuthority(host, port) {
28
+ return `${formatHostForAuthority(host)}:${port}`;
29
+ }
30
+ function hostFromAuthority(authority) {
31
+ if (authority.startsWith("[")) {
32
+ const close = authority.indexOf("]");
33
+ if (close === -1) return "";
34
+ const afterBracket = authority.slice(close + 1);
35
+ if (afterBracket !== "" && !/^:\d+$/.test(afterBracket)) return "";
36
+ return authority.slice(1, close);
37
+ }
38
+ const firstColon = authority.indexOf(":");
39
+ if (firstColon === -1) return authority;
40
+ if (authority.includes(":", firstColon + 1)) return "";
41
+ return authority.slice(0, firstColon);
42
+ }
43
+
44
+ //#endregion
45
+ //#region src/utils/loopback-host.ts
46
+ function normaliseHostLiteral(hostname) {
47
+ return hostname.trim().replace(/^\[/, "").replace(/\]$/, "").toLowerCase();
48
+ }
49
+ function isLoopbackLiteral(h) {
50
+ if (h === "localhost") return true;
51
+ if (h === "::1" || h === "0:0:0:0:0:0:0:1") return true;
52
+ const mapped = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(h);
53
+ if (mapped) return parseInt(mapped[1], 16) >> 8 === 127;
54
+ const dotted = /^(?:::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(h);
55
+ if (!dotted) return false;
56
+ const octets = dotted.slice(1).map(Number);
57
+ if (octets.some((o) => o > 255)) return false;
58
+ return octets[0] === 127;
59
+ }
60
+ function isWildcardLiteral(h) {
61
+ 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";
62
+ }
63
+ function isLoopbackHostname(hostname) {
64
+ return isLoopbackLiteral(normaliseHostLiteral(hostname));
65
+ }
66
+ function isWildcardHostname(hostname) {
67
+ return isWildcardLiteral(normaliseHostLiteral(hostname));
68
+ }
69
+ function isLoopbackHost(hostname) {
70
+ const h = normaliseHostLiteral(hostname).replace(/\.$/, "");
71
+ return h.endsWith(".localhost") || isLoopbackLiteral(h) || isWildcardLiteral(h);
72
+ }
73
+
74
+ //#endregion
75
+ //#region src/utils/aws-proxy.ts
76
+ const AGENT_OPTS = {
77
+ keepAlive: true,
78
+ maxSockets: 50
79
+ };
80
+ function isProxyEnvConfigured() {
81
+ return PROXY_ENV_VARIABLES.some((key) => Boolean(process.env[key]));
82
+ }
83
+ const PROXY_ENV_VARIABLES = [
84
+ "https_proxy",
85
+ "HTTPS_PROXY",
86
+ "http_proxy",
87
+ "HTTP_PROXY",
88
+ "all_proxy",
89
+ "ALL_PROXY"
90
+ ];
91
+ function isSpeakableProxyEnvValue(value) {
92
+ return !value.includes("://") || isSpeakableProxy(value.trim());
93
+ }
94
+ const AWS_ENDPOINT_PROBES = ["https://sts.amazonaws.com", "http://sts.amazonaws.com"];
95
+ function everySetProxyEnvValueIsUnspeakable() {
96
+ const set = PROXY_ENV_VARIABLES.map((key) => process.env[key] ?? "").filter((v) => v !== "");
97
+ return set.length > 0 && !set.some(isSpeakableProxyEnvValue);
98
+ }
99
+ const warnedProxySchemes = /* @__PURE__ */ new Set();
100
+ function proxySchemeOf(proxyUrl) {
101
+ const match = /^([a-z][a-z0-9+.-]{0,31}):\/\//i.exec(proxyUrl);
102
+ return match ? match[1].toLowerCase() : "(unrecognized)";
103
+ }
104
+ function isSpeakableProxy(proxyUrl) {
105
+ return /^https?:\/\//i.test(proxyUrl);
106
+ }
107
+ function warnUnspeakableProxy(proxyUrl) {
108
+ const scheme = proxySchemeOf(proxyUrl);
109
+ if (warnedProxySchemes.has(scheme)) return;
110
+ try {
111
+ 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.)`);
112
+ } catch {
113
+ return;
114
+ }
115
+ warnedProxySchemes.add(scheme);
116
+ }
117
+ function resolveProxyForTarget(targetHref) {
118
+ const proxyUrl = getProxyForUrl(targetHref).trim();
119
+ if (proxyUrl === "") return "";
120
+ if (isSpeakableProxy(proxyUrl)) return proxyUrl;
121
+ warnUnspeakableProxy(proxyUrl);
122
+ return "";
123
+ }
124
+ var EnvRoutingProxyAgent = class extends Agent$2 {
125
+ proxyAgents = /* @__PURE__ */ new Map();
126
+ directHttpAgent = new Agent(AGENT_OPTS);
127
+ directHttpsAgent = new Agent$1(AGENT_OPTS);
128
+ constructor() {
129
+ super(AGENT_OPTS);
130
+ }
131
+ connect(_req, options) {
132
+ const secure = options.secureEndpoint;
133
+ const host = options.host ?? "localhost";
134
+ const port = options.port || (secure ? 443 : 80);
135
+ const proxyUrl = resolveProxyForTarget(`${secure ? "https" : "http"}://${formatAuthority(host, port)}`);
136
+ if (!proxyUrl) return secure ? this.directHttpsAgent : this.directHttpAgent;
137
+ const key = `${secure ? "https" : "http"}|${proxyUrl}`;
138
+ let agent = this.proxyAgents.get(key);
139
+ if (!agent) {
140
+ agent = secure ? new HttpsProxyAgent(proxyUrl, AGENT_OPTS) : new HttpProxyAgent(proxyUrl, AGENT_OPTS);
141
+ this.proxyAgents.set(key, agent);
142
+ }
143
+ return agent;
144
+ }
145
+ destroy() {
146
+ for (const agent of this.proxyAgents.values()) agent.destroy();
147
+ this.proxyAgents.clear();
148
+ this.directHttpAgent.destroy();
149
+ this.directHttpsAgent.destroy();
150
+ super.destroy();
151
+ }
152
+ };
153
+ let endpointOverride;
154
+ function setAwsEndpointOverride(o) {
155
+ endpointOverride = o;
156
+ }
157
+ function getAwsEndpointOverride() {
158
+ return endpointOverride;
159
+ }
160
+ function endpointOverrideClientConfig(o) {
161
+ const httpsAgent = new Agent$1({
162
+ keepAlive: true,
163
+ ...o.caPem ? { ca: [...rootCertificates, o.caPem] } : {}
164
+ });
165
+ const creds = o.credentials;
166
+ return {
167
+ endpoint: o.endpoint,
168
+ requestHandler: new NodeHttpHandler({ httpsAgent }),
169
+ ...creds ? { credentials: async () => ({
170
+ accessKeyId: creds.accessKeyId,
171
+ secretAccessKey: creds.secretAccessKey,
172
+ ...creds.sessionToken ? { sessionToken: creds.sessionToken } : {}
173
+ }) } : {}
174
+ };
175
+ }
176
+ function buildProxyRequestHandler() {
177
+ const agent = new EnvRoutingProxyAgent();
178
+ return new NodeHttpHandler({
179
+ httpAgent: agent,
180
+ httpsAgent: agent
181
+ });
182
+ }
183
+ function buildProxyClientConfig(opts = {}) {
184
+ if (endpointOverride) return endpointOverrideClientConfig(endpointOverride);
185
+ if (!isProxyEnvConfigured()) return {};
186
+ if (everySetProxyEnvValueIsUnspeakable()) {
187
+ for (const probe of AWS_ENDPOINT_PROBES) resolveProxyForTarget(probe);
188
+ return {};
189
+ }
190
+ const profile = opts.profile;
191
+ let chain;
192
+ const credentials = async (identityProperties) => {
193
+ chain ??= (async () => {
194
+ const { defaultProvider } = await import("@aws-sdk/credential-provider-node");
195
+ return defaultProvider({
196
+ ...profile ? { profile } : {},
197
+ clientConfig: { requestHandler: buildProxyRequestHandler() }
198
+ });
199
+ })().catch((err) => {
200
+ chain = void 0;
201
+ throw err;
202
+ });
203
+ return (await chain)(identityProperties);
204
+ };
205
+ return {
206
+ requestHandler: buildProxyRequestHandler(),
207
+ credentials
208
+ };
209
+ }
210
+ const MAX_FETCH_REDIRECTS = 20;
211
+ const NULL_BODY_STATUSES = /* @__PURE__ */ new Set([
212
+ 204,
213
+ 205,
214
+ 304
215
+ ]);
216
+ const REQUEST_STALL_TIMEOUT_MS = 3e5;
217
+ function isRedirectStatus(status) {
218
+ return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
219
+ }
220
+ function parseHttpUrl(href) {
221
+ const parsed = new URL(href);
222
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new TypeError(`Unsupported protocol for a proxied request: "${parsed.protocol}"`);
223
+ return parsed;
224
+ }
225
+ function getThroughAgent(url, agent, timeoutMs = REQUEST_STALL_TIMEOUT_MS) {
226
+ return new Promise((resolve, reject) => {
227
+ let settled = false;
228
+ let timer;
229
+ let rearm = () => void 0;
230
+ const succeed = (value) => {
231
+ if (settled) return;
232
+ settled = true;
233
+ if (timer) clearTimeout(timer);
234
+ resolve(value);
235
+ };
236
+ const fail = (err) => {
237
+ if (settled) return;
238
+ settled = true;
239
+ if (timer) clearTimeout(timer);
240
+ reject(err);
241
+ };
242
+ const req = (url.protocol === "https:" ? request$1 : request)(url, {
243
+ agent,
244
+ headers: {
245
+ accept: "*/*",
246
+ "accept-encoding": "identity"
247
+ }
248
+ }, (res) => {
249
+ rearm();
250
+ const chunks = [];
251
+ res.on("data", (chunk) => {
252
+ rearm();
253
+ chunks.push(chunk);
254
+ });
255
+ res.on("error", fail);
256
+ res.on("end", () => {
257
+ if (res.statusCode === void 0) {
258
+ fail(/* @__PURE__ */ new Error("Malformed HTTP response: no status code"));
259
+ return;
260
+ }
261
+ succeed({
262
+ status: res.statusCode,
263
+ statusText: res.statusMessage ?? "",
264
+ headers: res.headers,
265
+ body: Buffer.concat(chunks)
266
+ });
267
+ });
268
+ });
269
+ req.on("error", fail);
270
+ rearm = () => {
271
+ if (settled) return;
272
+ if (timer) clearTimeout(timer);
273
+ timer = setTimeout(() => {
274
+ req.destroy();
275
+ fail(/* @__PURE__ */ new Error(`Proxied request stalled for ${timeoutMs} ms with no progress`));
276
+ }, timeoutMs);
277
+ timer.unref?.();
278
+ };
279
+ rearm();
280
+ req.end();
281
+ });
282
+ }
283
+ function decodeContentEncoding(raw) {
284
+ const header = raw.headers["content-encoding"];
285
+ const encoding = (Array.isArray(header) ? header.join(",") : header ?? "").trim().toLowerCase();
286
+ if (encoding === "" || encoding === "identity") return {
287
+ body: raw.body,
288
+ decoded: false
289
+ };
290
+ try {
291
+ if (encoding === "gzip" || encoding === "x-gzip") return {
292
+ body: gunzipSync(raw.body),
293
+ decoded: true
294
+ };
295
+ if (encoding === "deflate" || encoding === "x-deflate") return {
296
+ body: inflateSync(raw.body),
297
+ decoded: true
298
+ };
299
+ if (encoding === "br") return {
300
+ body: brotliDecompressSync(raw.body),
301
+ decoded: true
302
+ };
303
+ } catch {
304
+ return {
305
+ body: raw.body,
306
+ decoded: false
307
+ };
308
+ }
309
+ return {
310
+ body: raw.body,
311
+ decoded: false
312
+ };
313
+ }
314
+ function toWebResponse(raw) {
315
+ if (raw.status < 200 || raw.status > 599) throw new Error(`Unsupported HTTP status in response: ${raw.status}`);
316
+ const { body, decoded } = decodeContentEncoding(raw);
317
+ const headers = new Headers();
318
+ for (const [name, value] of Object.entries(raw.headers)) {
319
+ if (value === void 0) continue;
320
+ if (decoded && (name === "content-encoding" || name === "content-length")) continue;
321
+ if (Array.isArray(value)) for (const one of value) headers.append(name, one);
322
+ else headers.append(name, value);
323
+ }
324
+ return new Response(NULL_BODY_STATUSES.has(raw.status) ? null : body, {
325
+ status: raw.status,
326
+ statusText: raw.statusText.replace(/[^\t\x20-\x7e\x80-\xff]/g, ""),
327
+ headers
328
+ });
329
+ }
330
+ async function proxyAwareFetch(url, opts = {}) {
331
+ if (!isProxyEnvConfigured()) return globalThis.fetch(url);
332
+ let target = parseHttpUrl(url);
333
+ for (let hop = 0;; hop++) {
334
+ if (isLoopbackHost(target.hostname) || resolveProxyForTarget(target.href) === "") return globalThis.fetch(target.href);
335
+ const agent = new EnvRoutingProxyAgent();
336
+ let raw;
337
+ try {
338
+ raw = await getThroughAgent(target, agent, opts.timeoutMs);
339
+ } finally {
340
+ agent.destroy();
341
+ }
342
+ const location = raw.headers["location"];
343
+ if (!isRedirectStatus(raw.status) || typeof location !== "string" || location === "") return toWebResponse(raw);
344
+ if (hop >= MAX_FETCH_REDIRECTS) throw new Error(`Too many redirects (more than ${MAX_FETCH_REDIRECTS})`);
345
+ target = parseHttpUrl(new URL(location, target).href);
346
+ }
347
+ }
348
+
349
+ //#endregion
350
+ //#region src/utils/workload-identity.ts
351
+ function copyCredentials(c) {
352
+ return c ? {
353
+ accessKeyId: c.accessKeyId,
354
+ secretAccessKey: c.secretAccessKey,
355
+ ...c.sessionToken ? { sessionToken: c.sessionToken } : {}
356
+ } : void 0;
357
+ }
358
+ let record;
359
+ let stripWarned = false;
360
+ const SECOND_ASSUME_MESSAGE = "A role was already assumed in this process; refusing to assume a second one. Pass --role-arn once.";
361
+ function recordAssumedRole(caller, role) {
362
+ if (record !== void 0) throw new Error(SECOND_ASSUME_MESSAGE);
363
+ record = {
364
+ caller: copyCredentials(caller),
365
+ role: copyCredentials(role)
366
+ };
367
+ }
368
+ function assumedRoleRecorded() {
369
+ return record !== void 0;
370
+ }
371
+ function readEnvCallerCredentials(env = process.env) {
372
+ const accessKeyId = env["AWS_ACCESS_KEY_ID"];
373
+ const secretAccessKey = env["AWS_SECRET_ACCESS_KEY"];
374
+ if (!accessKeyId || !secretAccessKey) return void 0;
375
+ const sessionToken = env["AWS_SESSION_TOKEN"];
376
+ return {
377
+ accessKeyId,
378
+ secretAccessKey,
379
+ ...sessionToken ? { sessionToken } : {}
380
+ };
381
+ }
382
+ function resetWorkloadIdentity() {
383
+ record = void 0;
384
+ stripWarned = false;
385
+ }
386
+ function callerRecord() {
387
+ return getEmbedConfig().workloadIdentity === "caller" ? record : void 0;
388
+ }
389
+ const MULTIPLE_CREDENTIAL_SOURCES_WARNING = "Multiple credential sources detected";
390
+ const chainLogger = {
391
+ debug: () => {},
392
+ info: () => {},
393
+ warn: (...args) => {
394
+ const text = args.map(String).join(" ");
395
+ if (text.includes(MULTIPLE_CREDENTIAL_SOURCES_WARNING)) return;
396
+ getLogger().warn(text);
397
+ },
398
+ error: (...args) => {
399
+ getLogger().error(args.map(String).join(" "));
400
+ }
401
+ };
402
+ function callerChainWithoutEnv(proxied) {
403
+ let chain;
404
+ return async (identityProperties) => {
405
+ chain ??= (async () => {
406
+ const { defaultProvider } = await import("@aws-sdk/credential-provider-node");
407
+ return defaultProvider({
408
+ profile: "default",
409
+ logger: chainLogger,
410
+ ...proxied ? { clientConfig: { requestHandler: buildProxyRequestHandler() } } : {}
411
+ });
412
+ })().catch((err) => {
413
+ chain = void 0;
414
+ throw err;
415
+ });
416
+ return (await chain)(identityProperties);
417
+ };
418
+ }
419
+ function workloadClientConfig(opts = {}) {
420
+ const base = buildProxyClientConfig({ profile: opts.profile });
421
+ const rec = callerRecord();
422
+ if (!rec) return base;
423
+ if (base.endpoint !== void 0) return base;
424
+ if (opts.profile || process.env["AWS_PROFILE"]) return base;
425
+ if (rec.caller) {
426
+ const caller = rec.caller;
427
+ const credentials = async () => ({
428
+ accessKeyId: caller.accessKeyId,
429
+ secretAccessKey: caller.secretAccessKey,
430
+ ...caller.sessionToken ? { sessionToken: caller.sessionToken } : {}
431
+ });
432
+ return {
433
+ ...base,
434
+ credentials
435
+ };
436
+ }
437
+ return {
438
+ ...base,
439
+ credentials: callerChainWithoutEnv(base.requestHandler !== void 0)
440
+ };
441
+ }
442
+ function workloadStsClientConfig(args) {
443
+ return {
444
+ ...workloadClientConfig({ profile: args.profile }),
445
+ ...args.region && { region: args.region },
446
+ ...args.profile && { profile: args.profile }
447
+ };
448
+ }
449
+ function deployAccountStsClientConfig(args) {
450
+ const role = callerRecord()?.role;
451
+ if (!role) return {
452
+ ...buildProxyClientConfig({ profile: args.profile }),
453
+ ...args.region && { region: args.region },
454
+ ...args.profile && { profile: args.profile }
455
+ };
456
+ const credentials = async () => ({
457
+ accessKeyId: role.accessKeyId,
458
+ secretAccessKey: role.secretAccessKey,
459
+ ...role.sessionToken ? { sessionToken: role.sessionToken } : {}
460
+ });
461
+ return {
462
+ ...buildProxyClientConfig(),
463
+ ...args.region && { region: args.region },
464
+ ...args.profile && { profile: args.profile },
465
+ credentials
466
+ };
467
+ }
468
+ function accountLookupStsClientConfig(args) {
469
+ return args.readFromCfnStack ? workloadStsClientConfig({
470
+ region: args.region,
471
+ profile: args.profile
472
+ }) : deployAccountStsClientConfig({
473
+ region: args.region,
474
+ profile: args.profile
475
+ });
476
+ }
477
+ function applyWorkloadEnvCredentials(env) {
478
+ const rec = callerRecord();
479
+ if (!rec) return "unchanged";
480
+ if (rec.caller) {
481
+ env["AWS_ACCESS_KEY_ID"] = rec.caller.accessKeyId;
482
+ env["AWS_SECRET_ACCESS_KEY"] = rec.caller.secretAccessKey;
483
+ if (rec.caller.sessionToken) env["AWS_SESSION_TOKEN"] = rec.caller.sessionToken;
484
+ else delete env["AWS_SESSION_TOKEN"];
485
+ return "restored";
486
+ }
487
+ delete env["AWS_ACCESS_KEY_ID"];
488
+ delete env["AWS_SECRET_ACCESS_KEY"];
489
+ delete env["AWS_SESSION_TOKEN"];
490
+ return "stripped";
491
+ }
492
+ function warnWorkloadCredentialsStripped() {
493
+ if (stripWarned) return;
494
+ stripWarned = true;
495
+ 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.");
496
+ }
497
+
498
+ //#endregion
499
+ //#region src/local/workload-aws-wiring.ts
500
+ var workload_aws_wiring_exports = /* @__PURE__ */ __exportAll({
501
+ AUTH_OFF_PLACEHOLDER_CREDENTIALS: () => AUTH_OFF_PLACEHOLDER_CREDENTIALS,
502
+ CA_TRUST_ENV_KEYS: () => CA_TRUST_ENV_KEYS,
503
+ DEFAULT_AWS_EMULATOR_URL: () => DEFAULT_AWS_EMULATOR_URL,
504
+ EMULATOR_SCRUBBED_ENV_KEYS: () => EMULATOR_SCRUBBED_ENV_KEYS,
505
+ activateWorkloadAwsWiring: () => activateWorkloadAwsWiring,
506
+ applyWorkloadAwsWiringToEnv: () => applyWorkloadAwsWiringToEnv,
507
+ awsEmulatorEnvName: () => awsEmulatorEnvName,
508
+ collectHostEndpointOverrides: () => collectHostEndpointOverrides,
509
+ effectiveLoopbackPorts: () => effectiveLoopbackPorts,
510
+ getActiveWorkloadAwsWiring: () => getActiveWorkloadAwsWiring,
511
+ getContainerCaBundlePath: () => getContainerCaBundlePath,
512
+ parseAwsEndpoint: () => parseAwsEndpoint,
513
+ parseIniSections: () => parseIniSections,
514
+ probeAwsEmulatorHealth: () => probeAwsEmulatorHealth,
515
+ readEmulatorRunFiles: () => readEmulatorRunFiles,
516
+ readProfileEndpointSettings: () => readProfileEndpointSettings,
517
+ resolveAwsEmulatorOption: () => resolveAwsEmulatorOption,
518
+ resolveHostDefaultCredentials: () => resolveHostDefaultCredentials,
519
+ resolveWorkloadAwsWiring: () => resolveWorkloadAwsWiring,
520
+ setActiveWorkloadAwsWiring: () => setActiveWorkloadAwsWiring,
521
+ writeCaBundleFile: () => writeCaBundleFile
522
+ });
523
+ const CA_TRUST_ENV_KEYS = [
524
+ "AWS_CA_BUNDLE",
525
+ "NODE_EXTRA_CA_CERTS",
526
+ "REQUESTS_CA_BUNDLE",
527
+ "SSL_CERT_FILE"
528
+ ];
529
+ const EMULATOR_SCRUBBED_ENV_KEYS = [
530
+ "AWS_PROFILE",
531
+ "AWS_DEFAULT_PROFILE",
532
+ "AWS_SHARED_CREDENTIALS_FILE",
533
+ "AWS_CONFIG_FILE",
534
+ "AWS_WEB_IDENTITY_TOKEN_FILE",
535
+ "AWS_ROLE_ARN",
536
+ "AWS_ROLE_SESSION_NAME",
537
+ "AWS_CONTAINER_CREDENTIALS_FULL_URI",
538
+ "AWS_CONTAINER_AUTHORIZATION_TOKEN"
539
+ ];
540
+ const CREDENTIAL_KEYS = [
541
+ "AWS_ACCESS_KEY_ID",
542
+ "AWS_SECRET_ACCESS_KEY",
543
+ "AWS_SESSION_TOKEN"
544
+ ];
545
+ function parseAwsEndpoint(value, label = "--aws-emulator") {
546
+ let u;
547
+ try {
548
+ u = new URL(value);
549
+ } catch {
550
+ throw new Error(`${label} ${displayUntrustedValue(value)} is not a URL (expected e.g. https://127.0.0.1:9297).`);
551
+ }
552
+ if (u.protocol !== "https:" && u.protocol !== "http:") throw new Error(`${label} must be an http(s) URL, got ${displayUntrustedValue(value)}.`);
553
+ if (u.username || u.password || u.search || u.hash || u.pathname !== "/" && u.pathname !== "") throw new Error(`${label} must be a bare scheme://host:port URL (no credentials, path or query), got ${displayUntrustedValue(value)}.`);
554
+ const port = u.port ? Number(u.port) : u.protocol === "https:" ? 443 : 80;
555
+ const hostname = u.hostname.replace(/^\[|\]$/g, "");
556
+ return {
557
+ url: `${u.protocol}//${u.host}`,
558
+ hostname,
559
+ port,
560
+ loopback: isLoopbackHostname(u.hostname)
561
+ };
562
+ }
563
+ function parseIniSections(text) {
564
+ const out = {};
565
+ let current;
566
+ for (const raw of text.split(/\r?\n/)) {
567
+ const line = raw.trim();
568
+ if (line === "" || line.startsWith("#") || line.startsWith(";")) continue;
569
+ const sec = /^\[\s*(.+?)\s*\]$/.exec(line);
570
+ if (sec) {
571
+ current = Object.create(null);
572
+ Object.defineProperty(out, sec[1], {
573
+ value: current,
574
+ enumerable: true,
575
+ configurable: true,
576
+ writable: true
577
+ });
578
+ continue;
579
+ }
580
+ const eq = line.indexOf("=");
581
+ if (current && eq > 0) {
582
+ const k = line.slice(0, eq).trim();
583
+ Object.defineProperty(current, k, {
584
+ value: line.slice(eq + 1).trim(),
585
+ enumerable: true,
586
+ configurable: true,
587
+ writable: true
588
+ });
589
+ }
590
+ }
591
+ return out;
592
+ }
593
+ function readEmulatorRunFiles(port, homeDir = homedir()) {
594
+ const dir = path$1.join(homeDir, ".aws", "emulator", String(port));
595
+ const present = existsSync(dir);
596
+ const result = {
597
+ dir,
598
+ present
599
+ };
600
+ if (!present) return result;
601
+ try {
602
+ const sections = parseIniSections(readFileSync(path$1.join(dir, "emulator_credentials"), "utf8"));
603
+ const def = sections["default"] ?? Object.values(sections)[0];
604
+ if (def?.["aws_access_key_id"] && def["aws_secret_access_key"]) result.credentials = {
605
+ accessKeyId: def["aws_access_key_id"],
606
+ secretAccessKey: def["aws_secret_access_key"],
607
+ ...def["aws_session_token"] ? { sessionToken: def["aws_session_token"] } : {}
608
+ };
609
+ } catch {}
610
+ const ca = path$1.join(dir, "ca.pem");
611
+ if (existsSync(ca)) result.caPath = ca;
612
+ return result;
613
+ }
614
+ const AUTH_OFF_PLACEHOLDER_CREDENTIALS = Object.freeze({
615
+ accessKeyId: "EMULATORAUTHOFF00000",
616
+ secretAccessKey: "0000000000000000000000000000000000000000"
617
+ });
618
+ function profileName(env, profile) {
619
+ return profile || env["AWS_PROFILE"] || env["AWS_DEFAULT_PROFILE"] || "default";
620
+ }
621
+ function readProfileEndpointSettings(env, profile, homeDir = homedir()) {
622
+ const file = env["AWS_CONFIG_FILE"] || path$1.join(homeDir, ".aws", "config");
623
+ let sections;
624
+ try {
625
+ sections = parseIniSections(readFileSync(file, "utf8"));
626
+ } catch {
627
+ return {};
628
+ }
629
+ const name = profileName(env, profile);
630
+ const sec = name === "default" ? sections["default"] ?? sections["profile default"] : sections[`profile ${name}`];
631
+ if (!sec) return {};
632
+ return {
633
+ ...sec["endpoint_url"] ? { endpointUrl: sec["endpoint_url"] } : {},
634
+ ...sec["ca_bundle"] ? { caBundle: sec["ca_bundle"] } : {}
635
+ };
636
+ }
637
+ function collectHostEndpointOverrides(env, opts = {}) {
638
+ if ((env["AWS_IGNORE_CONFIGURED_ENDPOINT_URLS"] ?? "").toLowerCase() === "true") return {};
639
+ const out = {};
640
+ for (const [k, v] of Object.entries(env)) {
641
+ if (v === void 0 || v === "") continue;
642
+ if (k === "AWS_ENDPOINT_URL" || /^AWS_ENDPOINT_URL_[A-Z0-9_]+$/.test(k)) out[k] = v;
643
+ }
644
+ if (out["AWS_ENDPOINT_URL"] === void 0) {
645
+ const fromProfile = readProfileEndpointSettings(env, opts.profile, opts.homeDir).endpointUrl;
646
+ if (fromProfile) out["AWS_ENDPOINT_URL"] = fromProfile;
647
+ }
648
+ for (const [k, v] of Object.entries(out)) try {
649
+ parseAwsEndpoint(v, k);
650
+ } catch {
651
+ getLogger().warn(`${k} is not an http(s) URL; it is not forwarded to workload containers.`);
652
+ delete out[k];
653
+ }
654
+ return out;
655
+ }
656
+ function getContainerCaBundlePath() {
657
+ return `${getEmbedConfig().awsBindMountPath}/ca-bundle.pem`;
658
+ }
659
+ function expandHome(p, homeDir) {
660
+ return p === "~" ? homeDir : p.startsWith("~/") ? path$1.join(homeDir, p.slice(2)) : p;
661
+ }
662
+ function writeCaBundleFile(source) {
663
+ let pem;
664
+ try {
665
+ pem = readFileSync(source, "utf8");
666
+ } catch (err) {
667
+ throw new Error(`CA bundle ${displayUntrustedValue(source)} cannot be read (${err.code ?? "error"}).`);
668
+ }
669
+ const certs = pem.match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g);
670
+ if (!certs) throw new Error(`CA bundle ${displayUntrustedValue(source)} contains no PEM certificate.`);
671
+ const dir = mkdtempSync(path$1.join(tmpdir(), `${getEmbedConfig().productName}-ca-`));
672
+ const hostPath = path$1.join(dir, "ca-bundle.pem");
673
+ writeFileSync(hostPath, `${certs.join("\n")}\n${rootCertificates.join("\n")}\n`, { mode: 420 });
674
+ return {
675
+ hostPath,
676
+ dispose: () => rmSync(dir, {
677
+ recursive: true,
678
+ force: true
679
+ })
680
+ };
681
+ }
682
+ const DEFAULT_AWS_EMULATOR_URL = "https://127.0.0.1:9297";
683
+ function probeAwsEmulatorHealth(url, caPath) {
684
+ return new Promise((resolve) => {
685
+ let ca;
686
+ try {
687
+ ca = caPath ? [...rootCertificates, readFileSync(caPath, "utf8")] : void 0;
688
+ } catch {
689
+ ca = void 0;
690
+ }
691
+ const target = `${url}/__admin/health`;
692
+ const onResponse = (res) => {
693
+ res.resume();
694
+ resolve(res.statusCode === 200 ? void 0 : `HTTP_${res.statusCode ?? 0}`);
695
+ };
696
+ const req = target.startsWith("https:") ? get$1(target, {
697
+ timeout: 3e3,
698
+ ...ca ? { ca } : {}
699
+ }, onResponse) : get(target, { timeout: 3e3 }, onResponse);
700
+ req.on("timeout", () => {
701
+ req.destroy();
702
+ resolve("ETIMEDOUT");
703
+ });
704
+ req.on("error", (e) => resolve(e.code ?? "ERROR"));
705
+ });
706
+ }
707
+ function describeEmulatorUnreachable(ep, reason) {
708
+ return `--aws-emulator ${ep.url}: no AWS Emulator answers its health check at ${ep.url}/__admin/health (${reason}). Check that it is running on port ${ep.port} (\`aws-emulator -p ${ep.port}\`, or its Docker image published with \`-p 127.0.0.1:${ep.port}:${ep.port}\`), that the URL's port matches, and that it listens on an address this machine reaches (\`-b\`).`;
709
+ }
710
+ async function resolveWorkloadAwsWiring(opts) {
711
+ const env = opts.env ?? process.env;
712
+ const homeDir = opts.homeDir ?? homedir();
713
+ const disposers = [];
714
+ const dispose = () => {
715
+ for (const d of disposers.splice(0)) try {
716
+ d();
717
+ } catch {}
718
+ };
719
+ const caMount = (source) => {
720
+ const file = writeCaBundleFile(expandHome(source, homeDir));
721
+ disposers.push(file.dispose);
722
+ const containerPath = getContainerCaBundlePath();
723
+ const caEnv = {};
724
+ for (const k of CA_TRUST_ENV_KEYS) caEnv[k] = containerPath;
725
+ return {
726
+ hostPath: file.hostPath,
727
+ mounts: [{
728
+ hostPath: file.hostPath,
729
+ containerPath
730
+ }],
731
+ env: caEnv
732
+ };
733
+ };
734
+ try {
735
+ if (opts.awsEmulator) {
736
+ const ep = parseAwsEndpoint(opts.awsEmulator === true ? DEFAULT_AWS_EMULATOR_URL : opts.awsEmulator, "--aws-emulator");
737
+ if (ep.hostname === "localhost") {
738
+ ep.hostname = "127.0.0.1";
739
+ ep.url = ep.url.replace("//localhost", "//127.0.0.1");
740
+ }
741
+ const run = readEmulatorRunFiles(ep.port, homeDir);
742
+ const caSource = opts.caBundle || run.caPath || env["AWS_CA_BUNDLE"];
743
+ const failure = await (opts.probeHealth ?? probeAwsEmulatorHealth)(ep.url, caSource ? expandHome(caSource, homeDir) : void 0);
744
+ if (failure) throw new Error(describeEmulatorUnreachable(ep, failure));
745
+ let credentials;
746
+ if (run.credentials) credentials = run.credentials;
747
+ else {
748
+ credentials = AUTH_OFF_PLACEHOLDER_CREDENTIALS;
749
+ getLogger().info(`--aws-emulator: ${path$1.join(run.dir, "emulator_credentials")} not found but the emulator is healthy, so it runs with --auth off; workload containers get placeholder credentials.`);
750
+ }
751
+ const ca = caSource && ep.url.startsWith("https:") ? caMount(caSource) : void 0;
752
+ return {
753
+ mode: "emulator",
754
+ emulatorEndpoint: ep,
755
+ env: {
756
+ AWS_ENDPOINT_URL: ep.url,
757
+ AWS_EC2_METADATA_DISABLED: "true",
758
+ AWS_DISABLE_HOST_PREFIX_INJECTION: "true",
759
+ ...ca?.env ?? {}
760
+ },
761
+ scrubEnvKeys: EMULATOR_SCRUBBED_ENV_KEYS,
762
+ mounts: ca?.mounts ?? [],
763
+ loopbackPorts: ep.loopback ? [ep.port] : [],
764
+ probeHealth: ca !== void 0,
765
+ ...ca ? { caHostPath: ca.hostPath } : {},
766
+ emulatorCredentials: credentials,
767
+ dispose
768
+ };
769
+ }
770
+ const endpoints = collectHostEndpointOverrides(env, {
771
+ profile: opts.profile,
772
+ homeDir
773
+ });
774
+ let ca;
775
+ if (opts.caBundle) ca = caMount(opts.caBundle);
776
+ else {
777
+ const hostCa = env["AWS_CA_BUNDLE"] || readProfileEndpointSettings(env, opts.profile, homeDir).caBundle;
778
+ if (hostCa) try {
779
+ ca = caMount(hostCa);
780
+ } catch (err) {
781
+ getLogger().warn(`${err.message} It is not mounted into workload containers.`);
782
+ }
783
+ }
784
+ const ports = /* @__PURE__ */ new Set();
785
+ for (const v of Object.values(endpoints)) {
786
+ const ep = parseAwsEndpoint(v);
787
+ if (ep.loopback) ports.add(ep.port);
788
+ }
789
+ return {
790
+ mode: "forward",
791
+ env: {
792
+ ...endpoints,
793
+ ...ca?.env ?? {}
794
+ },
795
+ scrubEnvKeys: [],
796
+ mounts: ca?.mounts ?? [],
797
+ loopbackPorts: [...ports].sort((a, b) => a - b),
798
+ probeHealth: false,
799
+ ...ca ? { caHostPath: ca.hostPath } : {},
800
+ dispose
801
+ };
802
+ } catch (err) {
803
+ dispose();
804
+ throw err;
805
+ }
806
+ }
807
+ function effectiveLoopbackPorts(env, wiring) {
808
+ const used = /* @__PURE__ */ new Set();
809
+ for (const [k, v] of Object.entries(env)) {
810
+ if (k !== "AWS_ENDPOINT_URL" && !k.startsWith("AWS_ENDPOINT_URL_")) continue;
811
+ try {
812
+ const ep = parseAwsEndpoint(v, k);
813
+ if (ep.loopback) used.add(ep.port);
814
+ } catch {}
815
+ }
816
+ return wiring.loopbackPorts.filter((p) => used.has(p));
817
+ }
818
+ function applyWorkloadAwsWiringToEnv(env, wiring, defaultCredentials) {
819
+ const out = {};
820
+ for (const [k, v] of Object.entries(env)) Object.defineProperty(out, k, {
821
+ value: v,
822
+ enumerable: true,
823
+ configurable: true,
824
+ writable: true
825
+ });
826
+ const setCreds = (c) => {
827
+ for (const k of CREDENTIAL_KEYS) delete out[k];
828
+ if (!c) return;
829
+ out["AWS_ACCESS_KEY_ID"] = c.accessKeyId;
830
+ out["AWS_SECRET_ACCESS_KEY"] = c.secretAccessKey;
831
+ if (c.sessionToken) out["AWS_SESSION_TOKEN"] = c.sessionToken;
832
+ };
833
+ if (wiring.mode === "emulator") {
834
+ for (const k of wiring.scrubEnvKeys) delete out[k];
835
+ Object.assign(out, wiring.env);
836
+ setCreds(wiring.emulatorCredentials);
837
+ } else {
838
+ for (const [k, v] of Object.entries(wiring.env)) if (out[k] === void 0) out[k] = v;
839
+ if (defaultCredentials && !out["AWS_ACCESS_KEY_ID"]) setCreds(defaultCredentials);
840
+ }
841
+ if (out["AWS_REGION"] && !out["AWS_DEFAULT_REGION"]) out["AWS_DEFAULT_REGION"] = out["AWS_REGION"];
842
+ return out;
843
+ }
844
+ async function resolveHostDefaultCredentials(opts = {}) {
845
+ const name = assumedRoleRecorded() ? profileName(process.env, opts.profile) : opts.profile;
846
+ const key = `${assumedRoleRecorded() ? "noenv" : "chain"}:${name ?? ""}`;
847
+ const miss = chainMisses.get(key);
848
+ if (miss !== void 0 && Date.now() - miss < CHAIN_MISS_TTL_MS) return void 0;
849
+ let provider = chainProviders.get(key);
850
+ if (!provider) {
851
+ const { defaultProvider } = await import("@aws-sdk/credential-provider-node");
852
+ provider = defaultProvider(name ? { profile: name } : {});
853
+ chainProviders.set(key, provider);
854
+ }
855
+ try {
856
+ const c = await provider();
857
+ chainMisses.delete(key);
858
+ return {
859
+ accessKeyId: c.accessKeyId,
860
+ secretAccessKey: c.secretAccessKey,
861
+ ...c.sessionToken ? { sessionToken: c.sessionToken } : {}
862
+ };
863
+ } catch (err) {
864
+ chainMisses.set(key, Date.now());
865
+ getLogger().debug(`No credentials from the host default chain for workload containers: ${describeCredentialLoadFailure(err)}`);
866
+ return;
867
+ }
868
+ }
869
+ const CHAIN_MISS_TTL_MS = 6e4;
870
+ const chainProviders = /* @__PURE__ */ new Map();
871
+ const chainMisses = /* @__PURE__ */ new Map();
872
+ let active;
873
+ let exitHookInstalled = false;
874
+ function getActiveWorkloadAwsWiring() {
875
+ return active;
876
+ }
877
+ function setActiveWorkloadAwsWiring(wiring) {
878
+ if (active && active !== wiring) active.dispose();
879
+ active = wiring;
880
+ if (wiring && !exitHookInstalled) {
881
+ exitHookInstalled = true;
882
+ process.once("exit", () => active?.dispose());
883
+ }
884
+ }
885
+ function awsEmulatorEnvName() {
886
+ const { envPrefix } = getEmbedConfig();
887
+ return envPrefix === "CDKL" ? "CDK_LOCAL_AWS_EMULATOR" : `${envPrefix}_AWS_EMULATOR`;
888
+ }
889
+ function resolveAwsEmulatorOption(flag, env = process.env) {
890
+ if (typeof flag === "string" && flag !== "") return flag;
891
+ if (flag === true) return true;
892
+ const raw = (env[awsEmulatorEnvName()] ?? "").trim();
893
+ if (raw === "" || /^(0|false)$/i.test(raw)) return void 0;
894
+ return /^(1|true)$/i.test(raw) ? true : raw;
895
+ }
896
+ async function activateWorkloadAwsWiring(options) {
897
+ const wiring = await resolveWorkloadAwsWiring({
898
+ awsEmulator: resolveAwsEmulatorOption(options.awsEmulator),
899
+ caBundle: options.caBundle,
900
+ profile: options.profile
901
+ });
902
+ setActiveWorkloadAwsWiring(wiring);
903
+ if (wiring.mode === "emulator" && wiring.emulatorEndpoint) {
904
+ setAwsEndpointOverride({
905
+ endpoint: wiring.emulatorEndpoint.url,
906
+ ...wiring.caHostPath ? { caPem: readFileSync(wiring.caHostPath, "utf8") } : {},
907
+ ...wiring.emulatorCredentials ? { credentials: wiring.emulatorCredentials } : {}
908
+ });
909
+ getLogger().info(`Using AWS Emulator at ${wiring.emulatorEndpoint.url} for cdk-local's AWS calls and every workload container.`);
910
+ } else setAwsEndpointOverride(void 0);
911
+ return wiring;
912
+ }
913
+
914
+ //#endregion
915
+ export { warnWorkloadCredentialsStripped as A, formatAuthority as B, accountLookupStsClientConfig as C, readEnvCallerCredentials as D, deployAccountStsClientConfig as E, isProxyEnvConfigured as F, hostFromAuthority as H, proxyAwareFetch as I, setAwsEndpointOverride as L, workloadStsClientConfig as M, buildProxyClientConfig as N, recordAssumedRole as O, getAwsEndpointOverride as P, isLoopbackHostname as R, SECOND_ASSUME_MESSAGE as S, assumedRoleRecorded as T, formatHostForAuthority as V, resolveHostDefaultCredentials as _, activateWorkloadAwsWiring as a, workload_aws_wiring_exports as b, collectHostEndpointOverrides as c, getContainerCaBundlePath as d, parseAwsEndpoint as f, resolveAwsEmulatorOption as g, readProfileEndpointSettings as h, EMULATOR_SCRUBBED_ENV_KEYS as i, workloadClientConfig as j, resetWorkloadIdentity as k, effectiveLoopbackPorts as l, readEmulatorRunFiles as m, CA_TRUST_ENV_KEYS as n, applyWorkloadAwsWiringToEnv as o, probeAwsEmulatorHealth as p, DEFAULT_AWS_EMULATOR_URL as r, awsEmulatorEnvName as s, AUTH_OFF_PLACEHOLDER_CREDENTIALS as t, getActiveWorkloadAwsWiring as u, resolveWorkloadAwsWiring as v, applyWorkloadEnvCredentials as w, writeCaBundleFile as x, setActiveWorkloadAwsWiring as y, isWildcardHostname as z };
916
+ //# sourceMappingURL=workload-aws-wiring-BIxf0jtl.js.map