cdk-local 0.34.0 → 0.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/cli.js +2 -2
- package/dist/{docker-cmd--8TRSn9z.js → docker-cmd-voNPrcRh.js} +2 -2
- package/dist/docker-cmd-voNPrcRh.js.map +1 -0
- package/dist/index.d.ts +20 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{local-list-BjnmIFMU.js → local-list-8fAEdzBb.js} +248 -85
- package/dist/local-list-8fAEdzBb.js.map +1 -0
- package/package.json +2 -1
- package/dist/docker-cmd--8TRSn9z.js.map +0 -1
- package/dist/local-list-BjnmIFMU.js.map +0 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { a as runDockerStreaming, c as getEmbedConfig, i as runDockerForeground, n as formatDockerLoginError, o as spawnStreaming, r as getDockerCmd, s as getLogger, u as setEmbedConfig } from "./docker-cmd
|
|
1
|
+
import { a as runDockerStreaming, c as getEmbedConfig, i as runDockerForeground, n as formatDockerLoginError, o as spawnStreaming, r as getDockerCmd, s as getLogger, u as setEmbedConfig } from "./docker-cmd-voNPrcRh.js";
|
|
2
2
|
import { cpSync, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { dirname, isAbsolute, join, normalize, resolve } from "node:path";
|
|
6
6
|
import { Command, Option } from "commander";
|
|
7
7
|
import { AssumeRoleCommand, GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
|
|
8
|
-
import {
|
|
8
|
+
import { MultiSelectPrompt } from "@clack/core";
|
|
9
|
+
import { S_BAR, S_BAR_END, S_BAR_START, S_CHECKBOX_ACTIVE, S_CHECKBOX_INACTIVE, S_CHECKBOX_SELECTED, confirm, isCancel, select } from "@clack/prompts";
|
|
9
10
|
import { AssetManifestArtifact } from "@aws-cdk/cloud-assembly-api";
|
|
10
11
|
import { BaseCredentials, CdkAppMultiContext, NonInteractiveIoHost, Toolkit } from "@aws-cdk/toolkit-lib";
|
|
11
12
|
import { CloudFormationClient, DescribeStacksCommand, ListExportsCommand, ListStackResourcesCommand } from "@aws-sdk/client-cloudformation";
|
|
@@ -312,9 +313,6 @@ function withErrorHandling(fn) {
|
|
|
312
313
|
* Read the `aws:cdk:path` value that CDK encodes into every resource's
|
|
313
314
|
* `Metadata`. Returns the empty string when not present so callers don't
|
|
314
315
|
* have to special-case `undefined`.
|
|
315
|
-
*
|
|
316
|
-
* Hoisted out of `src/cli/commands/import.ts` so `cdkd orphan` can reuse the
|
|
317
|
-
* same lookup without duplicating the metadata-walking code.
|
|
318
316
|
*/
|
|
319
317
|
function readCdkPath(resource) {
|
|
320
318
|
const meta = resource.Metadata;
|
|
@@ -340,10 +338,9 @@ function readCdkPathOrUndefined(resource) {
|
|
|
340
338
|
/**
|
|
341
339
|
* Build a `Map<cdkPath, logicalId>` from a synthesized template.
|
|
342
340
|
*
|
|
343
|
-
*
|
|
344
|
-
* construct
|
|
345
|
-
*
|
|
346
|
-
* provider lookup) is keyed on.
|
|
341
|
+
* Translates user-supplied construct paths (which mirror the upstream
|
|
342
|
+
* `cdk` construct-path UX) back to the logical IDs that the rest of the
|
|
343
|
+
* pipeline (state, dependency analysis, provider lookup) is keyed on.
|
|
347
344
|
*
|
|
348
345
|
* `AWS::CDK::Metadata` resources are excluded — the synthesized
|
|
349
346
|
* `<Stack>/CDKMetadata/Default` sentinel exists in every stack but is
|
|
@@ -355,7 +352,7 @@ function readCdkPathOrUndefined(resource) {
|
|
|
355
352
|
*
|
|
356
353
|
* In practice each path maps to a single logical ID. If the same path
|
|
357
354
|
* happens to appear twice (which would itself be a bug in the synthesized
|
|
358
|
-
* template), the last entry wins —
|
|
355
|
+
* template), the last entry wins — callers still surface a
|
|
359
356
|
* clean "path not found" diff against the indexed map rather than
|
|
360
357
|
* silently grabbing both.
|
|
361
358
|
*/
|
|
@@ -2066,14 +2063,37 @@ function listApiSurfaces(stacks) {
|
|
|
2066
2063
|
function listTargets(stacks) {
|
|
2067
2064
|
return {
|
|
2068
2065
|
lambdas: sortEntries(scanByType(stacks, "AWS::Lambda::Function")),
|
|
2069
|
-
apis:
|
|
2066
|
+
apis: sortApiEntries(listApiSurfaces(stacks)),
|
|
2070
2067
|
ecsServices: sortEntries(scanByType(stacks, "AWS::ECS::Service")),
|
|
2071
2068
|
ecsTaskDefinitions: sortEntries(scanByType(stacks, "AWS::ECS::TaskDefinition"))
|
|
2072
2069
|
};
|
|
2073
2070
|
}
|
|
2071
|
+
const pathOf = (e) => e.displayPath ?? e.qualifiedId;
|
|
2074
2072
|
/** Stable, human-readable ordering: by display path, falling back to the qualified ID. */
|
|
2075
2073
|
function sortEntries(entries) {
|
|
2076
|
-
return [...entries].sort((a, b) => (a
|
|
2074
|
+
return [...entries].sort((a, b) => pathOf(a).localeCompare(pathOf(b)));
|
|
2075
|
+
}
|
|
2076
|
+
/** Display order for API surface kinds; entries are grouped in this order. */
|
|
2077
|
+
const API_KIND_ORDER = [
|
|
2078
|
+
"HTTP API v2",
|
|
2079
|
+
"REST API v1",
|
|
2080
|
+
"Function URL",
|
|
2081
|
+
"WebSocket"
|
|
2082
|
+
];
|
|
2083
|
+
/**
|
|
2084
|
+
* Order API surfaces by stack, then kind (in {@link API_KIND_ORDER}), then
|
|
2085
|
+
* display path — so a multi-stack app shows each stack's APIs as a block,
|
|
2086
|
+
* grouped by kind inside it (single-stack apps are simply kind-grouped). Used
|
|
2087
|
+
* by both `cdkl list` and the interactive picker. Exported for unit testing.
|
|
2088
|
+
*/
|
|
2089
|
+
function sortApiEntries(entries) {
|
|
2090
|
+
return [...entries].sort((a, b) => {
|
|
2091
|
+
if (a.stackName !== b.stackName) return a.stackName.localeCompare(b.stackName);
|
|
2092
|
+
const ka = API_KIND_ORDER.indexOf(a.kind ?? "");
|
|
2093
|
+
const kb = API_KIND_ORDER.indexOf(b.kind ?? "");
|
|
2094
|
+
if (ka !== kb) return ka - kb;
|
|
2095
|
+
return pathOf(a).localeCompare(pathOf(b));
|
|
2096
|
+
});
|
|
2077
2097
|
}
|
|
2078
2098
|
/** Total number of targets across every category. */
|
|
2079
2099
|
function countTargets(listing) {
|
|
@@ -2082,6 +2102,10 @@ function countTargets(listing) {
|
|
|
2082
2102
|
|
|
2083
2103
|
//#endregion
|
|
2084
2104
|
//#region src/local/target-picker.ts
|
|
2105
|
+
const ANSI = {
|
|
2106
|
+
cyan: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
2107
|
+
green: (s) => `\x1b[32m${s}\x1b[0m`
|
|
2108
|
+
};
|
|
2085
2109
|
/**
|
|
2086
2110
|
* True when both stdin and stdout are TTYs — the precondition for any
|
|
2087
2111
|
* interactive prompt. In a pipe / CI / non-interactive shell this is
|
|
@@ -2114,29 +2138,81 @@ async function pickOneTarget(message, entries) {
|
|
|
2114
2138
|
return chosen;
|
|
2115
2139
|
}
|
|
2116
2140
|
/**
|
|
2117
|
-
*
|
|
2118
|
-
*
|
|
2119
|
-
*
|
|
2141
|
+
* The selected-value array after a bulk action — `all` selects every
|
|
2142
|
+
* option, `none` clears the selection. Pure (no prompt state) so the
|
|
2143
|
+
* arrow-key bulk-select wiring is unit-testable without a TTY.
|
|
2144
|
+
*/
|
|
2145
|
+
function bulkSelectValues(options, action) {
|
|
2146
|
+
return action === "all" ? options.map((o) => o.value) : [];
|
|
2147
|
+
}
|
|
2148
|
+
/** Pre-compute the aligned `[kind] ` tag per option (blank when no kind). */
|
|
2149
|
+
function kindTags(opts) {
|
|
2150
|
+
const raw = opts.map((o) => o.hint ? `[${o.hint}] ` : "");
|
|
2151
|
+
const width = Math.max(0, ...raw.map((t) => t.length));
|
|
2152
|
+
return raw.map((t) => t.padEnd(width));
|
|
2153
|
+
}
|
|
2154
|
+
/**
|
|
2155
|
+
* Prompt for one or more targets. Caller must have already confirmed a TTY
|
|
2156
|
+
* and a non-empty `entries`. Throws {@link TargetSelectionCancelledError}
|
|
2157
|
+
* on Ctrl+C / Esc, on an empty selection (the user chose nothing), or when
|
|
2158
|
+
* the confirmation step is declined.
|
|
2120
2159
|
*
|
|
2121
|
-
*
|
|
2122
|
-
*
|
|
2123
|
-
*
|
|
2160
|
+
* Built on `@clack/core`'s `MultiSelectPrompt` (rather than the high-level
|
|
2161
|
+
* `multiselect`) so it can add bulk-selection keys the high-level wrapper
|
|
2162
|
+
* does not expose: Up/Down move, Space toggles, **Right selects all**,
|
|
2163
|
+
* **Left clears all**, Enter confirms. `MultiSelectPrompt` tracks the
|
|
2164
|
+
* selection in `this.value`, so the Right/Left handlers set it directly —
|
|
2165
|
+
* the same mechanism the built-in `toggleAll` uses.
|
|
2124
2166
|
*
|
|
2125
|
-
*
|
|
2126
|
-
*
|
|
2127
|
-
*
|
|
2128
|
-
*
|
|
2167
|
+
* Rows start UNSELECTED. Each row is prefixed with its surface kind
|
|
2168
|
+
* (`[HTTP API v2] MyApi`) — always shown, padded so labels align. Submitting
|
|
2169
|
+
* with nothing selected exits cleanly; a non-empty selection goes through a
|
|
2170
|
+
* Y/n confirmation before returning.
|
|
2129
2171
|
*/
|
|
2130
|
-
async function pickManyTargets(message, entries
|
|
2172
|
+
async function pickManyTargets(message, entries) {
|
|
2131
2173
|
const opts = entries.map(toOption);
|
|
2132
|
-
const
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2174
|
+
const tags = kindTags(opts);
|
|
2175
|
+
const displayByValue = new Map(opts.map((o) => [o.value, o.hint ? `[${o.hint}] ${o.label}` : o.label]));
|
|
2176
|
+
let initialValues = [];
|
|
2177
|
+
for (;;) {
|
|
2178
|
+
const prompt = new MultiSelectPrompt({
|
|
2179
|
+
options: opts,
|
|
2180
|
+
required: false,
|
|
2181
|
+
...initialValues.length > 0 ? { initialValues } : {},
|
|
2182
|
+
render() {
|
|
2183
|
+
if (this.state === "submit" || this.state === "cancel") return `${S_BAR_START} ${message}\n${S_BAR} ${(this.value ?? []).length} selected`;
|
|
2184
|
+
const header = `${S_BAR_START} ${message} (toggle: space | all: → | none: ← | confirm: enter)`;
|
|
2185
|
+
const selected = new Set(this.value ?? []);
|
|
2186
|
+
return `${header}\n${this.options.map((opt, i) => {
|
|
2187
|
+
const isActive = i === this.cursor;
|
|
2188
|
+
const isSelected = selected.has(opt.value);
|
|
2189
|
+
const box = isSelected ? ANSI.green(S_CHECKBOX_SELECTED) : isActive ? ANSI.cyan(S_CHECKBOX_ACTIVE) : S_CHECKBOX_INACTIVE;
|
|
2190
|
+
const text = `${tags[i]}${opt.label}`;
|
|
2191
|
+
return `${S_BAR} ${box} ${isActive ? ANSI.cyan(text) : isSelected ? ANSI.green(text) : text}`;
|
|
2192
|
+
}).join("\n")}\n${S_BAR_END}`;
|
|
2193
|
+
}
|
|
2194
|
+
});
|
|
2195
|
+
prompt.on("key", (_char, info) => {
|
|
2196
|
+
if (info?.name !== "right" && info?.name !== "left") return;
|
|
2197
|
+
prompt.value = bulkSelectValues(opts, info.name === "right" ? "all" : "none");
|
|
2198
|
+
prompt.cursor = 0;
|
|
2199
|
+
});
|
|
2200
|
+
const picked = await prompt.prompt();
|
|
2201
|
+
if (isCancel(picked)) throw new TargetSelectionCancelledError();
|
|
2202
|
+
const values = picked ?? [];
|
|
2203
|
+
if (values.length === 0) {
|
|
2204
|
+
const exit = await confirm({ message: "Nothing selected. Exit without running anything?" });
|
|
2205
|
+
if (isCancel(exit)) throw new TargetSelectionCancelledError();
|
|
2206
|
+
if (exit === true) throw new TargetSelectionCancelledError();
|
|
2207
|
+
initialValues = [];
|
|
2208
|
+
continue;
|
|
2209
|
+
}
|
|
2210
|
+
const bullets = values.map((v) => ` • ${displayByValue.get(v) ?? v}`).join("\n");
|
|
2211
|
+
const ok = await confirm({ message: `Run ${values.length === 1 ? "this target" : `these ${values.length} targets`}?\n${bullets}` });
|
|
2212
|
+
if (isCancel(ok)) throw new TargetSelectionCancelledError();
|
|
2213
|
+
if (ok === true) return values;
|
|
2214
|
+
initialValues = values;
|
|
2215
|
+
}
|
|
2140
2216
|
}
|
|
2141
2217
|
function ensureCanPrompt(onMissing) {
|
|
2142
2218
|
if (isInteractive()) return;
|
|
@@ -2276,9 +2352,9 @@ function mapStackArtifact(stack) {
|
|
|
2276
2352
|
//#endregion
|
|
2277
2353
|
//#region src/synthesis/synthesizer.ts
|
|
2278
2354
|
/**
|
|
2279
|
-
* Thin wrapper around {@link AssemblyReader}
|
|
2280
|
-
*
|
|
2281
|
-
* `
|
|
2355
|
+
* Thin wrapper around {@link AssemblyReader} exposing a `Synthesizer`
|
|
2356
|
+
* API used by the `cdkl invoke` / `start-api` / `run-task` /
|
|
2357
|
+
* `start-service` commands.
|
|
2282
2358
|
*
|
|
2283
2359
|
* When `app` resolves to an existing directory it is read as a
|
|
2284
2360
|
* pre-synthesized cloud assembly (no subprocess synth); otherwise it is
|
|
@@ -2447,15 +2523,16 @@ function collectSsmParameterRefs(template) {
|
|
|
2447
2523
|
* String parameters resolve too (matching how CloudFormation resolves
|
|
2448
2524
|
* the `AWS::SSM::Parameter::Value<String>` type at deploy time).
|
|
2449
2525
|
*
|
|
2450
|
-
* Security note: a decrypted SecureString value resolved here
|
|
2451
|
-
* baked into the container's `Environment` like any
|
|
2452
|
-
*
|
|
2453
|
-
*
|
|
2454
|
-
*
|
|
2455
|
-
*
|
|
2456
|
-
*
|
|
2457
|
-
*
|
|
2458
|
-
*
|
|
2526
|
+
* Security note (issue #99): a decrypted SecureString value resolved here
|
|
2527
|
+
* would otherwise be baked into the container's `Environment` like any
|
|
2528
|
+
* other resolved value and could appear on the `docker run -e KEY=VALUE`
|
|
2529
|
+
* argv (visible in host `ps`). To prevent that, the returned
|
|
2530
|
+
* {@link ResolvedSsmParameters.secureStringLogicalIds} flags every
|
|
2531
|
+
* SecureString parameter; downstream the consuming env keys are routed
|
|
2532
|
+
* through docker's value-from-process-env form (`-e KEY`, value supplied
|
|
2533
|
+
* via the spawned docker process's env) so the secret never lands on the
|
|
2534
|
+
* argv. The value still appears in `docker inspect` Config.Env, which is
|
|
2535
|
+
* inherent to container env and matches deployed behavior.
|
|
2459
2536
|
*
|
|
2460
2537
|
* Best-effort: a failed `GetParameters` chunk logs a warn and is skipped
|
|
2461
2538
|
* (the other chunks still contribute their values); the function never
|
|
@@ -2467,7 +2544,10 @@ function collectSsmParameterRefs(template) {
|
|
|
2467
2544
|
* Exported for unit testing.
|
|
2468
2545
|
*/
|
|
2469
2546
|
async function resolveSsmParameters(client, refs, label) {
|
|
2470
|
-
const out = {
|
|
2547
|
+
const out = {
|
|
2548
|
+
values: {},
|
|
2549
|
+
secureStringLogicalIds: []
|
|
2550
|
+
};
|
|
2471
2551
|
if (refs.length === 0) return out;
|
|
2472
2552
|
const logger = getLogger();
|
|
2473
2553
|
const CHUNK = 10;
|
|
@@ -2497,7 +2577,11 @@ async function resolveSsmParameters(client, refs, label) {
|
|
|
2497
2577
|
if (typeof p.Name !== "string" || typeof p.Value !== "string") continue;
|
|
2498
2578
|
const requesters = byName.get(p.Name);
|
|
2499
2579
|
if (!requesters) continue;
|
|
2500
|
-
|
|
2580
|
+
const isSecure = p.Type === "SecureString";
|
|
2581
|
+
for (const ref of requesters) {
|
|
2582
|
+
out.values[ref.logicalId] = p.Value;
|
|
2583
|
+
if (isSecure) out.secureStringLogicalIds.push(ref.logicalId);
|
|
2584
|
+
}
|
|
2501
2585
|
}
|
|
2502
2586
|
}
|
|
2503
2587
|
return out;
|
|
@@ -2632,7 +2716,10 @@ var CfnLocalStateProvider = class {
|
|
|
2632
2716
|
async resolveTemplateSsmParameters(template) {
|
|
2633
2717
|
if (this.disposed) throw new Error("CfnLocalStateProvider used after dispose()");
|
|
2634
2718
|
const refs = collectSsmParameterRefs(template);
|
|
2635
|
-
if (refs.length === 0) return {
|
|
2719
|
+
if (refs.length === 0) return {
|
|
2720
|
+
values: {},
|
|
2721
|
+
secureStringLogicalIds: []
|
|
2722
|
+
};
|
|
2636
2723
|
return resolveSsmParameters(this.getSsmClient(), refs, this.label);
|
|
2637
2724
|
}
|
|
2638
2725
|
/**
|
|
@@ -2921,8 +3008,8 @@ async function resolveProfileRegion(profile) {
|
|
|
2921
3008
|
* Host-extensible state sources (via the `extraStateProviders` option):
|
|
2922
3009
|
*
|
|
2923
3010
|
* - Hosts embedding cdk-local can register additional `LocalStateProvider`
|
|
2924
|
-
* factories that respond to their own CLI flags (e.g.
|
|
2925
|
-
* `--from-state`
|
|
3011
|
+
* factories that respond to their own CLI flags (e.g. a host-registered
|
|
3012
|
+
* `--from-state` backed by an S3 state store). Each entry is keyed by
|
|
2926
3013
|
* the camel-case Commander option name (e.g. `'fromState'`) so the
|
|
2927
3014
|
* dispatcher reads the corresponding boolean / string off the parsed
|
|
2928
3015
|
* options bag.
|
|
@@ -3046,7 +3133,7 @@ function rejectExplicitCfnStackWithMultipleStacks(options, routedStackCount) {
|
|
|
3046
3133
|
* fallback for the CFn client when no explicit region override is set.
|
|
3047
3134
|
*
|
|
3048
3135
|
* `extraStateProviders` is the host-supplied registry of additional
|
|
3049
|
-
* state sources (e.g.
|
|
3136
|
+
* state sources (e.g. a host's `--from-state` / S3-backed provider).
|
|
3050
3137
|
* Each entry's key is the camel-case Commander option name; the
|
|
3051
3138
|
* dispatcher activates the matching factory when the corresponding
|
|
3052
3139
|
* options field is truthy.
|
|
@@ -3102,7 +3189,7 @@ function stackMatchesPattern(stack, pattern) {
|
|
|
3102
3189
|
//#region src/local/intrinsic-image.ts
|
|
3103
3190
|
/**
|
|
3104
3191
|
* Derive the AWS pseudo parameters that are trivially knowable from the
|
|
3105
|
-
* deploy region alone, without any STS call or
|
|
3192
|
+
* deploy region alone, without any STS call or state load.
|
|
3106
3193
|
* `urlSuffix` and `partition` follow the canonical AWS partition rules:
|
|
3107
3194
|
*
|
|
3108
3195
|
* - region prefix `cn-*` → partition `aws-cn`, urlSuffix `amazonaws.com.cn`
|
|
@@ -3159,7 +3246,7 @@ function derivePseudoParametersFromRegion(region, accountId) {
|
|
|
3159
3246
|
* nested `Fn::Select` / `Fn::Split` over an `Fn::GetAtt: [<Repo>, 'Arn']`
|
|
3160
3247
|
* plus a `Ref` to the same `AWS::ECR::Repository` and a
|
|
3161
3248
|
* `Ref: AWS::URLSuffix`. For SAME-STACK references the account-id +
|
|
3162
|
-
* region only exist in
|
|
3249
|
+
* region only exist in the host's S3 state (recorded at deploy time on the
|
|
3163
3250
|
* Repository's `Arn` attribute), so the resolver inherently requires
|
|
3164
3251
|
* `--from-state` (Tier 2) for that variant. For IMPORTED repositories
|
|
3165
3252
|
* the URI components are flat strings + `Ref: AWS::URLSuffix` and
|
|
@@ -4178,10 +4265,13 @@ function resolveRef(arg, context) {
|
|
|
4178
4265
|
value: resource.physicalId
|
|
4179
4266
|
};
|
|
4180
4267
|
const parameterValue = context.parameters?.[arg];
|
|
4181
|
-
if (parameterValue !== void 0)
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4268
|
+
if (parameterValue !== void 0) {
|
|
4269
|
+
if (context.sensitiveParameters?.has(arg)) context.onSensitiveParameterConsumed?.(arg);
|
|
4270
|
+
return {
|
|
4271
|
+
kind: "literal",
|
|
4272
|
+
value: parameterValue
|
|
4273
|
+
};
|
|
4274
|
+
}
|
|
4185
4275
|
return {
|
|
4186
4276
|
kind: "unresolved",
|
|
4187
4277
|
reason: `Ref '${arg}': no record in the state source (was the resource deployed, or is it a CloudFormation parameter that could not be resolved — e.g. an SSM-backed AWS::SSM::Parameter::Value parameter whose SSM value was not readable?)`
|
|
@@ -4657,7 +4747,8 @@ function substituteEnvVarsFromState(templateEnv, contextOrResources) {
|
|
|
4657
4747
|
const env = {};
|
|
4658
4748
|
const audit = {
|
|
4659
4749
|
resolvedKeys: [],
|
|
4660
|
-
unresolved: []
|
|
4750
|
+
unresolved: [],
|
|
4751
|
+
sensitiveKeys: []
|
|
4661
4752
|
};
|
|
4662
4753
|
if (!templateEnv) return {
|
|
4663
4754
|
env,
|
|
@@ -4669,10 +4760,11 @@ function substituteEnvVarsFromState(templateEnv, contextOrResources) {
|
|
|
4669
4760
|
env[key] = value;
|
|
4670
4761
|
continue;
|
|
4671
4762
|
}
|
|
4672
|
-
const result =
|
|
4763
|
+
const { result, consumedSensitive } = resolveWithSensitivity(value, context);
|
|
4673
4764
|
if (result.kind === "literal") {
|
|
4674
4765
|
env[key] = result.value;
|
|
4675
4766
|
audit.resolvedKeys.push(key);
|
|
4767
|
+
if (consumedSensitive) audit.sensitiveKeys.push(key);
|
|
4676
4768
|
} else audit.unresolved.push({
|
|
4677
4769
|
key,
|
|
4678
4770
|
reason: result.reason
|
|
@@ -4684,6 +4776,53 @@ function substituteEnvVarsFromState(templateEnv, contextOrResources) {
|
|
|
4684
4776
|
};
|
|
4685
4777
|
}
|
|
4686
4778
|
/**
|
|
4779
|
+
* Resolve a single intrinsic value while detecting whether its resolution
|
|
4780
|
+
* consumed a sensitive (SecureString) parameter — including refs nested in
|
|
4781
|
+
* `Fn::Join` / `Fn::Sub`, since the combinators recurse through the same
|
|
4782
|
+
* per-key context. Installs a per-call sink on a shallow context copy so
|
|
4783
|
+
* the shared input context is never mutated. Used by both the sync and
|
|
4784
|
+
* async env-var helpers (the async path delegates these intrinsics to the
|
|
4785
|
+
* sync resolver, so the sink fires identically).
|
|
4786
|
+
*/
|
|
4787
|
+
function resolveWithSensitivity(value, context) {
|
|
4788
|
+
if (!context.sensitiveParameters || context.sensitiveParameters.size === 0) return {
|
|
4789
|
+
result: substituteAgainstState(value, context),
|
|
4790
|
+
consumedSensitive: false
|
|
4791
|
+
};
|
|
4792
|
+
let consumedSensitive = false;
|
|
4793
|
+
return {
|
|
4794
|
+
result: substituteAgainstState(value, {
|
|
4795
|
+
...context,
|
|
4796
|
+
onSensitiveParameterConsumed: () => {
|
|
4797
|
+
consumedSensitive = true;
|
|
4798
|
+
}
|
|
4799
|
+
}),
|
|
4800
|
+
consumedSensitive
|
|
4801
|
+
};
|
|
4802
|
+
}
|
|
4803
|
+
/**
|
|
4804
|
+
* Async sibling of {@link resolveWithSensitivity}. Routes through
|
|
4805
|
+
* {@link substituteAgainstStateAsync} (for `Fn::ImportValue` /
|
|
4806
|
+
* `Fn::GetStackOutput`), which delegates SSM-parameter-bearing intrinsics
|
|
4807
|
+
* to the sync resolver — so the sensitivity sink fires the same way.
|
|
4808
|
+
*/
|
|
4809
|
+
async function resolveWithSensitivityAsync(value, context) {
|
|
4810
|
+
if (!context.sensitiveParameters || context.sensitiveParameters.size === 0) return {
|
|
4811
|
+
result: await substituteAgainstStateAsync(value, context),
|
|
4812
|
+
consumedSensitive: false
|
|
4813
|
+
};
|
|
4814
|
+
let consumedSensitive = false;
|
|
4815
|
+
return {
|
|
4816
|
+
result: await substituteAgainstStateAsync(value, {
|
|
4817
|
+
...context,
|
|
4818
|
+
onSensitiveParameterConsumed: () => {
|
|
4819
|
+
consumedSensitive = true;
|
|
4820
|
+
}
|
|
4821
|
+
}),
|
|
4822
|
+
consumedSensitive
|
|
4823
|
+
};
|
|
4824
|
+
}
|
|
4825
|
+
/**
|
|
4687
4826
|
* Async sibling of {@link substituteEnvVarsFromState}. Routes every
|
|
4688
4827
|
* intrinsic-valued entry through {@link substituteAgainstStateAsync} so
|
|
4689
4828
|
* `Fn::ImportValue` / `Fn::GetStackOutput` resolve via the context's
|
|
@@ -4701,7 +4840,8 @@ async function substituteEnvVarsFromStateAsync(templateEnv, contextOrResources)
|
|
|
4701
4840
|
const env = {};
|
|
4702
4841
|
const audit = {
|
|
4703
4842
|
resolvedKeys: [],
|
|
4704
|
-
unresolved: []
|
|
4843
|
+
unresolved: [],
|
|
4844
|
+
sensitiveKeys: []
|
|
4705
4845
|
};
|
|
4706
4846
|
if (!templateEnv) return {
|
|
4707
4847
|
env,
|
|
@@ -4713,10 +4853,11 @@ async function substituteEnvVarsFromStateAsync(templateEnv, contextOrResources)
|
|
|
4713
4853
|
env[key] = value;
|
|
4714
4854
|
continue;
|
|
4715
4855
|
}
|
|
4716
|
-
const result = await
|
|
4856
|
+
const { result, consumedSensitive } = await resolveWithSensitivityAsync(value, context);
|
|
4717
4857
|
if (result.kind === "literal") {
|
|
4718
4858
|
env[key] = result.value;
|
|
4719
4859
|
audit.resolvedKeys.push(key);
|
|
4860
|
+
if (consumedSensitive) audit.sensitiveKeys.push(key);
|
|
4720
4861
|
} else audit.unresolved.push({
|
|
4721
4862
|
key,
|
|
4722
4863
|
reason: result.reason
|
|
@@ -5037,7 +5178,7 @@ function parseEcsTarget(target) {
|
|
|
5037
5178
|
* available task definition in the matched stack) on any miss.
|
|
5038
5179
|
*
|
|
5039
5180
|
* Optional `context` (issue #264): when the caller can supply AWS
|
|
5040
|
-
* pseudo-parameter values (Tier 1) and / or
|
|
5181
|
+
* pseudo-parameter values (Tier 1) and / or host state-recorded resources
|
|
5041
5182
|
* (Tier 2), `Fn::Sub`-shaped ECR image URIs that reference
|
|
5042
5183
|
* `${AWS::AccountId}` / `${AWS::Region}` / a same-stack
|
|
5043
5184
|
* `AWS::ECR::Repository` are substituted before classification.
|
|
@@ -5138,6 +5279,7 @@ function parseContainerDefinition(raw, idx, taskLogicalId, resources, stack, con
|
|
|
5138
5279
|
const workingDirectory = pickString(c["WorkingDirectory"]);
|
|
5139
5280
|
const subContext = buildSubstitutionContextFromImageContext(context);
|
|
5140
5281
|
const environment = {};
|
|
5282
|
+
const sensitiveEnvKeys = [];
|
|
5141
5283
|
const droppedEnvKeys = [];
|
|
5142
5284
|
if (Array.isArray(c["Environment"])) for (const entry of c["Environment"]) {
|
|
5143
5285
|
if (!entry || typeof entry !== "object") continue;
|
|
@@ -5150,9 +5292,10 @@ function parseContainerDefinition(raw, idx, taskLogicalId, resources, stack, con
|
|
|
5150
5292
|
continue;
|
|
5151
5293
|
}
|
|
5152
5294
|
if (subContext) {
|
|
5153
|
-
const sub =
|
|
5295
|
+
const { result: sub, consumedSensitive } = resolveWithSensitivity(value, subContext);
|
|
5154
5296
|
if (sub.kind === "literal") {
|
|
5155
5297
|
environment[key] = String(sub.value);
|
|
5298
|
+
if (consumedSensitive) sensitiveEnvKeys.push(key);
|
|
5156
5299
|
continue;
|
|
5157
5300
|
}
|
|
5158
5301
|
droppedEnvKeys.push({
|
|
@@ -5277,6 +5420,7 @@ function parseContainerDefinition(raw, idx, taskLogicalId, resources, stack, con
|
|
|
5277
5420
|
name,
|
|
5278
5421
|
image,
|
|
5279
5422
|
environment,
|
|
5423
|
+
sensitiveEnvKeys,
|
|
5280
5424
|
secrets,
|
|
5281
5425
|
portMappings,
|
|
5282
5426
|
mountPoints,
|
|
@@ -5306,6 +5450,7 @@ function buildSubstitutionContextFromImageContext(context) {
|
|
|
5306
5450
|
const subContext = { resources: context.stateResources };
|
|
5307
5451
|
if (context.pseudoParameters) subContext.pseudoParameters = { ...context.pseudoParameters };
|
|
5308
5452
|
if (context.stateParameters) subContext.parameters = { ...context.stateParameters };
|
|
5453
|
+
if (context.stateSensitiveParameters?.length) subContext.sensitiveParameters = new Set(context.stateSensitiveParameters);
|
|
5309
5454
|
return subContext;
|
|
5310
5455
|
}
|
|
5311
5456
|
/**
|
|
@@ -5668,10 +5813,11 @@ async function applyCrossStackResolverToTask(task, context) {
|
|
|
5668
5813
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") continue;
|
|
5669
5814
|
if (key in container.environment) continue;
|
|
5670
5815
|
if (!isCrossStackIntrinsic(value)) continue;
|
|
5671
|
-
const sub = await
|
|
5816
|
+
const { result: sub, consumedSensitive } = await resolveWithSensitivityAsync(value, context);
|
|
5672
5817
|
if (sub.kind === "literal") {
|
|
5673
5818
|
container.environment[key] = String(sub.value);
|
|
5674
5819
|
resolvedEnvKeys.add(key);
|
|
5820
|
+
if (consumedSensitive && !container.sensitiveEnvKeys.includes(key)) container.sensitiveEnvKeys.push(key);
|
|
5675
5821
|
}
|
|
5676
5822
|
}
|
|
5677
5823
|
if (Array.isArray(c["Secrets"])) for (const entry of c["Secrets"]) {
|
|
@@ -5979,7 +6125,8 @@ async function runDetached(opts) {
|
|
|
5979
6125
|
const ro = mount.readOnly ? ":ro" : "";
|
|
5980
6126
|
args.push("-v", `${mount.hostPath}:${mount.containerPath}${ro}`);
|
|
5981
6127
|
}
|
|
5982
|
-
const
|
|
6128
|
+
const sensitiveKeys = opts.sensitiveEnvKeys && opts.sensitiveEnvKeys.size > 0 ? new Set([...SENSITIVE_ENV_KEYS, ...opts.sensitiveEnvKeys]) : SENSITIVE_ENV_KEYS;
|
|
6129
|
+
const passthroughEnv = appendEnvFlags(args, opts.env, sensitiveKeys);
|
|
5983
6130
|
if (opts.tmpfs) args.push("--tmpfs", `${opts.tmpfs.target}:rw,size=${opts.tmpfs.sizeMb}m`);
|
|
5984
6131
|
if (opts.workingDir) args.push("--workdir", opts.workingDir);
|
|
5985
6132
|
let entryPointTail = [];
|
|
@@ -6437,8 +6584,8 @@ async function assumeRoleForEcr(roleArn, callerRegion, profile, logger) {
|
|
|
6437
6584
|
}
|
|
6438
6585
|
/**
|
|
6439
6586
|
* Authenticate the local docker daemon against the target ECR registry.
|
|
6440
|
-
*
|
|
6441
|
-
*
|
|
6587
|
+
* Self-contained in this module so the local-invoke path stays
|
|
6588
|
+
* independent of any full asset-publish path's larger surface area.
|
|
6442
6589
|
*/
|
|
6443
6590
|
async function ecrLogin(client, accountId, region) {
|
|
6444
6591
|
getLogger().child("ecr-puller").debug(`ECR login (account=${accountId}, region=${region})`);
|
|
@@ -7336,7 +7483,8 @@ async function localInvokeCommand(target, options, extraStateProviders) {
|
|
|
7336
7483
|
}
|
|
7337
7484
|
if (envHasIntrinsicValue$1(templateEnv) && stateProvider.resolveTemplateSsmParameters) {
|
|
7338
7485
|
const ssmParams = await stateProvider.resolveTemplateSsmParameters(lambda.stack.template);
|
|
7339
|
-
if (Object.keys(ssmParams).length > 0) subContext.parameters = ssmParams;
|
|
7486
|
+
if (Object.keys(ssmParams.values).length > 0) subContext.parameters = ssmParams.values;
|
|
7487
|
+
if (ssmParams.secureStringLogicalIds.length > 0) subContext.sensitiveParameters = new Set(ssmParams.secureStringLogicalIds);
|
|
7340
7488
|
}
|
|
7341
7489
|
if (envHasCrossStackIntrinsic(templateEnv)) {
|
|
7342
7490
|
const resolver = await stateProvider.buildCrossStackResolver(loaded.region);
|
|
@@ -7363,7 +7511,8 @@ async function localInvokeCommand(target, options, extraStateProviders) {
|
|
|
7363
7511
|
}
|
|
7364
7512
|
stateAudit = {
|
|
7365
7513
|
resolvedKeys,
|
|
7366
|
-
unresolved
|
|
7514
|
+
unresolved,
|
|
7515
|
+
sensitiveKeys: audit.sensitiveKeys
|
|
7367
7516
|
};
|
|
7368
7517
|
for (const { key, reason } of unresolved) logger.warn(`${label}: could not substitute env var ${key} (${reason}). Override it via --env-vars or it will be dropped.`);
|
|
7369
7518
|
}
|
|
@@ -7443,6 +7592,7 @@ async function localInvokeCommand(target, options, extraStateProviders) {
|
|
|
7443
7592
|
mounts: imagePlan.mounts,
|
|
7444
7593
|
extraMounts: extraMountsWithProfile,
|
|
7445
7594
|
env: dockerEnv,
|
|
7595
|
+
...stateAudit && stateAudit.sensitiveKeys.length > 0 && { sensitiveEnvKeys: new Set(stateAudit.sensitiveKeys) },
|
|
7446
7596
|
cmd: imagePlan.cmd,
|
|
7447
7597
|
hostPort,
|
|
7448
7598
|
host: containerHost,
|
|
@@ -10409,6 +10559,7 @@ function createContainerPool(specs, options) {
|
|
|
10409
10559
|
}],
|
|
10410
10560
|
extraMounts,
|
|
10411
10561
|
env: spec.env,
|
|
10562
|
+
...spec.sensitiveEnvKeys !== void 0 && { sensitiveEnvKeys: spec.sensitiveEnvKeys },
|
|
10412
10563
|
cmd: [spec.lambda.handler],
|
|
10413
10564
|
hostPort,
|
|
10414
10565
|
host: spec.containerHost,
|
|
@@ -10426,6 +10577,7 @@ function createContainerPool(specs, options) {
|
|
|
10426
10577
|
readOnly: true
|
|
10427
10578
|
}] },
|
|
10428
10579
|
env: spec.env,
|
|
10580
|
+
...spec.sensitiveEnvKeys !== void 0 && { sensitiveEnvKeys: spec.sensitiveEnvKeys },
|
|
10429
10581
|
cmd: spec.command,
|
|
10430
10582
|
hostPort,
|
|
10431
10583
|
host: spec.containerHost,
|
|
@@ -14643,9 +14795,9 @@ function groupRoutesByServer(routes) {
|
|
|
14643
14795
|
* exact match on the resource's `aws:cdk:path` metadata.
|
|
14644
14796
|
* 4. **CDK Construct path prefix** — when the input is a strict
|
|
14645
14797
|
* ancestor of the resource's `aws:cdk:path` (i.e.
|
|
14646
|
-
* `cdkPath.startsWith(input + '/')`). Mirrors the
|
|
14647
|
-
*
|
|
14648
|
-
* child (`MyStack/MyHttpApi` matches `MyStack/MyHttpApi/Resource`).
|
|
14798
|
+
* `cdkPath.startsWith(input + '/')`). Mirrors the upstream CDK
|
|
14799
|
+
* construct-path prefix rule so an L2 wrapper path resolves to its
|
|
14800
|
+
* L1 child (`MyStack/MyHttpApi` matches `MyStack/MyHttpApi/Resource`).
|
|
14649
14801
|
*
|
|
14650
14802
|
* Routes discovered before this field set was added (or routes where
|
|
14651
14803
|
* the synthesized template doesn't carry `aws:cdk:path` metadata —
|
|
@@ -15031,7 +15183,7 @@ async function localStartApiCommand(targets, options, extraStateProviders) {
|
|
|
15031
15183
|
if (shouldPromptBare && !interactivePicked.value) {
|
|
15032
15184
|
const apis = listTargets(stacks).apis;
|
|
15033
15185
|
if (apis.length === 0) throw new Error(`No APIs found in this CDK app to choose from. Run \`${getEmbedConfig().cliName} list\` to see what is available.`);
|
|
15034
|
-
const picked = await pickManyTargets("Select APIs to serve", apis
|
|
15186
|
+
const picked = await pickManyTargets("Select APIs to serve", apis);
|
|
15035
15187
|
apiFilters = picked;
|
|
15036
15188
|
effectiveTargets = picked;
|
|
15037
15189
|
interactivePicked.value = true;
|
|
@@ -15784,6 +15936,7 @@ async function buildContainerSpec(args) {
|
|
|
15784
15936
|
const context = { resources: stateBundle.state.resources };
|
|
15785
15937
|
if (stateBundle.pseudoParameters) context.pseudoParameters = stateBundle.pseudoParameters;
|
|
15786
15938
|
if (stateBundle.ssmParameters) context.parameters = stateBundle.ssmParameters;
|
|
15939
|
+
if (stateBundle.ssmSecureStringLogicalIds?.length) context.sensitiveParameters = new Set(stateBundle.ssmSecureStringLogicalIds);
|
|
15787
15940
|
const { env, audit } = substituteEnvVarsFromState(templateEnv, context);
|
|
15788
15941
|
templateEnv = env;
|
|
15789
15942
|
for (const key of audit.resolvedKeys) getLogger().debug(`Lambda ${logicalId}: state source substituted env var ${key}`);
|
|
@@ -15801,7 +15954,8 @@ async function buildContainerSpec(args) {
|
|
|
15801
15954
|
}
|
|
15802
15955
|
stateAudit = {
|
|
15803
15956
|
resolvedKeys,
|
|
15804
|
-
unresolved
|
|
15957
|
+
unresolved,
|
|
15958
|
+
sensitiveKeys: audit.sensitiveKeys
|
|
15805
15959
|
};
|
|
15806
15960
|
for (const { key, reason } of unresolved) getLogger().warn(`Lambda ${logicalId}: state source could not substitute env var ${key} (${reason}). Override it via --env-vars or it will be dropped.`);
|
|
15807
15961
|
}
|
|
@@ -15854,11 +16008,13 @@ async function buildContainerSpec(args) {
|
|
|
15854
16008
|
target: "/tmp",
|
|
15855
16009
|
sizeMb: lambda.ephemeralStorageMb
|
|
15856
16010
|
} : void 0;
|
|
16011
|
+
const sensitiveEnvKeys = stateAudit && stateAudit.sensitiveKeys.length > 0 ? new Set(stateAudit.sensitiveKeys) : void 0;
|
|
15857
16012
|
if (lambda.kind === "zip") return {
|
|
15858
16013
|
kind: "zip",
|
|
15859
16014
|
lambda,
|
|
15860
16015
|
codeDir,
|
|
15861
16016
|
env: dockerEnv,
|
|
16017
|
+
...sensitiveEnvKeys && { sensitiveEnvKeys },
|
|
15862
16018
|
containerHost,
|
|
15863
16019
|
...optDir !== void 0 && { optDir },
|
|
15864
16020
|
...debugPort !== void 0 && { debugPort },
|
|
@@ -15877,6 +16033,7 @@ async function buildContainerSpec(args) {
|
|
|
15877
16033
|
...lambda.imageConfig.entryPoint !== void 0 && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
|
|
15878
16034
|
...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory },
|
|
15879
16035
|
env: dockerEnv,
|
|
16036
|
+
...sensitiveEnvKeys && { sensitiveEnvKeys },
|
|
15880
16037
|
containerHost,
|
|
15881
16038
|
...debugPort !== void 0 && { debugPort },
|
|
15882
16039
|
...tmpfs !== void 0 && { tmpfs },
|
|
@@ -16238,10 +16395,10 @@ function forwardAwsEnv(env) {
|
|
|
16238
16395
|
* AWS SDK call fails with `Could not load credentials from any providers`.
|
|
16239
16396
|
*
|
|
16240
16397
|
* This helper constructs a transient `STSClient({ profile })` to drive
|
|
16241
|
-
* the SDK's default credential provider chain — same code path
|
|
16242
|
-
* own
|
|
16398
|
+
* the SDK's default credential provider chain — same code path the
|
|
16399
|
+
* host's own AWS SDK clients use when `--profile` is set, so SSO / IAM
|
|
16243
16400
|
* Identity Center / role-assumption profiles all resolve the same way
|
|
16244
|
-
* they already do for
|
|
16401
|
+
* they already do for the host's outbound calls. We then extract the
|
|
16245
16402
|
* resolved `AwsCredentialIdentity` via `sts.config.credentials()` and
|
|
16246
16403
|
* return the underlying `{ accessKeyId, secretAccessKey, sessionToken? }`
|
|
16247
16404
|
* for env-var injection.
|
|
@@ -16595,7 +16752,8 @@ async function loadStateForRoutedStacks(stacks, routes, routesWithAuth, options,
|
|
|
16595
16752
|
}
|
|
16596
16753
|
if (stackHasIntrinsicEnv(stackName) && provider.resolveTemplateSsmParameters) {
|
|
16597
16754
|
const ssmParameters = await provider.resolveTemplateSsmParameters(stack.template);
|
|
16598
|
-
if (Object.keys(ssmParameters).length > 0) bundle.ssmParameters = ssmParameters;
|
|
16755
|
+
if (Object.keys(ssmParameters.values).length > 0) bundle.ssmParameters = ssmParameters.values;
|
|
16756
|
+
if (ssmParameters.secureStringLogicalIds.length > 0) bundle.ssmSecureStringLogicalIds = ssmParameters.secureStringLogicalIds;
|
|
16599
16757
|
}
|
|
16600
16758
|
out.set(stackName, bundle);
|
|
16601
16759
|
logger.debug(`${provider.label}: loaded state for ${stackName} (${loaded.region})`);
|
|
@@ -17644,6 +17802,7 @@ function buildDockerRunArgs(opts) {
|
|
|
17644
17802
|
}
|
|
17645
17803
|
const sensitiveEnvKeys = new Set(SENSITIVE_ENV_KEYS);
|
|
17646
17804
|
for (const s of secrets) sensitiveEnvKeys.add(s.name);
|
|
17805
|
+
for (const k of container.sensitiveEnvKeys) sensitiveEnvKeys.add(k);
|
|
17647
17806
|
const sensitiveEnv = appendEnvFlags(args, finalEnv, sensitiveEnvKeys);
|
|
17648
17807
|
if (container.user) args.push("--user", container.user);
|
|
17649
17808
|
if (container.privileged) args.push("--privileged");
|
|
@@ -17760,6 +17919,7 @@ async function localRunTaskCommand(target, options, extraStateProviders) {
|
|
|
17760
17919
|
resources: imageContext?.stateResources ?? {},
|
|
17761
17920
|
...imageContext?.pseudoParameters && { pseudoParameters: imageContext.pseudoParameters },
|
|
17762
17921
|
...imageContext?.stateParameters && { parameters: imageContext.stateParameters },
|
|
17922
|
+
...imageContext?.stateSensitiveParameters?.length && { sensitiveParameters: new Set(imageContext.stateSensitiveParameters) },
|
|
17763
17923
|
consumerRegion,
|
|
17764
17924
|
crossStackResolver: resolver
|
|
17765
17925
|
});
|
|
@@ -17899,7 +18059,8 @@ async function buildEcsImageResolutionContext$1(candidate, stateProvider, option
|
|
|
17899
18059
|
if (loaded) ctx.stateResources = loaded.resources;
|
|
17900
18060
|
if (needs.needsEnvOrSecretSubstitution && stateProvider.resolveTemplateSsmParameters) {
|
|
17901
18061
|
const ssmParameters = await stateProvider.resolveTemplateSsmParameters(candidate.template);
|
|
17902
|
-
if (Object.keys(ssmParameters).length > 0) ctx.stateParameters = ssmParameters;
|
|
18062
|
+
if (Object.keys(ssmParameters.values).length > 0) ctx.stateParameters = ssmParameters.values;
|
|
18063
|
+
if (ssmParameters.secureStringLogicalIds.length > 0) ctx.stateSensitiveParameters = ssmParameters.secureStringLogicalIds;
|
|
17903
18064
|
}
|
|
17904
18065
|
} else if (!stateProvider && needs.needsStateResources) logger.warn("Container Image references a same-stack AWS::ECR::Repository. Pass a state-source flag (e.g. --from-cfn-stack or a host-provided extension) to substitute the deployed repository URI. Otherwise the resolver will surface its existing error.");
|
|
17905
18066
|
else if (!stateProvider && needs.needsEnvOrSecretSubstitution) logger.warn("Container Environment / Secrets entries contain CloudFormation intrinsics (Ref / Fn::GetAtt / Fn::Sub / Fn::Join). Pass a state-source flag (e.g. --from-cfn-stack or a host-provided extension) to substitute them against deployed state. Without a state source these entries are dropped (per-key warnings will follow).");
|
|
@@ -17948,7 +18109,7 @@ function readEnvOverridesFile$1(filePath) {
|
|
|
17948
18109
|
return parsed;
|
|
17949
18110
|
}
|
|
17950
18111
|
/**
|
|
17951
|
-
*
|
|
18112
|
+
* Pick the credentials forwarded to the AWS-published
|
|
17952
18113
|
* `amazon-ecs-local-container-endpoints` sidecar. Precedence:
|
|
17953
18114
|
* 1. `--assume-task-role <arn>` (or bare `--assume-task-role` against
|
|
17954
18115
|
* a resolvable `TaskRoleArn`) → STS-assumed temp creds. Highest
|
|
@@ -17964,7 +18125,7 @@ function readEnvOverridesFile$1(filePath) {
|
|
|
17964
18125
|
*
|
|
17965
18126
|
* Extracted as an exported helper so a unit test can exercise every
|
|
17966
18127
|
* branch without having to mock the full Synth + Docker + AWS pipeline
|
|
17967
|
-
* (the strategy
|
|
18128
|
+
* (the strategy used for the Lambda container path).
|
|
17968
18129
|
*/
|
|
17969
18130
|
async function resolveSidecarCredentials(options, assumedCredentials) {
|
|
17970
18131
|
if (assumedCredentials) return assumedCredentials;
|
|
@@ -18717,7 +18878,7 @@ function pickEssentialContainerId(instance, service) {
|
|
|
18717
18878
|
const defaultWaitForExitImpl = async (containerId) => {
|
|
18718
18879
|
const { execFile } = await import("node:child_process");
|
|
18719
18880
|
const { promisify } = await import("node:util");
|
|
18720
|
-
const { getDockerCmd } = await import("./docker-cmd
|
|
18881
|
+
const { getDockerCmd } = await import("./docker-cmd-voNPrcRh.js").then((n) => n.t);
|
|
18721
18882
|
const { stdout } = await promisify(execFile)(getDockerCmd(), ["wait", containerId], { maxBuffer: 1024 * 1024 });
|
|
18722
18883
|
const code = parseInt(stdout.trim(), 10);
|
|
18723
18884
|
return Number.isFinite(code) ? code : -1;
|
|
@@ -18737,7 +18898,7 @@ const EXIT_LOG_TAIL_LINES = 50;
|
|
|
18737
18898
|
const defaultReadContainerLogsImpl = async (containerId) => {
|
|
18738
18899
|
const { execFile } = await import("node:child_process");
|
|
18739
18900
|
const { promisify } = await import("node:util");
|
|
18740
|
-
const { getDockerCmd } = await import("./docker-cmd
|
|
18901
|
+
const { getDockerCmd } = await import("./docker-cmd-voNPrcRh.js").then((n) => n.t);
|
|
18741
18902
|
const { stdout, stderr } = await promisify(execFile)(getDockerCmd(), [
|
|
18742
18903
|
"logs",
|
|
18743
18904
|
"--tail",
|
|
@@ -19240,6 +19401,7 @@ async function runOneTarget(target, runState, stacks, options, discovery, skipPu
|
|
|
19240
19401
|
resources: imageContext?.stateResources ?? {},
|
|
19241
19402
|
...imageContext?.pseudoParameters && { pseudoParameters: imageContext.pseudoParameters },
|
|
19242
19403
|
...imageContext?.stateParameters && { parameters: imageContext.stateParameters },
|
|
19404
|
+
...imageContext?.stateSensitiveParameters?.length && { sensitiveParameters: new Set(imageContext.stateSensitiveParameters) },
|
|
19243
19405
|
consumerRegion,
|
|
19244
19406
|
crossStackResolver: resolver
|
|
19245
19407
|
};
|
|
@@ -19356,7 +19518,8 @@ async function buildEcsImageResolutionContext(target, stacks, options, stateProv
|
|
|
19356
19518
|
if (loaded) ctx.stateResources = loaded.resources;
|
|
19357
19519
|
if (needs.needsEnvOrSecretSubstitution && stateProvider.resolveTemplateSsmParameters) {
|
|
19358
19520
|
const ssmParameters = await stateProvider.resolveTemplateSsmParameters(candidate.template);
|
|
19359
|
-
if (Object.keys(ssmParameters).length > 0) ctx.stateParameters = ssmParameters;
|
|
19521
|
+
if (Object.keys(ssmParameters.values).length > 0) ctx.stateParameters = ssmParameters.values;
|
|
19522
|
+
if (ssmParameters.secureStringLogicalIds.length > 0) ctx.stateSensitiveParameters = ssmParameters.secureStringLogicalIds;
|
|
19360
19523
|
}
|
|
19361
19524
|
} else if (!stateProvider && needs.needsStateResources) logger.warn("Container Image references a same-stack AWS::ECR::Repository. Pass a state-source flag (e.g. --from-cfn-stack or a host-provided extension) to substitute the deployed repository URI.");
|
|
19362
19525
|
else if (!stateProvider && needs.needsEnvOrSecretSubstitution) logger.warn("Container Environment / Secrets entries contain CloudFormation intrinsics. Pass a state-source flag (e.g. --from-cfn-stack or a host-provided extension) to substitute them against the deployed state.");
|
|
@@ -19420,7 +19583,7 @@ function parseRestartPolicy(raw) {
|
|
|
19420
19583
|
throw new LocalStartServiceError(`--restart-policy must be one of 'on-failure', 'always', or 'none' (got '${raw}').`);
|
|
19421
19584
|
}
|
|
19422
19585
|
/**
|
|
19423
|
-
*
|
|
19586
|
+
* Pick the credentials forwarded to the AWS-published
|
|
19424
19587
|
* `amazon-ecs-local-container-endpoints` sidecar. `cdkl start-service`'s
|
|
19425
19588
|
* sidecar is SHARED across every replica boot in one CLI invocation, so
|
|
19426
19589
|
* this resolves ONCE at startup. Precedence:
|
|
@@ -19441,7 +19604,7 @@ function parseRestartPolicy(raw) {
|
|
|
19441
19604
|
*
|
|
19442
19605
|
* Extracted as an exported helper so a unit test can exercise both
|
|
19443
19606
|
* branches without having to mock the full Synth + Docker + AWS
|
|
19444
|
-
* pipeline (the strategy
|
|
19607
|
+
* pipeline (the strategy used for the Lambda container path).
|
|
19445
19608
|
*/
|
|
19446
19609
|
async function resolveSharedSidecarCredentials(options) {
|
|
19447
19610
|
if (options.profile) return resolveProfileCredentials(options.profile);
|
|
@@ -19530,4 +19693,4 @@ function createLocalListCommand(opts = {}) {
|
|
|
19530
19693
|
|
|
19531
19694
|
//#endregion
|
|
19532
19695
|
export { ConnectionRegistry as $, computeRequestIdentityHash as A, collectSsmParameterRefs as At, matchRoute as B, resolveLambdaArnIntrinsic as Bt, defaultCredentialsLoader as C, createLocalStateProvider as Ct, verifyCognitoJwt as D, resolveCfnRegion as Dt, createJwksCache as E, resolveCfnFallbackRegion as Et, applyCorsResponseHeaders as F, discoverWebSocketApis as Ft, evaluateResponseParameters as G, applyAuthorizerOverlay as H, buildCorsConfigByApiId as I, discoverWebSocketApisOrThrow as It, tryParseStatus as J, pickResponseTemplate as K, buildCorsConfigFromCloudFrontChain as L, parseSelectionExpressionPath as Lt, invokeRequestAuthorizer as M, resolveWatchConfig as Mt, invokeTokenAuthorizer as N, countTargets as Nt, verifyJwtAuthorizer as O, resolveCfnStackName as Ot, attachAuthorizers as P, listTargets as Pt, bufferToBody as Q, isFunctionUrlOacFronted as R, discoverRoutes as Rt, resolveServiceIntegrationParameters as S, LocalStateSourceError as St, buildJwksUrlFromIssuer as T, rejectExplicitCfnStackWithMultipleStacks as Tt, buildHttpApiV2Event as U, translateLambdaResponse as V, LocalInvokeBuildError as Vt, buildRestV1Event as W, HOST_GATEWAY_MIN_VERSION as X, VtlEvaluationError as Y, probeHostGatewaySupport as Z, filterRoutesByApiIdentifiers as _, resolveEnvVars as _t, CloudMapRegistry as a, buildMessageEvent as at, startApiServer as b, substituteImagePlaceholders as bt, createLocalStartApiCommand as c, buildContainerImage as ct, createAuthorizerCache as d, resolveRuntimeImage as dt, buildMgmtEndpointEnvUrl as et, createFileWatcher as f, EcsTaskResolutionError as ft, filterRoutesByApiIdentifier as g, substituteEnvVarsFromStateAsync as gt, availableApiIdentifiers as h, substituteEnvVarsFromState as ht, buildCloudMapIndex as i, buildDisconnectEvent as it, evaluateCachedLambdaPolicy as j, resolveSsmParameters as jt, buildMethodArn as k, CfnLocalStateProvider as kt, createWatchPredicates as l, resolveRuntimeCodeMountPath as lt, buildStageMap as m, substituteAgainstStateAsync as mt, formatTargetListing as n, parseConnectionsPath as nt, getContainerNetworkIp as o, createLocalInvokeCommand as ot, attachStageContext as p, substituteAgainstState as pt, selectIntegrationResponse as q, createLocalStartServiceCommand as r, buildConnectEvent as rt, createLocalRunTaskCommand as s, architectureToPlatform as st, createLocalListCommand as t, handleConnectionsRequest as tt, resolveApiTargetSubset as u, resolveRuntimeFileExtension as ut, groupRoutesByServer as v, materializeLayerFromArn as vt, buildCognitoJwksUrl as w, isCfnFlagPresent as wt, resolveSelectionExpression as x, tryResolveImageFnJoin as xt, readMtlsMaterialsFromDisk as y, derivePseudoParametersFromRegion as yt, matchPreflight as z, pickRefLogicalId as zt };
|
|
19533
|
-
//# sourceMappingURL=local-list-
|
|
19696
|
+
//# sourceMappingURL=local-list-8fAEdzBb.js.map
|