cdk-local 0.35.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 +1 -1
- 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-BvDCmBir.js → local-list-8fAEdzBb.js} +145 -62
- package/dist/local-list-8fAEdzBb.js.map +1 -0
- package/package.json +1 -1
- package/dist/docker-cmd--8TRSn9z.js.map +0 -1
- package/dist/local-list-BvDCmBir.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
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";
|
|
@@ -313,9 +313,6 @@ function withErrorHandling(fn) {
|
|
|
313
313
|
* Read the `aws:cdk:path` value that CDK encodes into every resource's
|
|
314
314
|
* `Metadata`. Returns the empty string when not present so callers don't
|
|
315
315
|
* have to special-case `undefined`.
|
|
316
|
-
*
|
|
317
|
-
* Hoisted out of `src/cli/commands/import.ts` so `cdkd orphan` can reuse the
|
|
318
|
-
* same lookup without duplicating the metadata-walking code.
|
|
319
316
|
*/
|
|
320
317
|
function readCdkPath(resource) {
|
|
321
318
|
const meta = resource.Metadata;
|
|
@@ -341,10 +338,9 @@ function readCdkPathOrUndefined(resource) {
|
|
|
341
338
|
/**
|
|
342
339
|
* Build a `Map<cdkPath, logicalId>` from a synthesized template.
|
|
343
340
|
*
|
|
344
|
-
*
|
|
345
|
-
* construct
|
|
346
|
-
*
|
|
347
|
-
* 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.
|
|
348
344
|
*
|
|
349
345
|
* `AWS::CDK::Metadata` resources are excluded — the synthesized
|
|
350
346
|
* `<Stack>/CDKMetadata/Default` sentinel exists in every stack but is
|
|
@@ -356,7 +352,7 @@ function readCdkPathOrUndefined(resource) {
|
|
|
356
352
|
*
|
|
357
353
|
* In practice each path maps to a single logical ID. If the same path
|
|
358
354
|
* happens to appear twice (which would itself be a bug in the synthesized
|
|
359
|
-
* template), the last entry wins —
|
|
355
|
+
* template), the last entry wins — callers still surface a
|
|
360
356
|
* clean "path not found" diff against the indexed map rather than
|
|
361
357
|
* silently grabbing both.
|
|
362
358
|
*/
|
|
@@ -2356,9 +2352,9 @@ function mapStackArtifact(stack) {
|
|
|
2356
2352
|
//#endregion
|
|
2357
2353
|
//#region src/synthesis/synthesizer.ts
|
|
2358
2354
|
/**
|
|
2359
|
-
* Thin wrapper around {@link AssemblyReader}
|
|
2360
|
-
*
|
|
2361
|
-
* `
|
|
2355
|
+
* Thin wrapper around {@link AssemblyReader} exposing a `Synthesizer`
|
|
2356
|
+
* API used by the `cdkl invoke` / `start-api` / `run-task` /
|
|
2357
|
+
* `start-service` commands.
|
|
2362
2358
|
*
|
|
2363
2359
|
* When `app` resolves to an existing directory it is read as a
|
|
2364
2360
|
* pre-synthesized cloud assembly (no subprocess synth); otherwise it is
|
|
@@ -2527,15 +2523,16 @@ function collectSsmParameterRefs(template) {
|
|
|
2527
2523
|
* String parameters resolve too (matching how CloudFormation resolves
|
|
2528
2524
|
* the `AWS::SSM::Parameter::Value<String>` type at deploy time).
|
|
2529
2525
|
*
|
|
2530
|
-
* Security note: a decrypted SecureString value resolved here
|
|
2531
|
-
* baked into the container's `Environment` like any
|
|
2532
|
-
*
|
|
2533
|
-
*
|
|
2534
|
-
*
|
|
2535
|
-
*
|
|
2536
|
-
*
|
|
2537
|
-
*
|
|
2538
|
-
*
|
|
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.
|
|
2539
2536
|
*
|
|
2540
2537
|
* Best-effort: a failed `GetParameters` chunk logs a warn and is skipped
|
|
2541
2538
|
* (the other chunks still contribute their values); the function never
|
|
@@ -2547,7 +2544,10 @@ function collectSsmParameterRefs(template) {
|
|
|
2547
2544
|
* Exported for unit testing.
|
|
2548
2545
|
*/
|
|
2549
2546
|
async function resolveSsmParameters(client, refs, label) {
|
|
2550
|
-
const out = {
|
|
2547
|
+
const out = {
|
|
2548
|
+
values: {},
|
|
2549
|
+
secureStringLogicalIds: []
|
|
2550
|
+
};
|
|
2551
2551
|
if (refs.length === 0) return out;
|
|
2552
2552
|
const logger = getLogger();
|
|
2553
2553
|
const CHUNK = 10;
|
|
@@ -2577,7 +2577,11 @@ async function resolveSsmParameters(client, refs, label) {
|
|
|
2577
2577
|
if (typeof p.Name !== "string" || typeof p.Value !== "string") continue;
|
|
2578
2578
|
const requesters = byName.get(p.Name);
|
|
2579
2579
|
if (!requesters) continue;
|
|
2580
|
-
|
|
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
|
+
}
|
|
2581
2585
|
}
|
|
2582
2586
|
}
|
|
2583
2587
|
return out;
|
|
@@ -2712,7 +2716,10 @@ var CfnLocalStateProvider = class {
|
|
|
2712
2716
|
async resolveTemplateSsmParameters(template) {
|
|
2713
2717
|
if (this.disposed) throw new Error("CfnLocalStateProvider used after dispose()");
|
|
2714
2718
|
const refs = collectSsmParameterRefs(template);
|
|
2715
|
-
if (refs.length === 0) return {
|
|
2719
|
+
if (refs.length === 0) return {
|
|
2720
|
+
values: {},
|
|
2721
|
+
secureStringLogicalIds: []
|
|
2722
|
+
};
|
|
2716
2723
|
return resolveSsmParameters(this.getSsmClient(), refs, this.label);
|
|
2717
2724
|
}
|
|
2718
2725
|
/**
|
|
@@ -3001,8 +3008,8 @@ async function resolveProfileRegion(profile) {
|
|
|
3001
3008
|
* Host-extensible state sources (via the `extraStateProviders` option):
|
|
3002
3009
|
*
|
|
3003
3010
|
* - Hosts embedding cdk-local can register additional `LocalStateProvider`
|
|
3004
|
-
* factories that respond to their own CLI flags (e.g.
|
|
3005
|
-
* `--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
|
|
3006
3013
|
* the camel-case Commander option name (e.g. `'fromState'`) so the
|
|
3007
3014
|
* dispatcher reads the corresponding boolean / string off the parsed
|
|
3008
3015
|
* options bag.
|
|
@@ -3126,7 +3133,7 @@ function rejectExplicitCfnStackWithMultipleStacks(options, routedStackCount) {
|
|
|
3126
3133
|
* fallback for the CFn client when no explicit region override is set.
|
|
3127
3134
|
*
|
|
3128
3135
|
* `extraStateProviders` is the host-supplied registry of additional
|
|
3129
|
-
* state sources (e.g.
|
|
3136
|
+
* state sources (e.g. a host's `--from-state` / S3-backed provider).
|
|
3130
3137
|
* Each entry's key is the camel-case Commander option name; the
|
|
3131
3138
|
* dispatcher activates the matching factory when the corresponding
|
|
3132
3139
|
* options field is truthy.
|
|
@@ -3182,7 +3189,7 @@ function stackMatchesPattern(stack, pattern) {
|
|
|
3182
3189
|
//#region src/local/intrinsic-image.ts
|
|
3183
3190
|
/**
|
|
3184
3191
|
* Derive the AWS pseudo parameters that are trivially knowable from the
|
|
3185
|
-
* deploy region alone, without any STS call or
|
|
3192
|
+
* deploy region alone, without any STS call or state load.
|
|
3186
3193
|
* `urlSuffix` and `partition` follow the canonical AWS partition rules:
|
|
3187
3194
|
*
|
|
3188
3195
|
* - region prefix `cn-*` → partition `aws-cn`, urlSuffix `amazonaws.com.cn`
|
|
@@ -3239,7 +3246,7 @@ function derivePseudoParametersFromRegion(region, accountId) {
|
|
|
3239
3246
|
* nested `Fn::Select` / `Fn::Split` over an `Fn::GetAtt: [<Repo>, 'Arn']`
|
|
3240
3247
|
* plus a `Ref` to the same `AWS::ECR::Repository` and a
|
|
3241
3248
|
* `Ref: AWS::URLSuffix`. For SAME-STACK references the account-id +
|
|
3242
|
-
* region only exist in
|
|
3249
|
+
* region only exist in the host's S3 state (recorded at deploy time on the
|
|
3243
3250
|
* Repository's `Arn` attribute), so the resolver inherently requires
|
|
3244
3251
|
* `--from-state` (Tier 2) for that variant. For IMPORTED repositories
|
|
3245
3252
|
* the URI components are flat strings + `Ref: AWS::URLSuffix` and
|
|
@@ -4258,10 +4265,13 @@ function resolveRef(arg, context) {
|
|
|
4258
4265
|
value: resource.physicalId
|
|
4259
4266
|
};
|
|
4260
4267
|
const parameterValue = context.parameters?.[arg];
|
|
4261
|
-
if (parameterValue !== void 0)
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4268
|
+
if (parameterValue !== void 0) {
|
|
4269
|
+
if (context.sensitiveParameters?.has(arg)) context.onSensitiveParameterConsumed?.(arg);
|
|
4270
|
+
return {
|
|
4271
|
+
kind: "literal",
|
|
4272
|
+
value: parameterValue
|
|
4273
|
+
};
|
|
4274
|
+
}
|
|
4265
4275
|
return {
|
|
4266
4276
|
kind: "unresolved",
|
|
4267
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?)`
|
|
@@ -4737,7 +4747,8 @@ function substituteEnvVarsFromState(templateEnv, contextOrResources) {
|
|
|
4737
4747
|
const env = {};
|
|
4738
4748
|
const audit = {
|
|
4739
4749
|
resolvedKeys: [],
|
|
4740
|
-
unresolved: []
|
|
4750
|
+
unresolved: [],
|
|
4751
|
+
sensitiveKeys: []
|
|
4741
4752
|
};
|
|
4742
4753
|
if (!templateEnv) return {
|
|
4743
4754
|
env,
|
|
@@ -4749,10 +4760,11 @@ function substituteEnvVarsFromState(templateEnv, contextOrResources) {
|
|
|
4749
4760
|
env[key] = value;
|
|
4750
4761
|
continue;
|
|
4751
4762
|
}
|
|
4752
|
-
const result =
|
|
4763
|
+
const { result, consumedSensitive } = resolveWithSensitivity(value, context);
|
|
4753
4764
|
if (result.kind === "literal") {
|
|
4754
4765
|
env[key] = result.value;
|
|
4755
4766
|
audit.resolvedKeys.push(key);
|
|
4767
|
+
if (consumedSensitive) audit.sensitiveKeys.push(key);
|
|
4756
4768
|
} else audit.unresolved.push({
|
|
4757
4769
|
key,
|
|
4758
4770
|
reason: result.reason
|
|
@@ -4764,6 +4776,53 @@ function substituteEnvVarsFromState(templateEnv, contextOrResources) {
|
|
|
4764
4776
|
};
|
|
4765
4777
|
}
|
|
4766
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
|
+
/**
|
|
4767
4826
|
* Async sibling of {@link substituteEnvVarsFromState}. Routes every
|
|
4768
4827
|
* intrinsic-valued entry through {@link substituteAgainstStateAsync} so
|
|
4769
4828
|
* `Fn::ImportValue` / `Fn::GetStackOutput` resolve via the context's
|
|
@@ -4781,7 +4840,8 @@ async function substituteEnvVarsFromStateAsync(templateEnv, contextOrResources)
|
|
|
4781
4840
|
const env = {};
|
|
4782
4841
|
const audit = {
|
|
4783
4842
|
resolvedKeys: [],
|
|
4784
|
-
unresolved: []
|
|
4843
|
+
unresolved: [],
|
|
4844
|
+
sensitiveKeys: []
|
|
4785
4845
|
};
|
|
4786
4846
|
if (!templateEnv) return {
|
|
4787
4847
|
env,
|
|
@@ -4793,10 +4853,11 @@ async function substituteEnvVarsFromStateAsync(templateEnv, contextOrResources)
|
|
|
4793
4853
|
env[key] = value;
|
|
4794
4854
|
continue;
|
|
4795
4855
|
}
|
|
4796
|
-
const result = await
|
|
4856
|
+
const { result, consumedSensitive } = await resolveWithSensitivityAsync(value, context);
|
|
4797
4857
|
if (result.kind === "literal") {
|
|
4798
4858
|
env[key] = result.value;
|
|
4799
4859
|
audit.resolvedKeys.push(key);
|
|
4860
|
+
if (consumedSensitive) audit.sensitiveKeys.push(key);
|
|
4800
4861
|
} else audit.unresolved.push({
|
|
4801
4862
|
key,
|
|
4802
4863
|
reason: result.reason
|
|
@@ -5117,7 +5178,7 @@ function parseEcsTarget(target) {
|
|
|
5117
5178
|
* available task definition in the matched stack) on any miss.
|
|
5118
5179
|
*
|
|
5119
5180
|
* Optional `context` (issue #264): when the caller can supply AWS
|
|
5120
|
-
* pseudo-parameter values (Tier 1) and / or
|
|
5181
|
+
* pseudo-parameter values (Tier 1) and / or host state-recorded resources
|
|
5121
5182
|
* (Tier 2), `Fn::Sub`-shaped ECR image URIs that reference
|
|
5122
5183
|
* `${AWS::AccountId}` / `${AWS::Region}` / a same-stack
|
|
5123
5184
|
* `AWS::ECR::Repository` are substituted before classification.
|
|
@@ -5218,6 +5279,7 @@ function parseContainerDefinition(raw, idx, taskLogicalId, resources, stack, con
|
|
|
5218
5279
|
const workingDirectory = pickString(c["WorkingDirectory"]);
|
|
5219
5280
|
const subContext = buildSubstitutionContextFromImageContext(context);
|
|
5220
5281
|
const environment = {};
|
|
5282
|
+
const sensitiveEnvKeys = [];
|
|
5221
5283
|
const droppedEnvKeys = [];
|
|
5222
5284
|
if (Array.isArray(c["Environment"])) for (const entry of c["Environment"]) {
|
|
5223
5285
|
if (!entry || typeof entry !== "object") continue;
|
|
@@ -5230,9 +5292,10 @@ function parseContainerDefinition(raw, idx, taskLogicalId, resources, stack, con
|
|
|
5230
5292
|
continue;
|
|
5231
5293
|
}
|
|
5232
5294
|
if (subContext) {
|
|
5233
|
-
const sub =
|
|
5295
|
+
const { result: sub, consumedSensitive } = resolveWithSensitivity(value, subContext);
|
|
5234
5296
|
if (sub.kind === "literal") {
|
|
5235
5297
|
environment[key] = String(sub.value);
|
|
5298
|
+
if (consumedSensitive) sensitiveEnvKeys.push(key);
|
|
5236
5299
|
continue;
|
|
5237
5300
|
}
|
|
5238
5301
|
droppedEnvKeys.push({
|
|
@@ -5357,6 +5420,7 @@ function parseContainerDefinition(raw, idx, taskLogicalId, resources, stack, con
|
|
|
5357
5420
|
name,
|
|
5358
5421
|
image,
|
|
5359
5422
|
environment,
|
|
5423
|
+
sensitiveEnvKeys,
|
|
5360
5424
|
secrets,
|
|
5361
5425
|
portMappings,
|
|
5362
5426
|
mountPoints,
|
|
@@ -5386,6 +5450,7 @@ function buildSubstitutionContextFromImageContext(context) {
|
|
|
5386
5450
|
const subContext = { resources: context.stateResources };
|
|
5387
5451
|
if (context.pseudoParameters) subContext.pseudoParameters = { ...context.pseudoParameters };
|
|
5388
5452
|
if (context.stateParameters) subContext.parameters = { ...context.stateParameters };
|
|
5453
|
+
if (context.stateSensitiveParameters?.length) subContext.sensitiveParameters = new Set(context.stateSensitiveParameters);
|
|
5389
5454
|
return subContext;
|
|
5390
5455
|
}
|
|
5391
5456
|
/**
|
|
@@ -5748,10 +5813,11 @@ async function applyCrossStackResolverToTask(task, context) {
|
|
|
5748
5813
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") continue;
|
|
5749
5814
|
if (key in container.environment) continue;
|
|
5750
5815
|
if (!isCrossStackIntrinsic(value)) continue;
|
|
5751
|
-
const sub = await
|
|
5816
|
+
const { result: sub, consumedSensitive } = await resolveWithSensitivityAsync(value, context);
|
|
5752
5817
|
if (sub.kind === "literal") {
|
|
5753
5818
|
container.environment[key] = String(sub.value);
|
|
5754
5819
|
resolvedEnvKeys.add(key);
|
|
5820
|
+
if (consumedSensitive && !container.sensitiveEnvKeys.includes(key)) container.sensitiveEnvKeys.push(key);
|
|
5755
5821
|
}
|
|
5756
5822
|
}
|
|
5757
5823
|
if (Array.isArray(c["Secrets"])) for (const entry of c["Secrets"]) {
|
|
@@ -6059,7 +6125,8 @@ async function runDetached(opts) {
|
|
|
6059
6125
|
const ro = mount.readOnly ? ":ro" : "";
|
|
6060
6126
|
args.push("-v", `${mount.hostPath}:${mount.containerPath}${ro}`);
|
|
6061
6127
|
}
|
|
6062
|
-
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);
|
|
6063
6130
|
if (opts.tmpfs) args.push("--tmpfs", `${opts.tmpfs.target}:rw,size=${opts.tmpfs.sizeMb}m`);
|
|
6064
6131
|
if (opts.workingDir) args.push("--workdir", opts.workingDir);
|
|
6065
6132
|
let entryPointTail = [];
|
|
@@ -6517,8 +6584,8 @@ async function assumeRoleForEcr(roleArn, callerRegion, profile, logger) {
|
|
|
6517
6584
|
}
|
|
6518
6585
|
/**
|
|
6519
6586
|
* Authenticate the local docker daemon against the target ECR registry.
|
|
6520
|
-
*
|
|
6521
|
-
*
|
|
6587
|
+
* Self-contained in this module so the local-invoke path stays
|
|
6588
|
+
* independent of any full asset-publish path's larger surface area.
|
|
6522
6589
|
*/
|
|
6523
6590
|
async function ecrLogin(client, accountId, region) {
|
|
6524
6591
|
getLogger().child("ecr-puller").debug(`ECR login (account=${accountId}, region=${region})`);
|
|
@@ -7416,7 +7483,8 @@ async function localInvokeCommand(target, options, extraStateProviders) {
|
|
|
7416
7483
|
}
|
|
7417
7484
|
if (envHasIntrinsicValue$1(templateEnv) && stateProvider.resolveTemplateSsmParameters) {
|
|
7418
7485
|
const ssmParams = await stateProvider.resolveTemplateSsmParameters(lambda.stack.template);
|
|
7419
|
-
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);
|
|
7420
7488
|
}
|
|
7421
7489
|
if (envHasCrossStackIntrinsic(templateEnv)) {
|
|
7422
7490
|
const resolver = await stateProvider.buildCrossStackResolver(loaded.region);
|
|
@@ -7443,7 +7511,8 @@ async function localInvokeCommand(target, options, extraStateProviders) {
|
|
|
7443
7511
|
}
|
|
7444
7512
|
stateAudit = {
|
|
7445
7513
|
resolvedKeys,
|
|
7446
|
-
unresolved
|
|
7514
|
+
unresolved,
|
|
7515
|
+
sensitiveKeys: audit.sensitiveKeys
|
|
7447
7516
|
};
|
|
7448
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.`);
|
|
7449
7518
|
}
|
|
@@ -7523,6 +7592,7 @@ async function localInvokeCommand(target, options, extraStateProviders) {
|
|
|
7523
7592
|
mounts: imagePlan.mounts,
|
|
7524
7593
|
extraMounts: extraMountsWithProfile,
|
|
7525
7594
|
env: dockerEnv,
|
|
7595
|
+
...stateAudit && stateAudit.sensitiveKeys.length > 0 && { sensitiveEnvKeys: new Set(stateAudit.sensitiveKeys) },
|
|
7526
7596
|
cmd: imagePlan.cmd,
|
|
7527
7597
|
hostPort,
|
|
7528
7598
|
host: containerHost,
|
|
@@ -10489,6 +10559,7 @@ function createContainerPool(specs, options) {
|
|
|
10489
10559
|
}],
|
|
10490
10560
|
extraMounts,
|
|
10491
10561
|
env: spec.env,
|
|
10562
|
+
...spec.sensitiveEnvKeys !== void 0 && { sensitiveEnvKeys: spec.sensitiveEnvKeys },
|
|
10492
10563
|
cmd: [spec.lambda.handler],
|
|
10493
10564
|
hostPort,
|
|
10494
10565
|
host: spec.containerHost,
|
|
@@ -10506,6 +10577,7 @@ function createContainerPool(specs, options) {
|
|
|
10506
10577
|
readOnly: true
|
|
10507
10578
|
}] },
|
|
10508
10579
|
env: spec.env,
|
|
10580
|
+
...spec.sensitiveEnvKeys !== void 0 && { sensitiveEnvKeys: spec.sensitiveEnvKeys },
|
|
10509
10581
|
cmd: spec.command,
|
|
10510
10582
|
hostPort,
|
|
10511
10583
|
host: spec.containerHost,
|
|
@@ -14723,9 +14795,9 @@ function groupRoutesByServer(routes) {
|
|
|
14723
14795
|
* exact match on the resource's `aws:cdk:path` metadata.
|
|
14724
14796
|
* 4. **CDK Construct path prefix** — when the input is a strict
|
|
14725
14797
|
* ancestor of the resource's `aws:cdk:path` (i.e.
|
|
14726
|
-
* `cdkPath.startsWith(input + '/')`). Mirrors the
|
|
14727
|
-
*
|
|
14728
|
-
* 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`).
|
|
14729
14801
|
*
|
|
14730
14802
|
* Routes discovered before this field set was added (or routes where
|
|
14731
14803
|
* the synthesized template doesn't carry `aws:cdk:path` metadata —
|
|
@@ -15864,6 +15936,7 @@ async function buildContainerSpec(args) {
|
|
|
15864
15936
|
const context = { resources: stateBundle.state.resources };
|
|
15865
15937
|
if (stateBundle.pseudoParameters) context.pseudoParameters = stateBundle.pseudoParameters;
|
|
15866
15938
|
if (stateBundle.ssmParameters) context.parameters = stateBundle.ssmParameters;
|
|
15939
|
+
if (stateBundle.ssmSecureStringLogicalIds?.length) context.sensitiveParameters = new Set(stateBundle.ssmSecureStringLogicalIds);
|
|
15867
15940
|
const { env, audit } = substituteEnvVarsFromState(templateEnv, context);
|
|
15868
15941
|
templateEnv = env;
|
|
15869
15942
|
for (const key of audit.resolvedKeys) getLogger().debug(`Lambda ${logicalId}: state source substituted env var ${key}`);
|
|
@@ -15881,7 +15954,8 @@ async function buildContainerSpec(args) {
|
|
|
15881
15954
|
}
|
|
15882
15955
|
stateAudit = {
|
|
15883
15956
|
resolvedKeys,
|
|
15884
|
-
unresolved
|
|
15957
|
+
unresolved,
|
|
15958
|
+
sensitiveKeys: audit.sensitiveKeys
|
|
15885
15959
|
};
|
|
15886
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.`);
|
|
15887
15961
|
}
|
|
@@ -15934,11 +16008,13 @@ async function buildContainerSpec(args) {
|
|
|
15934
16008
|
target: "/tmp",
|
|
15935
16009
|
sizeMb: lambda.ephemeralStorageMb
|
|
15936
16010
|
} : void 0;
|
|
16011
|
+
const sensitiveEnvKeys = stateAudit && stateAudit.sensitiveKeys.length > 0 ? new Set(stateAudit.sensitiveKeys) : void 0;
|
|
15937
16012
|
if (lambda.kind === "zip") return {
|
|
15938
16013
|
kind: "zip",
|
|
15939
16014
|
lambda,
|
|
15940
16015
|
codeDir,
|
|
15941
16016
|
env: dockerEnv,
|
|
16017
|
+
...sensitiveEnvKeys && { sensitiveEnvKeys },
|
|
15942
16018
|
containerHost,
|
|
15943
16019
|
...optDir !== void 0 && { optDir },
|
|
15944
16020
|
...debugPort !== void 0 && { debugPort },
|
|
@@ -15957,6 +16033,7 @@ async function buildContainerSpec(args) {
|
|
|
15957
16033
|
...lambda.imageConfig.entryPoint !== void 0 && lambda.imageConfig.entryPoint.length > 0 && { entryPoint: lambda.imageConfig.entryPoint },
|
|
15958
16034
|
...lambda.imageConfig.workingDirectory !== void 0 && { workingDir: lambda.imageConfig.workingDirectory },
|
|
15959
16035
|
env: dockerEnv,
|
|
16036
|
+
...sensitiveEnvKeys && { sensitiveEnvKeys },
|
|
15960
16037
|
containerHost,
|
|
15961
16038
|
...debugPort !== void 0 && { debugPort },
|
|
15962
16039
|
...tmpfs !== void 0 && { tmpfs },
|
|
@@ -16318,10 +16395,10 @@ function forwardAwsEnv(env) {
|
|
|
16318
16395
|
* AWS SDK call fails with `Could not load credentials from any providers`.
|
|
16319
16396
|
*
|
|
16320
16397
|
* This helper constructs a transient `STSClient({ profile })` to drive
|
|
16321
|
-
* the SDK's default credential provider chain — same code path
|
|
16322
|
-
* 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
|
|
16323
16400
|
* Identity Center / role-assumption profiles all resolve the same way
|
|
16324
|
-
* they already do for
|
|
16401
|
+
* they already do for the host's outbound calls. We then extract the
|
|
16325
16402
|
* resolved `AwsCredentialIdentity` via `sts.config.credentials()` and
|
|
16326
16403
|
* return the underlying `{ accessKeyId, secretAccessKey, sessionToken? }`
|
|
16327
16404
|
* for env-var injection.
|
|
@@ -16675,7 +16752,8 @@ async function loadStateForRoutedStacks(stacks, routes, routesWithAuth, options,
|
|
|
16675
16752
|
}
|
|
16676
16753
|
if (stackHasIntrinsicEnv(stackName) && provider.resolveTemplateSsmParameters) {
|
|
16677
16754
|
const ssmParameters = await provider.resolveTemplateSsmParameters(stack.template);
|
|
16678
|
-
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;
|
|
16679
16757
|
}
|
|
16680
16758
|
out.set(stackName, bundle);
|
|
16681
16759
|
logger.debug(`${provider.label}: loaded state for ${stackName} (${loaded.region})`);
|
|
@@ -17724,6 +17802,7 @@ function buildDockerRunArgs(opts) {
|
|
|
17724
17802
|
}
|
|
17725
17803
|
const sensitiveEnvKeys = new Set(SENSITIVE_ENV_KEYS);
|
|
17726
17804
|
for (const s of secrets) sensitiveEnvKeys.add(s.name);
|
|
17805
|
+
for (const k of container.sensitiveEnvKeys) sensitiveEnvKeys.add(k);
|
|
17727
17806
|
const sensitiveEnv = appendEnvFlags(args, finalEnv, sensitiveEnvKeys);
|
|
17728
17807
|
if (container.user) args.push("--user", container.user);
|
|
17729
17808
|
if (container.privileged) args.push("--privileged");
|
|
@@ -17840,6 +17919,7 @@ async function localRunTaskCommand(target, options, extraStateProviders) {
|
|
|
17840
17919
|
resources: imageContext?.stateResources ?? {},
|
|
17841
17920
|
...imageContext?.pseudoParameters && { pseudoParameters: imageContext.pseudoParameters },
|
|
17842
17921
|
...imageContext?.stateParameters && { parameters: imageContext.stateParameters },
|
|
17922
|
+
...imageContext?.stateSensitiveParameters?.length && { sensitiveParameters: new Set(imageContext.stateSensitiveParameters) },
|
|
17843
17923
|
consumerRegion,
|
|
17844
17924
|
crossStackResolver: resolver
|
|
17845
17925
|
});
|
|
@@ -17979,7 +18059,8 @@ async function buildEcsImageResolutionContext$1(candidate, stateProvider, option
|
|
|
17979
18059
|
if (loaded) ctx.stateResources = loaded.resources;
|
|
17980
18060
|
if (needs.needsEnvOrSecretSubstitution && stateProvider.resolveTemplateSsmParameters) {
|
|
17981
18061
|
const ssmParameters = await stateProvider.resolveTemplateSsmParameters(candidate.template);
|
|
17982
|
-
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;
|
|
17983
18064
|
}
|
|
17984
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.");
|
|
17985
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).");
|
|
@@ -18028,7 +18109,7 @@ function readEnvOverridesFile$1(filePath) {
|
|
|
18028
18109
|
return parsed;
|
|
18029
18110
|
}
|
|
18030
18111
|
/**
|
|
18031
|
-
*
|
|
18112
|
+
* Pick the credentials forwarded to the AWS-published
|
|
18032
18113
|
* `amazon-ecs-local-container-endpoints` sidecar. Precedence:
|
|
18033
18114
|
* 1. `--assume-task-role <arn>` (or bare `--assume-task-role` against
|
|
18034
18115
|
* a resolvable `TaskRoleArn`) → STS-assumed temp creds. Highest
|
|
@@ -18044,7 +18125,7 @@ function readEnvOverridesFile$1(filePath) {
|
|
|
18044
18125
|
*
|
|
18045
18126
|
* Extracted as an exported helper so a unit test can exercise every
|
|
18046
18127
|
* branch without having to mock the full Synth + Docker + AWS pipeline
|
|
18047
|
-
* (the strategy
|
|
18128
|
+
* (the strategy used for the Lambda container path).
|
|
18048
18129
|
*/
|
|
18049
18130
|
async function resolveSidecarCredentials(options, assumedCredentials) {
|
|
18050
18131
|
if (assumedCredentials) return assumedCredentials;
|
|
@@ -18797,7 +18878,7 @@ function pickEssentialContainerId(instance, service) {
|
|
|
18797
18878
|
const defaultWaitForExitImpl = async (containerId) => {
|
|
18798
18879
|
const { execFile } = await import("node:child_process");
|
|
18799
18880
|
const { promisify } = await import("node:util");
|
|
18800
|
-
const { getDockerCmd } = await import("./docker-cmd
|
|
18881
|
+
const { getDockerCmd } = await import("./docker-cmd-voNPrcRh.js").then((n) => n.t);
|
|
18801
18882
|
const { stdout } = await promisify(execFile)(getDockerCmd(), ["wait", containerId], { maxBuffer: 1024 * 1024 });
|
|
18802
18883
|
const code = parseInt(stdout.trim(), 10);
|
|
18803
18884
|
return Number.isFinite(code) ? code : -1;
|
|
@@ -18817,7 +18898,7 @@ const EXIT_LOG_TAIL_LINES = 50;
|
|
|
18817
18898
|
const defaultReadContainerLogsImpl = async (containerId) => {
|
|
18818
18899
|
const { execFile } = await import("node:child_process");
|
|
18819
18900
|
const { promisify } = await import("node:util");
|
|
18820
|
-
const { getDockerCmd } = await import("./docker-cmd
|
|
18901
|
+
const { getDockerCmd } = await import("./docker-cmd-voNPrcRh.js").then((n) => n.t);
|
|
18821
18902
|
const { stdout, stderr } = await promisify(execFile)(getDockerCmd(), [
|
|
18822
18903
|
"logs",
|
|
18823
18904
|
"--tail",
|
|
@@ -19320,6 +19401,7 @@ async function runOneTarget(target, runState, stacks, options, discovery, skipPu
|
|
|
19320
19401
|
resources: imageContext?.stateResources ?? {},
|
|
19321
19402
|
...imageContext?.pseudoParameters && { pseudoParameters: imageContext.pseudoParameters },
|
|
19322
19403
|
...imageContext?.stateParameters && { parameters: imageContext.stateParameters },
|
|
19404
|
+
...imageContext?.stateSensitiveParameters?.length && { sensitiveParameters: new Set(imageContext.stateSensitiveParameters) },
|
|
19323
19405
|
consumerRegion,
|
|
19324
19406
|
crossStackResolver: resolver
|
|
19325
19407
|
};
|
|
@@ -19436,7 +19518,8 @@ async function buildEcsImageResolutionContext(target, stacks, options, stateProv
|
|
|
19436
19518
|
if (loaded) ctx.stateResources = loaded.resources;
|
|
19437
19519
|
if (needs.needsEnvOrSecretSubstitution && stateProvider.resolveTemplateSsmParameters) {
|
|
19438
19520
|
const ssmParameters = await stateProvider.resolveTemplateSsmParameters(candidate.template);
|
|
19439
|
-
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;
|
|
19440
19523
|
}
|
|
19441
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.");
|
|
19442
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.");
|
|
@@ -19500,7 +19583,7 @@ function parseRestartPolicy(raw) {
|
|
|
19500
19583
|
throw new LocalStartServiceError(`--restart-policy must be one of 'on-failure', 'always', or 'none' (got '${raw}').`);
|
|
19501
19584
|
}
|
|
19502
19585
|
/**
|
|
19503
|
-
*
|
|
19586
|
+
* Pick the credentials forwarded to the AWS-published
|
|
19504
19587
|
* `amazon-ecs-local-container-endpoints` sidecar. `cdkl start-service`'s
|
|
19505
19588
|
* sidecar is SHARED across every replica boot in one CLI invocation, so
|
|
19506
19589
|
* this resolves ONCE at startup. Precedence:
|
|
@@ -19521,7 +19604,7 @@ function parseRestartPolicy(raw) {
|
|
|
19521
19604
|
*
|
|
19522
19605
|
* Extracted as an exported helper so a unit test can exercise both
|
|
19523
19606
|
* branches without having to mock the full Synth + Docker + AWS
|
|
19524
|
-
* pipeline (the strategy
|
|
19607
|
+
* pipeline (the strategy used for the Lambda container path).
|
|
19525
19608
|
*/
|
|
19526
19609
|
async function resolveSharedSidecarCredentials(options) {
|
|
19527
19610
|
if (options.profile) return resolveProfileCredentials(options.profile);
|
|
@@ -19610,4 +19693,4 @@ function createLocalListCommand(opts = {}) {
|
|
|
19610
19693
|
|
|
19611
19694
|
//#endregion
|
|
19612
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 };
|
|
19613
|
-
//# sourceMappingURL=local-list-
|
|
19696
|
+
//# sourceMappingURL=local-list-8fAEdzBb.js.map
|