cdk-local 0.147.8 → 0.147.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +5 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -2
- package/dist/{local-studio-PCB6DpBn.js → local-studio-9eVA5PPS.js} +500 -22
- package/dist/local-studio-9eVA5PPS.js.map +1 -0
- package/dist/local-studio-BBA_8Xvk.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/local-studio-PCB6DpBn.js.map +0 -1
|
@@ -228,6 +228,395 @@ function buildStsClientConfig(args) {
|
|
|
228
228
|
};
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/local/credential-error.ts
|
|
233
|
+
/**
|
|
234
|
+
* Rendering an AWS SDK failure into a log line cdk-local is willing to print
|
|
235
|
+
* at DEFAULT level (issues #564, #570).
|
|
236
|
+
*
|
|
237
|
+
* # Why a shared module
|
|
238
|
+
*
|
|
239
|
+
* Issue #564 settled the policy for one site — the credential-chain failure
|
|
240
|
+
* in {@link file://./sigv4-verify.ts} — and #570 found the same shape at nine
|
|
241
|
+
* more, spread across five `src/cli/commands/*.ts` files. Every one of them
|
|
242
|
+
* relays a third-party error's `message` into a `logger.warn`, so they share
|
|
243
|
+
* one question and must not grow nine answers to it.
|
|
244
|
+
*
|
|
245
|
+
* SCOPE, stated so a later sweep finds a decision rather than an oversight:
|
|
246
|
+
* this module governs those nine plus sigv4-verify's one, and its
|
|
247
|
+
* {@link flattenToOneLine} additionally covers every other wire-derived value
|
|
248
|
+
* printed on those lines (the role ARN, on the failure AND success paths). It
|
|
249
|
+
* does NOT yet govern the AWS SDK error relays elsewhere under
|
|
250
|
+
* `src/local/**` — notably
|
|
251
|
+
* `formatAwsErrorForWarn` (`cfn-local-state-provider.ts`, six warn sites and
|
|
252
|
+
* one non-warn caller)
|
|
253
|
+
* and `formatSsmError` (`ssm-parameter-resolver.ts`), which still print an
|
|
254
|
+
* UNCLAMPED wire-derived `err.name`. Those are enumerated and tracked in
|
|
255
|
+
* issue #579; they were left out here so a cross-cutting refactor of eight
|
|
256
|
+
* more files would not share a review with the policy that justifies it.
|
|
257
|
+
*
|
|
258
|
+
* # The two axes that decide it
|
|
259
|
+
*
|
|
260
|
+
* PROVENANCE alone says relay: a credential-chain error is about the
|
|
261
|
+
* developer's own machine configuration, not something cdk-local fetched out
|
|
262
|
+
* of a secret store (issue #555's criterion). Two further axes overrule it:
|
|
263
|
+
*
|
|
264
|
+
* LEVEL — these are `warn`, so they print on a plain `cdkl start-api` /
|
|
265
|
+
* `cdkl invoke` run rather than only under `--verbose`, and `cdkl studio`
|
|
266
|
+
* mirrors a serve child's output into a log ring it serves over HTTP.
|
|
267
|
+
* Everybody sees a `warn`; only someone who asked sees a `debug`.
|
|
268
|
+
*
|
|
269
|
+
* RECONSTRUCTION — what can reach the string is not a hint about a secret,
|
|
270
|
+
* it is the secret. `@aws-sdk/credential-provider-process` builds its
|
|
271
|
+
* failure as `new CredentialsProviderError(error.message)` where `error` is
|
|
272
|
+
* the rejection of `promisify(child_process.exec)`, i.e. Node's
|
|
273
|
+
* `Command failed: <command line>\n<stderr>`, and a passphrase written on a
|
|
274
|
+
* `credential_process` command line is an ordinary thing to have. (Verified
|
|
275
|
+
* at `@aws-sdk/credential-provider-process@3.972.{39,41,43}`
|
|
276
|
+
* `dist-cjs/index.js:56` in this repo's tree.)
|
|
277
|
+
*
|
|
278
|
+
* # Where these sites DIFFER from sigv4-verify's, and why the answer differs
|
|
279
|
+
*
|
|
280
|
+
* {@link file://./sigv4-verify.ts}'s `catch` wraps `client.config.credentials()`
|
|
281
|
+
* and nothing else: credential-chain resolution, with no AWS operation
|
|
282
|
+
* cdk-local asked for. Nothing actionable is lost by withholding all of it,
|
|
283
|
+
* so that site withholds unconditionally and keeps the text at `debug`.
|
|
284
|
+
*
|
|
285
|
+
* The #570 sites wrap an SDK call cdk-local DID make — STS
|
|
286
|
+
* `GetCallerIdentity` or `AssumeRole` — so two unrelated error populations
|
|
287
|
+
* land in one `catch`:
|
|
288
|
+
*
|
|
289
|
+
* 1. the credential chain failed before the request went out, which is
|
|
290
|
+
* #564's population exactly, and
|
|
291
|
+
* 2. STS answered with a modeled service exception — `ExpiredTokenException`,
|
|
292
|
+
* `AccessDenied` — whose message IS the diagnosis the user needs, and
|
|
293
|
+
* which never went near `credential_process`. (Spelled as the SDK
|
|
294
|
+
* spells them: `@aws-sdk/client-sts` models `ExpiredTokenException`
|
|
295
|
+
* (`dist-cjs/models/errors.js:6`), while `AccessDenied` is unmodeled and
|
|
296
|
+
* arrives as the wire code verbatim — which is exactly why the name is
|
|
297
|
+
* clamped rather than trusted.)
|
|
298
|
+
*
|
|
299
|
+
* Blanket-withholding would turn the single commonest failure of these
|
|
300
|
+
* commands (`ExpiredTokenException: The security token included in the
|
|
301
|
+
* request is expired`) into a class name and a character count. So the split
|
|
302
|
+
* is by population, via {@link describeAwsFailureForWarn}.
|
|
303
|
+
*
|
|
304
|
+
* # The safe state is defined POSITIVELY
|
|
305
|
+
*
|
|
306
|
+
* The discriminator is not a deny-list of bad error shapes — #564 rejected
|
|
307
|
+
* that reasoning for the `Command failed:` first line, and it loses the same
|
|
308
|
+
* race here. It is the SDK's own structural test for "this came off the wire
|
|
309
|
+
* as a modeled service error" ({@link isAwsServiceException}). Anything that
|
|
310
|
+
* does not match — a chain failure, a socket error, a bare `throw 'x'` — is
|
|
311
|
+
* withheld. An unrecognised shape therefore fails toward withholding.
|
|
312
|
+
*
|
|
313
|
+
* A hostile endpoint cannot steer the discriminator into disclosing MORE.
|
|
314
|
+
* `$fault` / `$metadata` are set by the SDK from the HTTP response, not from
|
|
315
|
+
* anything the body names, so forging `x-amzn-errortype:
|
|
316
|
+
* CredentialsProviderError` only changes `err.name` — the response is still a
|
|
317
|
+
* service response, so the error stays on the KEPT branch and its message is
|
|
318
|
+
* still the sanitized, capped one the endpoint could have sent under any
|
|
319
|
+
* other name. What the endpoint cannot do is move a `credential_process`
|
|
320
|
+
* command line onto that branch: that text originates locally, inside a
|
|
321
|
+
* `CredentialsProviderError` that never acquires `$fault`.
|
|
322
|
+
*
|
|
323
|
+
* # What this does NOT close
|
|
324
|
+
*
|
|
325
|
+
* A single-LINE forged string still reaches readers other than a human.
|
|
326
|
+
* `cdkl studio` matches every serve-child stdout line against an unanchored
|
|
327
|
+
* ready-line regex and proxies to the URL it captures, so a message
|
|
328
|
+
* containing `Server listening on http://...` can redirect the studio proxy.
|
|
329
|
+
* That is not fixed here — the sanitizer bounds the line, it does not stop a
|
|
330
|
+
* machine from reading it — and it predates this change (an ordinary handler
|
|
331
|
+
* log line trips the same matcher). Tracked in issue #578.
|
|
332
|
+
*/
|
|
333
|
+
/**
|
|
334
|
+
* Longest service-exception message relayed into a `warn` line, in
|
|
335
|
+
* characters.
|
|
336
|
+
*
|
|
337
|
+
* A modeled STS error's message is WIRE-DERIVED — the SDK reads it out of the
|
|
338
|
+
* response body — so its length is not cdk-local's to assume. Real ones run
|
|
339
|
+
* to roughly 150 characters (`AccessDenied: User: arn:... is not authorized to
|
|
340
|
+
* perform: sts:AssumeRole on resource: arn:...`), and the policy-quoting ones
|
|
341
|
+
* are the longest, so the cap is set well above that: it exists to stop an
|
|
342
|
+
* unbounded body from becoming an unbounded log line, not to trim ordinary
|
|
343
|
+
* AWS text, which must survive intact or the branch buys nothing.
|
|
344
|
+
*
|
|
345
|
+
* Truncation is announced with the true length (see
|
|
346
|
+
* {@link sanitizeServiceExceptionMessage}) so a capped line is never mistaken
|
|
347
|
+
* for a complete one.
|
|
348
|
+
*/
|
|
349
|
+
const SERVICE_MESSAGE_MAX = 512;
|
|
350
|
+
/**
|
|
351
|
+
* Total stringification of a thrown value's message.
|
|
352
|
+
*
|
|
353
|
+
* `String(err)` is NOT total. That throw would escape the `catch` it is
|
|
354
|
+
* called from and turn a warn-and-continue branch into a hard failure — a 500
|
|
355
|
+
* from the SigV4 authorizer in #564's testing, and a dead `cdkl invoke` here.
|
|
356
|
+
* One helper rather than an expression repeated per site, so the length
|
|
357
|
+
* reported in a `warn` and the text printed at `debug` can never describe
|
|
358
|
+
* different strings.
|
|
359
|
+
*
|
|
360
|
+
* CORRECTION to #564, measured on this repo's Node 24: `String(aSymbol)`
|
|
361
|
+
* does NOT throw — it returns `'Symbol(x)'`, and it is template
|
|
362
|
+
* INTERPOLATION (`` `${aSymbol}` ``) that raises
|
|
363
|
+
* `TypeError: Cannot convert a Symbol value to a string`. Since both the old
|
|
364
|
+
* code and this helper call `String()` explicitly, a `Symbol` throw was never
|
|
365
|
+
* one of the reachable cases. The two that ARE reachable, both verified:
|
|
366
|
+
* an object with a null prototype (`TypeError: Cannot convert object to
|
|
367
|
+
* primitive value`, because it has no `toString`), and any value whose
|
|
368
|
+
* `toString` / `Symbol.toPrimitive` throws — which a hostile or merely buggy
|
|
369
|
+
* third-party error object is free to do.
|
|
370
|
+
*
|
|
371
|
+
* Named for what it does rather than for one caller: #564 shipped it as
|
|
372
|
+
* `stringifyCredentialLoadFailure`, and #570 gave it a second population
|
|
373
|
+
* (service exceptions) for which that name was simply wrong.
|
|
374
|
+
*/
|
|
375
|
+
function stringifyThrown(err) {
|
|
376
|
+
try {
|
|
377
|
+
return err instanceof Error ? String(err.message) : String(err);
|
|
378
|
+
} catch {
|
|
379
|
+
return "[unstringifiable throw]";
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* The throwing class's name, clamped to something no input can forge.
|
|
384
|
+
*
|
|
385
|
+
* `err.name` is NOT input-independent, which is the whole reason this is a
|
|
386
|
+
* function and not an interpolation. For an AWS service exception it is
|
|
387
|
+
* WIRE-DERIVED: `@aws-sdk/core` builds it from the `x-amzn-errortype` header
|
|
388
|
+
* / the body's `code` / `__type` through `sanitizeErrorCode`, which splits on
|
|
389
|
+
* ',' ':' and '#' and does nothing else — no length cap, no newline stripping
|
|
390
|
+
* (read at `@aws-sdk/core@3.974.13` `protocols/index.js:324`). Such an
|
|
391
|
+
* exception reaches these call sites, because `credential-provider-ini` calls
|
|
392
|
+
* the STS `roleAssumer` unwrapped and because the #570 sites invoke STS
|
|
393
|
+
* directly. So a hostile or hijacked credential endpoint
|
|
394
|
+
* (`AWS_CONTAINER_CREDENTIALS_FULL_URI`, a redirected IMDS) answering
|
|
395
|
+
* `x-amzn-errortype: Foo\nWARN: signature verified` could FORGE log lines
|
|
396
|
+
* into the `warn` stream — and into the studio ring served over HTTP.
|
|
397
|
+
*
|
|
398
|
+
* A bare identifier of at most 64 characters is what every real class name is
|
|
399
|
+
* and what no injected value can be; anything else degrades to `'unknown'`,
|
|
400
|
+
* which also covers a non-`Error` throw, so the field never names a class the
|
|
401
|
+
* throw was not.
|
|
402
|
+
*
|
|
403
|
+
* Note the WRONG fix: `err.name.slice(0, 64)` keeps the newline, so the
|
|
404
|
+
* forgery survives truncation.
|
|
405
|
+
*/
|
|
406
|
+
function clampErrorName(err) {
|
|
407
|
+
let rawKind;
|
|
408
|
+
try {
|
|
409
|
+
rawKind = err instanceof Error ? err.name : "unknown";
|
|
410
|
+
} catch {
|
|
411
|
+
return "unknown";
|
|
412
|
+
}
|
|
413
|
+
return typeof rawKind === "string" && /^[A-Za-z0-9_.-]{1,64}$/.test(rawKind) ? rawKind : "unknown";
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* The thrown value's `code`, when it is a bare identifier, else `undefined`.
|
|
417
|
+
*
|
|
418
|
+
* This exists because withholding by class name alone is not discriminating
|
|
419
|
+
* enough for the population that actually reaches the withheld branch most
|
|
420
|
+
* often. `Region is missing`, `getaddrinfo ENOTFOUND sts.<region>.amazonaws.com`
|
|
421
|
+
* and `connect ETIMEDOUT 169.254.169.254:80` all arrive as a plain `Error`, so
|
|
422
|
+
* all three render as `Error; N-character message withheld` and the reader
|
|
423
|
+
* cannot tell a misconfiguration from an unreachable endpoint.
|
|
424
|
+
*
|
|
425
|
+
* Node sets `code` on its system errors (`ENOTFOUND`, `ETIMEDOUT`,
|
|
426
|
+
* `ECONNREFUSED`) and there it is a fixed enum chosen by the runtime. It is
|
|
427
|
+
* NOT input-independent in general, though, and the earlier draft of this note
|
|
428
|
+
* claimed it was: `@smithy/core`'s `decorateServiceException`
|
|
429
|
+
* (`dist-cjs/submodules/client/index.js:795-802`) copies every key of the
|
|
430
|
+
* PARSED RESPONSE BODY onto the exception, so an unmodeled error from a
|
|
431
|
+
* hostile endpoint can carry a `code` of its choosing. The clamp is therefore
|
|
432
|
+
* load-bearing rather than belt-and-braces, exactly as it is for
|
|
433
|
+
* {@link clampErrorName}: what survives is at most 64 characters matching
|
|
434
|
+
* `[A-Za-z0-9_.-]`, which cannot forge a line, and which is the same residue
|
|
435
|
+
* the class name already accepts.
|
|
436
|
+
*
|
|
437
|
+
* `undefined` rather than `'unknown'` when there is none, so the caller can
|
|
438
|
+
* omit the field entirely instead of printing a placeholder that says less
|
|
439
|
+
* than nothing.
|
|
440
|
+
*/
|
|
441
|
+
function clampErrorCode(err) {
|
|
442
|
+
if (!err || typeof err !== "object") return void 0;
|
|
443
|
+
let raw;
|
|
444
|
+
try {
|
|
445
|
+
raw = err.code;
|
|
446
|
+
} catch {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
if (typeof raw !== "string") return void 0;
|
|
450
|
+
return /^[A-Za-z0-9_.-]{1,64}$/.test(raw) ? raw : void 0;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Is `err` a modeled AWS service exception — i.e. did the SDK parse it out of
|
|
454
|
+
* a service RESPONSE, rather than raise it while assembling the request?
|
|
455
|
+
*
|
|
456
|
+
* This is `ServiceException.isInstance`'s own structural test, reproduced
|
|
457
|
+
* rather than imported: cdk-local loads `@aws-sdk/client-sts` lazily at every
|
|
458
|
+
* one of these call sites (a dynamic `import()` inside the `try`), so taking
|
|
459
|
+
* a static dependency on `@smithy/core` purely to type-test an error would
|
|
460
|
+
* pull the SDK into the CLI's startup path. The structural form also keeps
|
|
461
|
+
* working across the several `@smithy/core` copies pnpm resolves in this
|
|
462
|
+
* tree, where an `instanceof` against one copy's class fails for an error
|
|
463
|
+
* minted by another.
|
|
464
|
+
*
|
|
465
|
+
* The test is deliberately the SDK's and not a name list: a name list would
|
|
466
|
+
* have to be extended for every new STS error code, and a missing entry would
|
|
467
|
+
* fail toward DISCLOSING less, which is safe, but also toward hiding the
|
|
468
|
+
* actionable message, which is the regression this split exists to avoid.
|
|
469
|
+
*/
|
|
470
|
+
function isAwsServiceException(err) {
|
|
471
|
+
if (!err || typeof err !== "object") return false;
|
|
472
|
+
const candidate = err;
|
|
473
|
+
try {
|
|
474
|
+
return Boolean(candidate.$metadata) && (candidate.$fault === "client" || candidate.$fault === "server");
|
|
475
|
+
} catch {
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Replace every character that could make one emitted line render as more than
|
|
481
|
+
* one line, or render in an order it was not written in, with a space.
|
|
482
|
+
*
|
|
483
|
+
* Four Unicode categories, each measured rather than assumed (see the fixture
|
|
484
|
+
* in `tests/unit/local/credential-error.test.ts`):
|
|
485
|
+
*
|
|
486
|
+
* - `Cc` — the C0/C1 controls, which is `\n` / `\r` (a forged extra line in
|
|
487
|
+
* the studio ring) and `\x1b` (an ANSI escape in a terminal). U+0085 NEL
|
|
488
|
+
* lives here too.
|
|
489
|
+
* - `Cf` — the format characters, which is U+202E RIGHT-TO-LEFT OVERRIDE and
|
|
490
|
+
* friends: they forge how the REST of the line reads. The cost is that a
|
|
491
|
+
* ZWJ inside an emoji or an Indic cluster is replaced too; an AWS error
|
|
492
|
+
* message is ASCII, so that is a trade with no observed downside.
|
|
493
|
+
* - `Zl` / `Zp` — U+2028 and U+2029. Neither is in `Cc` or `Cf`, and both are
|
|
494
|
+
* forced line breaks in the studio UI's `<pre>`, so leaving them out would
|
|
495
|
+
* have left the forged-line case open in HTML while closing it in a
|
|
496
|
+
* terminal.
|
|
497
|
+
* - `Cs` — a LONE surrogate, which is not a character at all and breaks JSON
|
|
498
|
+
* encoding of the log event. With the `u` flag a well-formed pair is one
|
|
499
|
+
* code point and does NOT match, so emoji survive.
|
|
500
|
+
*
|
|
501
|
+
* Used by both branches of {@link describeAwsFailureForWarn} — the kept
|
|
502
|
+
* message, and the `debug` line carrying the withheld one, because the `debug`
|
|
503
|
+
* stream is the SAME studio ring under `--verbose`, so a text unsafe to put on
|
|
504
|
+
* a line at `warn` is unsafe at `debug` — and, since issue #570's review
|
|
505
|
+
* rounds, by every OTHER wire-derived value that lands on one of these lines:
|
|
506
|
+
* `sigv4-verify`'s own `debug` line, and the role ARN at the four warn sites
|
|
507
|
+
* plus the five `info` / `debug` sites that print an ARN resolved from a live
|
|
508
|
+
* `GetFunctionConfiguration` / `GetAgentRuntime` response. The last group is
|
|
509
|
+
* the more reachable one — it fires on SUCCESS.
|
|
510
|
+
*/
|
|
511
|
+
function flattenToOneLine(message) {
|
|
512
|
+
return message.replace(/[\p{Cc}\p{Cf}\p{Zl}\p{Zp}\p{Cs}]/gu, " ");
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Render a wire-derived service message safe to put on one log line.
|
|
516
|
+
*
|
|
517
|
+
* Two properties, and both are about the LINE rather than about secrecy — the
|
|
518
|
+
* message itself is already judged safe to print by the time this is called:
|
|
519
|
+
*
|
|
520
|
+
* - No line breaks and no rendering-direction control, via
|
|
521
|
+
* {@link flattenToOneLine}.
|
|
522
|
+
* - Bounded length, with the true length named when it is exceeded. The
|
|
523
|
+
* suffix names the character count of the SANITIZED message rather than
|
|
524
|
+
* of the raw one, because the sanitized string is what the truncated
|
|
525
|
+
* prefix is a prefix OF; quoting the raw length would describe a string
|
|
526
|
+
* the reader can never see.
|
|
527
|
+
*
|
|
528
|
+
* The cut is made on CODE POINTS rather than UTF-16 units, so a truncation
|
|
529
|
+
* landing inside an astral character cannot emit half of a surrogate pair. The
|
|
530
|
+
* count in the suffix is the code-point count for the same reason: the prefix
|
|
531
|
+
* and the number must describe the same string.
|
|
532
|
+
*/
|
|
533
|
+
function sanitizeServiceExceptionMessage(message) {
|
|
534
|
+
const points = [...flattenToOneLine(message)];
|
|
535
|
+
if (points.length <= SERVICE_MESSAGE_MAX) return points.join("");
|
|
536
|
+
return `${points.slice(0, SERVICE_MESSAGE_MAX).join("")}[... truncated; ${points.length}-character message]`;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Describe a credential-chain failure for a default-level log line WITHOUT
|
|
540
|
+
* relaying the chain's own message (issue #564).
|
|
541
|
+
*
|
|
542
|
+
* What is reported instead is input-INDEPENDENT: the clamped class name (see
|
|
543
|
+
* {@link clampErrorName}), which is the same discriminator
|
|
544
|
+
* `ecs-secrets-resolver.ts` reports for the JSON parse failure it must not
|
|
545
|
+
* echo, plus the clamped {@link clampErrorCode} when the throw carries one.
|
|
546
|
+
*
|
|
547
|
+
* Withholding is NOT free, and the cost lands on cdk-local's own text as well
|
|
548
|
+
* as on the SDK's: `role-arn.ts`'s
|
|
549
|
+
* `AssumeRole(<arn>) returned no usable credentials.` is a plain `Error` with
|
|
550
|
+
* no `$fault`, so it is withheld like any other. That is a real diagnostic
|
|
551
|
+
* loss, accepted because the alternative — an allow-list of messages that may
|
|
552
|
+
* print — is the deny-list this design rejects, wearing the other sign. The
|
|
553
|
+
* fix is to make cdk-local's own throws identifiable rather than to guess at
|
|
554
|
+
* their text; it is not done here, and is noted in issue #579.
|
|
555
|
+
*
|
|
556
|
+
* The LENGTH is reported, unlike in `ecs-secrets-resolver.ts`, and the
|
|
557
|
+
* difference is deliberate: there the user already knows which secret it is
|
|
558
|
+
* and can read the value at its source, so a character count would be
|
|
559
|
+
* disclosure buying nothing. Here the user cannot see the withheld message at
|
|
560
|
+
* all, and the count is what separates a one-line
|
|
561
|
+
* `Could not load credentials from any providers` (45 characters, measured
|
|
562
|
+
* against `@aws-sdk/credential-provider-node@3.972.44` `dist-cjs/index.js:144`)
|
|
563
|
+
* from a multi-hundred-character `Command failed:` dump — which is what tells
|
|
564
|
+
* them whether their `credential_process` even ran.
|
|
565
|
+
*
|
|
566
|
+
* The count is a side channel, and a narrow one: against a KNOWN
|
|
567
|
+
* `credential_process` template the number is `constant + len(passphrase)`, so
|
|
568
|
+
* it yields the passphrase's LENGTH. That is accepted rather than overlooked.
|
|
569
|
+
* It buys the one thing the user cannot otherwise see, the `Command failed:`
|
|
570
|
+
* dump is not reachable on today's SDK versions anyway, and bucketing the
|
|
571
|
+
* number would blur exactly the boilerplate-vs-dump distinction the field
|
|
572
|
+
* exists for.
|
|
573
|
+
*/
|
|
574
|
+
function describeCredentialLoadFailure(err) {
|
|
575
|
+
const code = clampErrorCode(err);
|
|
576
|
+
return `${code === void 0 ? clampErrorName(err) : `${clampErrorName(err)} ${code}`}; ${stringifyThrown(err).length}-character message withheld, logged at debug level under --verbose`;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Render an AWS SDK call failure for a `logger.warn` line, and emit the
|
|
580
|
+
* withheld text at `debug` when it is withheld (issue #570).
|
|
581
|
+
*
|
|
582
|
+
* `operation` names the call for the `debug` line — e.g.
|
|
583
|
+
* `'STS GetCallerIdentity'`. It is cdk-local's own literal at every call
|
|
584
|
+
* site, never anything read off an error or a response.
|
|
585
|
+
*
|
|
586
|
+
* # Why this emits the `debug` line itself
|
|
587
|
+
*
|
|
588
|
+
* Because the alternative is nine call sites each free to withhold a message
|
|
589
|
+
* and forget to print it anywhere. The pairing is the invariant — "withheld
|
|
590
|
+
* at `warn`" is only acceptable while "in full at `debug`" holds — so it
|
|
591
|
+
* lives in one function rather than in a convention nine sites must keep. A
|
|
592
|
+
* tenth site gets it for free.
|
|
593
|
+
*
|
|
594
|
+
* The `debug` line fires ONLY on the withheld branch. On the service-exception
|
|
595
|
+
* branch the `warn` already carries the message, and repeating it verbatim one
|
|
596
|
+
* level down would say nothing the reader did not just read.
|
|
597
|
+
*
|
|
598
|
+
* It is FLATTENED (not capped). Flattened because the `debug` stream is not a
|
|
599
|
+
* private channel: it is the same stdout `cdkl studio` mirrors into the log
|
|
600
|
+
* ring it serves over HTTP, so a `\n` in the withheld text would forge a line
|
|
601
|
+
* there exactly as it would at `warn`. Not capped, because being able to read
|
|
602
|
+
* the whole withheld message is the entire reason the line exists — the
|
|
603
|
+
* `warn`'s character count is what tells the reader how much they are about to
|
|
604
|
+
* see. Note that this puts the full text into that ring for a
|
|
605
|
+
* `--verbose` studio run; see `docs/troubleshooting.md`.
|
|
606
|
+
*
|
|
607
|
+
* ORDERING: the `debug` line is emitted when THIS function runs, which is
|
|
608
|
+
* before the `warn` at every site — inline in the `warn`'s template at eight of
|
|
609
|
+
* them, and a couple of statements earlier at the one that hoists the result
|
|
610
|
+
* into a `const reason`. Either way it prints immediately ABOVE the `warn` that
|
|
611
|
+
* refers to it under `--verbose`. Left as is: restructuring every call site to
|
|
612
|
+
* log afterwards would buy an ordering nobody reads top-down anyway.
|
|
613
|
+
*/
|
|
614
|
+
function describeAwsFailureForWarn(err, operation) {
|
|
615
|
+
if (isAwsServiceException(err)) return `${clampErrorName(err)}: ${sanitizeServiceExceptionMessage(stringifyThrown(err))}`;
|
|
616
|
+
getLogger().debug(`${operation}: the AWS SDK's own failure message was: ${flattenToOneLine(stringifyThrown(err))}`);
|
|
617
|
+
return describeCredentialLoadFailure(err);
|
|
618
|
+
}
|
|
619
|
+
|
|
231
620
|
//#endregion
|
|
232
621
|
//#region src/utils/role-arn.ts
|
|
233
622
|
/**
|
|
@@ -13421,7 +13810,8 @@ async function verifySigV4(req, loadCredentials, opts = {}) {
|
|
|
13421
13810
|
try {
|
|
13422
13811
|
local = await loadCredentials();
|
|
13423
13812
|
} catch (err) {
|
|
13424
|
-
|
|
13813
|
+
logger.debug(`AWS_IAM authorizer: the AWS credential chain's own failure message was: ${flattenToOneLine(stringifyThrown(err))}`);
|
|
13814
|
+
const reason = describeCredentialLoadFailure(err);
|
|
13425
13815
|
const { sigV4StrictByDefault, sigV4OptFlag: optFlag } = getEmbedConfig();
|
|
13426
13816
|
if (opts.strict && !opts.oacFronted) {
|
|
13427
13817
|
logger.warn(sigV4StrictByDefault ? `AWS_IAM authorizer: could not resolve local AWS credentials (${reason}), so the request's SigV4 signature cannot be verified. cdk-local denies unverifiable IAM requests by default; pass ${optFlag} to warn-and-pass, or configure AWS credentials cdk-local can read.` : `AWS_IAM authorizer: could not resolve local AWS credentials (${reason}), so the request's SigV4 signature cannot be verified. ${optFlag} is set, so cdk-local denies unverifiable IAM requests; remove ${optFlag} to warn-and-pass (the default), or configure AWS credentials cdk-local can read.`);
|
|
@@ -13439,12 +13829,12 @@ async function verifySigV4(req, loadCredentials, opts = {}) {
|
|
|
13439
13829
|
}
|
|
13440
13830
|
if (local.accessKeyId.toLowerCase() !== parsed.credentialAccessKeyId.toLowerCase()) {
|
|
13441
13831
|
const warned = opts.warnedForeignIds;
|
|
13442
|
-
const dedupKey = parsed.credentialAccessKeyId.toLowerCase();
|
|
13832
|
+
const dedupKey = createHash("sha256").update(parsed.credentialAccessKeyId.toLowerCase()).digest("hex");
|
|
13443
13833
|
const { sigV4StrictByDefault, sigV4OptFlag: optFlag } = getEmbedConfig();
|
|
13444
13834
|
if (opts.strict && !opts.oacFronted) {
|
|
13445
13835
|
if (!warned || !warned.has(dedupKey)) {
|
|
13446
13836
|
logger.warn(sigV4StrictByDefault ? `AWS_IAM authorizer: request signed with access-key-id '${redactAuthorizationSegment(parsed.credentialAccessKeyId)}', which differs from the AWS credentials cdk-local resolved locally — SigV4 (HMAC / shared-secret) can only be verified with the signer's own credentials, never a federated / Cognito Identity Pool / cross-account signer's. cdk-local denies it by default; pass ${optFlag} to warn-and-pass, or sign the request with the same credentials cdk-local resolves locally.` : `AWS_IAM authorizer: request signed with access-key-id '${redactAuthorizationSegment(parsed.credentialAccessKeyId)}', which differs from the AWS credentials cdk-local resolved locally — SigV4 (HMAC / shared-secret) can only be verified with the signer's own credentials, never a federated / Cognito Identity Pool / cross-account signer's. ${optFlag} is set, so cdk-local denies it; remove ${optFlag} to warn-and-pass (the default), or sign the request with the same credentials cdk-local resolves locally.`);
|
|
13447
|
-
warned
|
|
13837
|
+
rememberWarnedForeignId(warned, dedupKey);
|
|
13448
13838
|
}
|
|
13449
13839
|
return {
|
|
13450
13840
|
allow: false,
|
|
@@ -13453,7 +13843,7 @@ async function verifySigV4(req, loadCredentials, opts = {}) {
|
|
|
13453
13843
|
}
|
|
13454
13844
|
if (!warned || !warned.has(dedupKey)) {
|
|
13455
13845
|
logger.warn(opts.oacFronted ? `AWS_IAM authorizer: Function URL is fronted by CloudFront OAC — in production CloudFront re-signs the origin request, so the local client's signature (access-key-id '${redactAuthorizationSegment(parsed.credentialAccessKeyId)}') cannot be verified. Passing through with unverified principalId 'unverified-foreign-identity'. Do NOT trust event.requestContext.authorizer.principalId in handler code.` : sigV4StrictByDefault ? `AWS_IAM authorizer: request signed with access-key-id '${redactAuthorizationSegment(parsed.credentialAccessKeyId)}', a federated / Cognito Identity Pool / cross-account signer cdk-local cannot verify locally (SigV4 is an HMAC shared-secret signature; the deployed API Gateway verifies it because AWS holds the secret). ${optFlag} is set; passing through with unverified principalId 'unverified-foreign-identity'. Do NOT trust event.requestContext.authorizer.principalId in handler code.` : `AWS_IAM authorizer: request signed with access-key-id '${redactAuthorizationSegment(parsed.credentialAccessKeyId)}', a federated / Cognito Identity Pool / cross-account signer cdk-local cannot verify locally (SigV4 is an HMAC shared-secret signature; the deployed API Gateway verifies it because AWS holds the secret). Passing through with unverified principalId 'unverified-foreign-identity' — cdk-local's default for unverifiable IAM requests; pass ${optFlag} to deny instead. Do NOT trust event.requestContext.authorizer.principalId in handler code.`);
|
|
13456
|
-
warned
|
|
13846
|
+
rememberWarnedForeignId(warned, dedupKey);
|
|
13457
13847
|
}
|
|
13458
13848
|
return {
|
|
13459
13849
|
allow: true,
|
|
@@ -13579,6 +13969,57 @@ function redactSignature(signature) {
|
|
|
13579
13969
|
return signature;
|
|
13580
13970
|
}
|
|
13581
13971
|
/**
|
|
13972
|
+
* How many distinct foreign access-key-ids {@link verifySigV4}'s warn-dedup
|
|
13973
|
+
* set retains (issue #561).
|
|
13974
|
+
*
|
|
13975
|
+
* The legitimate population is tiny — a session sees one federated / Cognito
|
|
13976
|
+
* Identity Pool / cross-account signer, occasionally a handful — so 256
|
|
13977
|
+
* leaves two orders of magnitude of headroom over any real use while holding
|
|
13978
|
+
* the set at 256 entries of exactly 64 hex characters whatever a caller
|
|
13979
|
+
* sends, because {@link verifySigV4} hashes the id before it becomes a key.
|
|
13980
|
+
*
|
|
13981
|
+
* `docs/local-emulation.md` states this number to users ("the 256 most
|
|
13982
|
+
* recently warned ids"); change both together.
|
|
13983
|
+
*/
|
|
13984
|
+
const FOREIGN_ID_DEDUP_MAX = 256;
|
|
13985
|
+
/**
|
|
13986
|
+
* Record that the foreign-access-key-id warning has been emitted for
|
|
13987
|
+
* `dedupKey`, evicting oldest-first so the set cannot grow without bound
|
|
13988
|
+
* (issue #561).
|
|
13989
|
+
*
|
|
13990
|
+
* # Why eviction, and not "stop warning past the cap"
|
|
13991
|
+
*
|
|
13992
|
+
* The set's only power is SUPPRESSION — an entry present means the warning
|
|
13993
|
+
* is skipped — so the two candidate policies differ in the DIRECTION they
|
|
13994
|
+
* fail. Evicting an entry can only ever cause a REPEAT warning, which is
|
|
13995
|
+
* precisely the un-deduped behaviour this code had before the dedup existed:
|
|
13996
|
+
* noisier, never quieter. Capping by refusing to warn once the set is full
|
|
13997
|
+
* would instead silence the (cap+1)-th distinct signer, and that signer is
|
|
13998
|
+
* every bit as likely to be the real federated identity the developer needs
|
|
13999
|
+
* told about as it is to be a prober's next value. A warning that never
|
|
14000
|
+
* arrives is a worse failure than a set that grows, so the bound is put
|
|
14001
|
+
* where it cannot suppress anything.
|
|
14002
|
+
*
|
|
14003
|
+
* `Set` iterates in insertion order, so `values().next()` is the oldest
|
|
14004
|
+
* entry and this is FIFO. It is a loop rather than a single `delete` so a
|
|
14005
|
+
* set handed in already over the cap is brought back under it.
|
|
14006
|
+
*
|
|
14007
|
+
* What this does NOT fix: a client looping over DISTINCT ids still draws one
|
|
14008
|
+
* warn line per probe. Distinct ids defeat the dedup whether or not the set
|
|
14009
|
+
* is bounded, and closing that half would need suppression — the direction
|
|
14010
|
+
* ruled out above. The bound here is on memory only.
|
|
14011
|
+
*/
|
|
14012
|
+
function rememberWarnedForeignId(warned, dedupKey) {
|
|
14013
|
+
if (!warned) return;
|
|
14014
|
+
if (warned.has(dedupKey)) return;
|
|
14015
|
+
while (warned.size >= FOREIGN_ID_DEDUP_MAX) {
|
|
14016
|
+
const oldest = warned.values().next();
|
|
14017
|
+
if (oldest.done === true) break;
|
|
14018
|
+
warned.delete(oldest.value);
|
|
14019
|
+
}
|
|
14020
|
+
warned.add(dedupKey);
|
|
14021
|
+
}
|
|
14022
|
+
/**
|
|
13582
14023
|
* Parse `AWS4-HMAC-SHA256 Credential=..., SignedHeaders=..., Signature=...`.
|
|
13583
14024
|
* Rejects every other shape (including legacy `AWS4-HMAC-SHA256-...`
|
|
13584
14025
|
* variants and HTTP/1.0-style multi-line values).
|
|
@@ -16683,7 +17124,7 @@ function resolveStartApiAssumeRoleArn(args) {
|
|
|
16683
17124
|
if (stateBundle) {
|
|
16684
17125
|
const fromState = resolveExecutionRoleArnFromState(stateBundle.state, logicalId);
|
|
16685
17126
|
if (fromState) {
|
|
16686
|
-
getLogger().info(`--assume-role: auto-resolved execution role for '${logicalId}' from state: ${fromState}`);
|
|
17127
|
+
getLogger().info(`--assume-role: auto-resolved execution role for '${logicalId}' from state: ${flattenToOneLine(fromState)}`);
|
|
16687
17128
|
return fromState;
|
|
16688
17129
|
}
|
|
16689
17130
|
}
|
|
@@ -17497,6 +17938,11 @@ async function loadStateForRoutedStacks(stacks, routes, routesWithAuth, options,
|
|
|
17497
17938
|
*
|
|
17498
17939
|
* Region precedence: `--region` > `AWS_REGION` > `AWS_DEFAULT_REGION` >
|
|
17499
17940
|
* the state record's region (returned by the active `LocalStateProvider`).
|
|
17941
|
+
*
|
|
17942
|
+
* Exported so the issue #570 site-level test can drive the STS failure
|
|
17943
|
+
* branch with a mocked STS client. A helper being correct says nothing about
|
|
17944
|
+
* whether a given site actually routes through it, so each of the nine
|
|
17945
|
+
* converted sites is driven separately.
|
|
17500
17946
|
*/
|
|
17501
17947
|
async function resolvePseudoParametersForStartApi(stateRegion, options) {
|
|
17502
17948
|
const logger = getLogger();
|
|
@@ -17514,7 +17960,7 @@ async function resolvePseudoParametersForStartApi(stateRegion, options) {
|
|
|
17514
17960
|
sts.destroy();
|
|
17515
17961
|
}
|
|
17516
17962
|
} catch (err) {
|
|
17517
|
-
logger.warn(`--from-state: resolver needs \${AWS::AccountId} but STS GetCallerIdentity failed: ${err
|
|
17963
|
+
logger.warn(`--from-state: resolver needs \${AWS::AccountId} but STS GetCallerIdentity failed: ${describeAwsFailureForWarn(err, "STS GetCallerIdentity")}. Substitution will be skipped for AWS::AccountId; affected env entries will be dropped with per-key warnings.`);
|
|
17518
17964
|
}
|
|
17519
17965
|
const partitionAndSuffix = region ? derivePartitionAndUrlSuffix(region) : void 0;
|
|
17520
17966
|
const bag = {
|
|
@@ -17909,6 +18355,15 @@ function envHasCrossStackIntrinsic(templateEnv) {
|
|
|
17909
18355
|
}
|
|
17910
18356
|
return false;
|
|
17911
18357
|
}
|
|
18358
|
+
/**
|
|
18359
|
+
* Build the AWS pseudo-parameter bag (`${AWS::AccountId}` / `${AWS::Region}` /
|
|
18360
|
+
* partition / URL suffix) that `cdkl invoke`'s env-var substitution consumes.
|
|
18361
|
+
*
|
|
18362
|
+
* Exported so the issue #570 site-level test can drive the STS failure branch
|
|
18363
|
+
* with a mocked STS client -- the same reason `resolveLambdaContainerEnv`
|
|
18364
|
+
* below is exported. A helper being correct says nothing about whether a
|
|
18365
|
+
* given site actually routes through it.
|
|
18366
|
+
*/
|
|
17912
18367
|
async function resolvePseudoParametersForInvoke(stackRegion, options) {
|
|
17913
18368
|
const logger = getLogger();
|
|
17914
18369
|
const region = options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"] ?? stackRegion;
|
|
@@ -17926,7 +18381,7 @@ async function resolvePseudoParametersForInvoke(stackRegion, options) {
|
|
|
17926
18381
|
sts.destroy();
|
|
17927
18382
|
}
|
|
17928
18383
|
} catch (err) {
|
|
17929
|
-
logger.warn(`Resolver needs \${AWS::AccountId} but STS GetCallerIdentity failed: ${err
|
|
18384
|
+
logger.warn(`Resolver needs \${AWS::AccountId} but STS GetCallerIdentity failed: ${describeAwsFailureForWarn(err, "STS GetCallerIdentity")}. Substitution will be skipped; affected env entries will be dropped with per-key warnings.`);
|
|
17930
18385
|
}
|
|
17931
18386
|
const partitionAndSuffix = region ? derivePartitionAndUrlSuffix(region) : void 0;
|
|
17932
18387
|
const bag = {
|
|
@@ -18118,8 +18573,8 @@ async function resolveLambdaContainerEnv(lambda, options, profileCredentials, ex
|
|
|
18118
18573
|
if (stsRegion) dockerEnv["AWS_REGION"] = stsRegion;
|
|
18119
18574
|
assumeSucceeded = true;
|
|
18120
18575
|
} catch (err) {
|
|
18121
|
-
const reason = err
|
|
18122
|
-
logger.warn(`--assume-role: STS AssumeRole(${resolvedAssumeRoleArn}) failed: ${reason}. Falling back to the developer's shell credentials.`);
|
|
18576
|
+
const reason = describeAwsFailureForWarn(err, "STS AssumeRole");
|
|
18577
|
+
logger.warn(`--assume-role: STS AssumeRole(${flattenToOneLine(resolvedAssumeRoleArn)}) failed: ${reason}. Falling back to the developer's shell credentials.`);
|
|
18123
18578
|
}
|
|
18124
18579
|
}
|
|
18125
18580
|
if (!assumeSucceeded) {
|
|
@@ -18151,10 +18606,23 @@ function materializeInlineCode$1(handler, source, fileExtension) {
|
|
|
18151
18606
|
writeFileSync(filePath, source, "utf-8");
|
|
18152
18607
|
return dir;
|
|
18153
18608
|
}
|
|
18609
|
+
/**
|
|
18610
|
+
* Suggest `--assume-role` when the deployed function's execution role is
|
|
18611
|
+
* known and the user did not ask for it.
|
|
18612
|
+
*
|
|
18613
|
+
* Exported for the issue #570 ARN-flatten test. This is the MOST reachable of
|
|
18614
|
+
* the sites that print a wire-derived ARN: its caller is guarded on
|
|
18615
|
+
* `options.assumeRole === undefined`, so it fires on a plain
|
|
18616
|
+
* `cdkl invoke --from-cfn-stack <fn>` with no role flag at all. The ARN comes
|
|
18617
|
+
* from the same `resolveExecutionRoleArnFromState` whose other readers are
|
|
18618
|
+
* flattened, `info` is a default level, and `cdkl studio` splits an invoke
|
|
18619
|
+
* child's stdout on `\n` and emits every line as its own ring entry -- so an
|
|
18620
|
+
* unflattened newline here is two entries, the second entirely attacker-chosen.
|
|
18621
|
+
*/
|
|
18154
18622
|
function suggestAssumeRoleFromState(state, logicalId) {
|
|
18155
18623
|
const logger = getLogger();
|
|
18156
18624
|
const roleArn = resolveExecutionRoleArnFromState(state, logicalId);
|
|
18157
|
-
if (roleArn) logger.info(`Hint: the deployed function uses execution role ${roleArn}. Re-run with --assume-role to invoke under the deployed function's narrow permissions.`);
|
|
18625
|
+
if (roleArn) logger.info(`Hint: the deployed function uses execution role ${flattenToOneLine(roleArn)}. Re-run with --assume-role to invoke under the deployed function's narrow permissions.`);
|
|
18158
18626
|
}
|
|
18159
18627
|
/**
|
|
18160
18628
|
* Resolve the role ARN to assume for a Lambda invoke, honoring the three
|
|
@@ -18185,14 +18653,14 @@ async function resolveAssumeRoleArnForLambda(assumeRole, stateForRoleHint, state
|
|
|
18185
18653
|
}
|
|
18186
18654
|
const fromState = resolveExecutionRoleArnFromState(stateForRoleHint, lambdaLogicalId);
|
|
18187
18655
|
if (fromState) {
|
|
18188
|
-
logger.info(`--assume-role: auto-resolved execution role from state: ${fromState}`);
|
|
18656
|
+
logger.info(`--assume-role: auto-resolved execution role from state: ${flattenToOneLine(fromState)}`);
|
|
18189
18657
|
return fromState;
|
|
18190
18658
|
}
|
|
18191
18659
|
const fnPhysicalId = stateForRoleHint.resources[lambdaLogicalId]?.physicalId;
|
|
18192
18660
|
if (stateProvider?.resolveLambdaExecutionRoleArn && fnPhysicalId) {
|
|
18193
18661
|
const liveArn = await stateProvider.resolveLambdaExecutionRoleArn(fnPhysicalId);
|
|
18194
18662
|
if (liveArn) {
|
|
18195
|
-
logger.info(`--assume-role: auto-resolved execution role from GetFunctionConfiguration: ${liveArn}`);
|
|
18663
|
+
logger.info(`--assume-role: auto-resolved execution role from GetFunctionConfiguration: ${flattenToOneLine(liveArn)}`);
|
|
18196
18664
|
return liveArn;
|
|
18197
18665
|
}
|
|
18198
18666
|
}
|
|
@@ -19758,6 +20226,11 @@ async function buildSigV4HeadersIfRequested(options, resolved, loaded, host, por
|
|
|
19758
20226
|
*
|
|
19759
20227
|
* Throws a {@link CdkLocalError} when none are available — `--sigv4` cannot
|
|
19760
20228
|
* proceed without credentials, unlike the unsigned path.
|
|
20229
|
+
*
|
|
20230
|
+
* Exported so the issue #570 site-level test can drive the STS failure
|
|
20231
|
+
* branch with a mocked STS client -- the same reason
|
|
20232
|
+
* `applyAgentCoreCredentialEnv` below is exported. A helper being correct
|
|
20233
|
+
* says nothing about whether a given site actually routes through it.
|
|
19761
20234
|
*/
|
|
19762
20235
|
async function resolveHostCredentialsForSigV4(options, resolved, loaded, region, stateProvider) {
|
|
19763
20236
|
const logger = getLogger();
|
|
@@ -19765,7 +20238,7 @@ async function resolveHostCredentialsForSigV4(options, resolved, loaded, region,
|
|
|
19765
20238
|
if (assumeRoleArn) try {
|
|
19766
20239
|
return await assumeAgentCoreExecutionRole(assumeRoleArn, region, options.profile);
|
|
19767
20240
|
} catch (err) {
|
|
19768
|
-
logger.warn(`--assume-role: STS AssumeRole(${assumeRoleArn}) failed for --sigv4 signing: ${err
|
|
20241
|
+
logger.warn(`--assume-role: STS AssumeRole(${flattenToOneLine(assumeRoleArn)}) failed for --sigv4 signing: ${describeAwsFailureForWarn(err, "STS AssumeRole (--sigv4 signing)")}. Falling back to ${options.profile ? `--profile ${options.profile}` : "shell credentials"}.`);
|
|
19769
20242
|
}
|
|
19770
20243
|
if (options.profile) {
|
|
19771
20244
|
const creds = await resolveProfileCredentials(options.profile);
|
|
@@ -19868,6 +20341,11 @@ async function resolveAgentCoreCodeImage(resolved, code, options, architecture,
|
|
|
19868
20341
|
* or resolved from `--from-cfn-stack` state for the bare form) yields STS temp
|
|
19869
20342
|
* creds for the download; otherwise `--profile` / the default chain is used.
|
|
19870
20343
|
* The region is `--region` / `--stack-region` / env / the stack's region.
|
|
20344
|
+
*
|
|
20345
|
+
* Exported so the issue #570 site-level test can drive the STS failure
|
|
20346
|
+
* branch with a mocked STS client -- the same reason
|
|
20347
|
+
* `applyAgentCoreCredentialEnv` below is exported. A helper being correct
|
|
20348
|
+
* says nothing about whether a given site actually routes through it.
|
|
19871
20349
|
*/
|
|
19872
20350
|
async function resolveAgentCoreCodeImageFromS3(resolved, code, s3Source, options, architecture, loaded, stateProvider) {
|
|
19873
20351
|
const logger = getLogger();
|
|
@@ -19883,7 +20361,7 @@ async function resolveAgentCoreCodeImageFromS3(resolved, code, s3Source, options
|
|
|
19883
20361
|
if (assumeRoleArn) try {
|
|
19884
20362
|
credentials = await assumeAgentCoreExecutionRole(assumeRoleArn, region, options.profile);
|
|
19885
20363
|
} catch (err) {
|
|
19886
|
-
logger.warn(`--assume-role: STS AssumeRole(${assumeRoleArn}) failed for the fromS3 bundle download: ${err
|
|
20364
|
+
logger.warn(`--assume-role: STS AssumeRole(${flattenToOneLine(assumeRoleArn)}) failed for the fromS3 bundle download: ${describeAwsFailureForWarn(err, "STS AssumeRole (fromS3 bundle download)")}. Falling back to ${options.profile ? `--profile ${options.profile}` : "the default credentials"}.`);
|
|
19887
20365
|
}
|
|
19888
20366
|
const bundle = await downloadAndExtractS3Bundle(location, {
|
|
19889
20367
|
...region !== void 0 && { region },
|
|
@@ -20022,7 +20500,7 @@ async function buildAgentCoreImageContext(candidate, stateProvider, options) {
|
|
|
20022
20500
|
try {
|
|
20023
20501
|
accountId = await resolveCallerAccountId$2(region, options.profile);
|
|
20024
20502
|
} catch (err) {
|
|
20025
|
-
logger.warn(`--from-cfn-stack: STS GetCallerIdentity failed: ${err
|
|
20503
|
+
logger.warn(`--from-cfn-stack: STS GetCallerIdentity failed: ${describeAwsFailureForWarn(err, "STS GetCallerIdentity")}. A same-stack ECR image URI referencing \${AWS::AccountId} may not resolve.`);
|
|
20026
20504
|
}
|
|
20027
20505
|
const context = {};
|
|
20028
20506
|
const pseudo = derivePseudoParametersFromRegion(region, accountId);
|
|
@@ -20081,7 +20559,7 @@ async function applyAgentCoreCredentialEnv(dockerEnv, args) {
|
|
|
20081
20559
|
if (stsRegion) dockerEnv["AWS_REGION"] = stsRegion;
|
|
20082
20560
|
assumeSucceeded = true;
|
|
20083
20561
|
} catch (err) {
|
|
20084
|
-
logger.warn(`--assume-role: STS AssumeRole(${args.assumeRoleArn}) failed: ${err
|
|
20562
|
+
logger.warn(`--assume-role: STS AssumeRole(${flattenToOneLine(args.assumeRoleArn)}) failed: ${describeAwsFailureForWarn(err, "STS AssumeRole")}. Falling back to the developer's shell credentials.`);
|
|
20085
20563
|
}
|
|
20086
20564
|
}
|
|
20087
20565
|
if (!assumeSucceeded) {
|
|
@@ -20112,14 +20590,14 @@ async function resolveAssumeRoleArn(options, resolved, loaded, stateProvider) {
|
|
|
20112
20590
|
if (loaded) {
|
|
20113
20591
|
const fromState = resolveExecutionRoleArnFromState(loaded, resolved.logicalId, "RoleArn");
|
|
20114
20592
|
if (fromState) {
|
|
20115
|
-
getLogger().debug(`--assume-role: resolved RoleArn from state: ${fromState}`);
|
|
20593
|
+
getLogger().debug(`--assume-role: resolved RoleArn from state: ${flattenToOneLine(fromState)}`);
|
|
20116
20594
|
return fromState;
|
|
20117
20595
|
}
|
|
20118
20596
|
const runtimePhysicalId = loaded.resources[resolved.logicalId]?.physicalId;
|
|
20119
20597
|
if (stateProvider?.resolveAgentCoreRuntimeRoleArn && runtimePhysicalId) {
|
|
20120
20598
|
const liveArn = await stateProvider.resolveAgentCoreRuntimeRoleArn(runtimePhysicalId);
|
|
20121
20599
|
if (liveArn) {
|
|
20122
|
-
getLogger().info(`--assume-role: auto-resolved execution role from GetAgentRuntime: ${liveArn}`);
|
|
20600
|
+
getLogger().info(`--assume-role: auto-resolved execution role from GetAgentRuntime: ${flattenToOneLine(liveArn)}`);
|
|
20123
20601
|
return liveArn;
|
|
20124
20602
|
}
|
|
20125
20603
|
}
|
|
@@ -27079,7 +27557,7 @@ async function buildEcsImageResolutionContext$1(target, stacks, options, statePr
|
|
|
27079
27557
|
try {
|
|
27080
27558
|
accountId = await resolveCallerAccountId$1(region, options.profile);
|
|
27081
27559
|
} catch (err) {
|
|
27082
|
-
logger.warn(`Resolver needs \${AWS::AccountId} but STS GetCallerIdentity failed: ${err
|
|
27560
|
+
logger.warn(`Resolver needs \${AWS::AccountId} but STS GetCallerIdentity failed: ${describeAwsFailureForWarn(err, "STS GetCallerIdentity")}. Substitution will be skipped; affected env / secret entries will be dropped with per-key warnings.`);
|
|
27083
27561
|
}
|
|
27084
27562
|
const partitionAndSuffix = region ? derivePartitionAndUrlSuffix(region) : void 0;
|
|
27085
27563
|
ctx.pseudoParameters = {
|
|
@@ -27642,7 +28120,7 @@ async function buildEcsImageResolutionContext(candidate, stateProvider, options)
|
|
|
27642
28120
|
try {
|
|
27643
28121
|
accountId = await resolveCallerAccountId(region, options.profile);
|
|
27644
28122
|
} catch (err) {
|
|
27645
|
-
logger.warn(`Resolver needs \${AWS::AccountId} but STS GetCallerIdentity failed: ${err
|
|
28123
|
+
logger.warn(`Resolver needs \${AWS::AccountId} but STS GetCallerIdentity failed: ${describeAwsFailureForWarn(err, "STS GetCallerIdentity")}. Substitution will be skipped; affected env / secret entries will be dropped with per-key warnings.`);
|
|
27646
28124
|
}
|
|
27647
28125
|
const partitionAndSuffix = region ? derivePartitionAndUrlSuffix(region) : void 0;
|
|
27648
28126
|
ctx.pseudoParameters = {
|
|
@@ -37953,5 +38431,5 @@ function addStudioSpecificOptions(cmd) {
|
|
|
37953
38431
|
}
|
|
37954
38432
|
|
|
37955
38433
|
//#endregion
|
|
37956
|
-
export { applyEdgeResponseResult as $, buildJwksUrlFromIssuer as $n, resolveCfnStackName as $r, buildCloudMapIndex as $t, startAgentCoreHttpServer as A,
|
|
37957
|
-
//# sourceMappingURL=local-studio-
|
|
38434
|
+
export { applyEdgeResponseResult as $, buildJwksUrlFromIssuer as $n, resolveCfnStackName as $r, buildCloudMapIndex as $t, startAgentCoreHttpServer as A, describeCredentialLoadFailure as Ai, classifySourceChange as An, ConnectionRegistry as Ar, addRunTaskSpecificOptions as At, idFromArn as B, buildStageMap as Bn, resolveRuntimeFileExtension as Br, resolveEcsAssumeRoleOption as Bt, addListSpecificOptions as C, resolveAgentCoreTarget as Ci, waitForAgentCorePing as Cn, tryParseStatus as Cr, parseLbPortOverrides as Ct, createLocalStartAgentCoreCommand as D, tryResolveImageFnJoin as Di, computeCodeImageTag as Dn, probeHostGatewaySupport as Dr, addStartServiceSpecificOptions as Dt, addStartAgentCoreSpecificOptions as E, substituteImagePlaceholders as Ei, buildAgentCoreCodeImage as En, HOST_GATEWAY_MIN_VERSION as Er, resolveAlbFrontDoor as Et, createLocalStartCloudFrontCommand as F, createWatchPredicates as Fn, buildDisconnectEvent as Fr, addImageOverrideOptions as Ft, classifyS3Error as G, filterRoutesByApiIdentifiers as Gn, substituteEnvVarsFromState as Gr, enforceImageOverrideOrphans as Gt, createDeployedKvsDataSource as H, resolveEnvVars$1 as Hn, EcsTaskResolutionError as Hr, runEcsServiceEmulator as Ht, normalizeKvsFileKeys as I, resolveApiTargetSubset as In, buildMessageEvent as Ir, buildEcsImageResolutionContext$1 as It, startCloudFrontServer as J, startApiServer as Jn, createLocalStateProvider as Jr, resolveImageOverrides as Jt, createS3OriginReader as K, groupRoutesByServer as Kn, substituteEnvVarsFromStateAsync as Kr, mergeForService as Kt, parseKvsFileOverrides as L, createAuthorizerCache as Ln, architectureToPlatform as Lr, ecsClusterOption as Lt, startAgentCoreWsBridge as M, resolveProfileCredentials as Mi, createLocalInvokeCommand as Mn, handleConnectionsRequest as Mr, MAX_TASKS_SUBNET_RANGE_CAP as Mt, LocalStartCloudFrontError as N, addStartApiSpecificOptions as Nn, parseConnectionsPath as Nr, addCommonEcsServiceOptions as Nt, buildAgentCoreServeAuthCheck as O, LocalInvokeBuildError as Oi, renderCodeDockerfile as On, resolveHostGatewayExtraHosts as Or, createLocalStartServiceCommand as Ot, addStartCloudFrontSpecificOptions as P, createLocalStartApiCommand as Pn, buildConnectEvent as Pr, addEcsAssumeRoleOptions as Pt, applyEdgeRequestResult as Q, buildCognitoJwksUrl as Qn, resolveCfnRegion as Qr, listPinnedTargets as Qt, parseOriginOverrides as R, createFileWatcher as Rn, buildContainerImage as Rr, parseMaxTasks as Rt, StudioEventBus as S, pickAgentCoreCandidateStack as Si, waitForAgentCoreHttpReady as Sn, selectIntegrationResponse as Sr, createLocalStartAlbCommand as St, formatTargetListing as T, formatStateRemedy as Ti, SUPPORTED_CODE_RUNTIMES as Tn, HOST_DOCKER_INTERNAL_GATEWAY as Tr, isApplicationLoadBalancer as Tt, resolveDeployedKvsArnByName as U, availableApiIdentifiers as Un, substituteAgainstState as Ur, ImageOverrideError as Ut, resolveKvsModulesForDistribution as V, materializeLayerFromArn as Vn, resolveRuntimeImage as Vr, resolveSharedSidecarCredentials as Vt, resolveDeployedOriginBucket as W, filterRoutesByApiIdentifier as Wn, substituteAgainstStateAsync as Wr, buildImageOverrideTag as Wt, serveFromStaticOrigin as X, resolveServiceIntegrationParameters as Xn, rejectExplicitCfnStackWithMultipleStacks as Xr, describePinnedImageUri as Xt, resolveErrorResponseCandidates as Y, resolveSelectionExpression as Yn, isCfnFlagPresent as Yr, runImageOverrideBuilds as Yt, serveLambdaUrlOrigin as Z, defaultCredentialsLoader as Zn, resolveCfnFallbackRegion as Zr, isLocalCdkAssetImage as Zt, filterStudioTargetGroups as _, AGENTCORE_AGUI_PROTOCOL as _i, parseSseForJsonRpc as _n, applyAuthorizerOverlay as _r, createCloudFrontModule as _t, createLocalStudioCommand as a, countTargets as ai, attachContainerLogStreamer as an, computeRequestIdentityHash as ar, describeS3OriginDomain as at, renderStudioHtml as b, AGENTCORE_RUNTIME_TYPE as bi, AGENTCORE_SESSION_ID_HEADER as bn, evaluateResponseParameters as br, addAlbSpecificOptions as bt, startStudioProxy as c, discoverWebSocketApis as ci, bridgeAgentCoreWs as cn, invokeTokenAuthorizer as cr, pickFunctionUrlLogicalIdFromOrigin as ct, createStudioDispatcher as d, parseSelectionExpressionPath as di, A2A_PATH as dn, buildCorsConfigByApiId as dr, pickTargetFunctionLogicalId as dt, CfnLocalStateProvider as ei, CloudMapRegistry as en, createJwksCache as er, buildEdgeRequestEvent as et, filterStudioCustomResources as f, webSocketApiMatchesIdentifier as fi, a2aInvokeOnce as fn, buildCorsConfigFromCloudFrontChain as fr, resolveCloudFrontDistribution as ft, annotatePinnedEcsTargets as g, AGENTCORE_A2A_PROTOCOL as gi, mcpInvokeOnce as gn, translateLambdaResponse as gr, stripCloudFrontImport as gt, annotateEcsTaskPinnedTargets as h, resolveLambdaArnIntrinsic as hi, MCP_PROTOCOL_VERSION as hn, matchRoute as hr, runViewerResponse as ht, coerceStopRequest as i, resolveSingleTarget as ii, getContainerNetworkIp as in, buildMethodArn as ir, CLOUDFRONT_DISTRIBUTION_TYPE as it, attachAgentCoreWsBridge as j, buildStsClientConfig as ji, addInvokeSpecificOptions as jn, buildMgmtEndpointEnvUrl as jr, createLocalRunTaskCommand as jt, selectServeInboundAuth as k, describeAwsFailureForWarn as ki, toCmdArgv as kn, bufferToBody as kr, serviceStrategy as kt, relayServeRequest as l, discoverWebSocketApisOrThrow as li, invokeAgentCoreWs as ln, attachAuthorizers as lr, pickKvsLogicalIdFromArn as lt, annotateAlbPinnedBackingServices as m, pickRefLogicalId as mi, MCP_PATH as mn, matchPreflight as mr, runViewerRequest as mt, coerceRunRequest as n, resolveSsmParameters as ni, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as nn, verifyJwtAuthorizer as nr, edgeHeadersToHttp as nt, resolveServeBaseUrl as o, listTargets as oi, addInvokeAgentCoreSpecificOptions as on, evaluateCachedLambdaPolicy as or, extractKvsAssociations as ot, isCustomResourceLambdaTarget as p, discoverRoutes as pi, MCP_CONTAINER_PORT as pn, isFunctionUrlOacFronted as pr, compileCloudFrontFunction as pt, matchBehavior as q, readMtlsMaterialsFromDisk as qn, LocalStateSourceError as qr, parseImageOverrideFlags as qt, coerceServeRequest as r, resolveWatchConfig as ri, setShadowReadyTimeoutMs as rn, verifyJwtViaDiscovery as rr, httpHeadersToEdge as rt, createStudioServeManager as s, availableWebSocketApiIdentifiers as si, createLocalInvokeAgentCoreCommand as sn, invokeRequestAuthorizer as sr, isCloudFrontDistribution as st, addStudioSpecificOptions as t, collectSsmParameterRefs as ti, DEFAULT_SHADOW_READY_TIMEOUT_MS as tn, verifyCognitoJwt as tr, buildEdgeResponseEvent as tt, reinvoke as u, filterWebSocketApisByIdentifiers as ui, A2A_CONTAINER_PORT as un, applyCorsResponseHeaders as ur, pickLambdaEdgeFunctionLogicalId as ut, startStudioServer as v, AGENTCORE_HTTP_PROTOCOL as vi, AGENTCORE_SIGV4_SERVICE as vn, buildHttpApiV2Event as vr, createLocalFileKvsDataSource as vt, createLocalListCommand as w, derivePseudoParametersFromRegion as wi, downloadAndExtractS3Bundle as wn, VtlEvaluationError as wr, resolveAlbTarget as wt, createStudioStore as x, AgentCoreResolutionError as xi, invokeAgentCore as xn, pickResponseTemplate as xr, albStrategy as xt, toStudioTargetGroups as y, AGENTCORE_MCP_PROTOCOL as yi, signAgentCoreInvocation as yn, buildRestV1Event as yr, createUnboundCloudFrontModule as yt, resolveCloudFrontTarget as z, attachStageContext as zn, resolveRuntimeCodeMountPath as zr, parseRestartPolicy as zt };
|
|
38435
|
+
//# sourceMappingURL=local-studio-9eVA5PPS.js.map
|