@go-to-k/cdkd 0.167.0 → 0.167.2
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 +123 -11
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -62,7 +62,7 @@ import { CreateVectorBucketCommand, DeleteIndexCommand, DeleteVectorBucketComman
|
|
|
62
62
|
import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as CreateTableCommand$2, DeleteNamespaceCommand as DeleteNamespaceCommand$1, DeleteTableBucketCommand, DeleteTableCommand as DeleteTableCommand$2, GetTableBucketCommand, GetTableCommand as GetTableCommand$1, ListNamespacesCommand as ListNamespacesCommand$1, ListTableBucketsCommand, ListTablesCommand as ListTablesCommand$1, ListTagsForResourceCommand as ListTagsForResourceCommand$19, NotFoundException as NotFoundException$5, S3TablesClient } from "@aws-sdk/client-s3tables";
|
|
63
63
|
import { AttachLoadBalancerTargetGroupsCommand, AttachLoadBalancersCommand, AttachTrafficSourcesCommand, AutoScalingClient, CreateAutoScalingGroupCommand, CreateOrUpdateTagsCommand, DeleteAutoScalingGroupCommand, DeleteLifecycleHookCommand, DeleteNotificationConfigurationCommand, DeleteTagsCommand as DeleteTagsCommand$1, DescribeAutoScalingGroupsCommand, DescribeLifecycleHooksCommand, DescribeNotificationConfigurationsCommand, DescribeTrafficSourcesCommand, DetachLoadBalancerTargetGroupsCommand, DetachLoadBalancersCommand, DetachTrafficSourcesCommand, DisableMetricsCollectionCommand, EnableMetricsCollectionCommand, PutLifecycleHookCommand, PutNotificationConfigurationCommand, UpdateAutoScalingGroupCommand } from "@aws-sdk/client-auto-scaling";
|
|
64
64
|
import { Document, Pair, Scalar, YAMLMap, YAMLSeq, parse as parse$1, stringify } from "yaml";
|
|
65
|
-
import { mkdir, mkdtemp } from "node:fs/promises";
|
|
65
|
+
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
66
66
|
import { Readable } from "node:stream";
|
|
67
67
|
import { pipeline } from "node:stream/promises";
|
|
68
68
|
import { createServer } from "node:net";
|
|
@@ -46251,12 +46251,22 @@ async function invokeRieStreaming(host, port, event, timeoutMs) {
|
|
|
46251
46251
|
throw new Error(`RIE streaming response did not emit the prelude/body separator within ${STREAM_PRELUDE_MAX_BYTES} bytes. The handler likely did not call awslambda.HttpResponseStream.from(stream, metadata).`);
|
|
46252
46252
|
}
|
|
46253
46253
|
}
|
|
46254
|
+
let preludeSynthesized = false;
|
|
46254
46255
|
if (separatorIdx < 0) {
|
|
46255
|
-
|
|
46256
|
-
|
|
46256
|
+
if (preludeBytes.length === 0) {
|
|
46257
|
+
clearTimeout(timer);
|
|
46258
|
+
throw new Error(`RIE streaming response ended with zero bytes. The handler likely threw before any write — check container logs.`);
|
|
46259
|
+
}
|
|
46260
|
+
preludeSynthesized = true;
|
|
46261
|
+
bodyTail = preludeBytes;
|
|
46262
|
+
preludeBytes = Buffer.alloc(0);
|
|
46257
46263
|
}
|
|
46258
46264
|
let prelude;
|
|
46259
|
-
|
|
46265
|
+
if (preludeSynthesized) prelude = {
|
|
46266
|
+
statusCode: 200,
|
|
46267
|
+
headers: { "Content-Type": "application/octet-stream" }
|
|
46268
|
+
};
|
|
46269
|
+
else try {
|
|
46260
46270
|
prelude = parseStreamingPrelude(preludeBytes.toString("utf8"));
|
|
46261
46271
|
} catch (err) {
|
|
46262
46272
|
clearTimeout(timer);
|
|
@@ -46510,6 +46520,62 @@ function singleFlight(fn, onError) {
|
|
|
46510
46520
|
};
|
|
46511
46521
|
}
|
|
46512
46522
|
|
|
46523
|
+
//#endregion
|
|
46524
|
+
//#region src/cli/commands/local-profile-credentials-file.ts
|
|
46525
|
+
/**
|
|
46526
|
+
* Path inside the container where the credentials file is mounted. Fixed
|
|
46527
|
+
* (not user-configurable) so the env-var injection is stable. `/cdkd-aws/`
|
|
46528
|
+
* is outside `/var/task` (the Lambda code mount) and outside `/root/`
|
|
46529
|
+
* (which the user's handler may bind-mount or modify), so there is no
|
|
46530
|
+
* collision risk with the user's payload.
|
|
46531
|
+
*/
|
|
46532
|
+
const CONTAINER_AWS_CREDENTIALS_PATH = "/cdkd-aws/credentials";
|
|
46533
|
+
/**
|
|
46534
|
+
* Write a temporary AWS shared-credentials file containing the resolved
|
|
46535
|
+
* `--profile <name>` credentials, ready to bind-mount into a Lambda
|
|
46536
|
+
* container at {@link CONTAINER_AWS_CREDENTIALS_PATH}.
|
|
46537
|
+
*
|
|
46538
|
+
* The file content is the standard `[profile-name]` INI shape:
|
|
46539
|
+
*
|
|
46540
|
+
* [<profileName>]
|
|
46541
|
+
* aws_access_key_id = <accessKeyId>
|
|
46542
|
+
* aws_secret_access_key = <secretAccessKey>
|
|
46543
|
+
* aws_session_token = <sessionToken> ← only when present
|
|
46544
|
+
*
|
|
46545
|
+
* `aws_session_token` is omitted when the resolved profile produced
|
|
46546
|
+
* long-lived (non-STS) credentials, mirroring the same logic
|
|
46547
|
+
* `applyProfileCredentialsOverlay` uses for env-var injection.
|
|
46548
|
+
*
|
|
46549
|
+
* Caller is responsible for invoking `dispose()` when the container pool
|
|
46550
|
+
* tears down (e.g., on `SIGINT` via `singleFlight` cleanup). Leaving the
|
|
46551
|
+
* file behind in `/tmp` is a security smell (temp credentials live on
|
|
46552
|
+
* disk).
|
|
46553
|
+
*/
|
|
46554
|
+
async function writeProfileCredentialsFile(profileName, creds) {
|
|
46555
|
+
if (profileName === "") throw new Error("writeProfileCredentialsFile: profile name must not be empty.");
|
|
46556
|
+
if (/[\r\n[\]]/.test(profileName)) throw new Error(`writeProfileCredentialsFile: profile name '${profileName}' contains a forbidden character (any of CR, LF, '[', ']' would corrupt the INI file or the docker -e env var).`);
|
|
46557
|
+
const dir = await mkdtemp(path.join(tmpdir(), "cdkd-profile-creds-"));
|
|
46558
|
+
const hostPath = path.join(dir, "credentials");
|
|
46559
|
+
const lines = [
|
|
46560
|
+
`[${profileName}]`,
|
|
46561
|
+
`aws_access_key_id = ${creds.accessKeyId}`,
|
|
46562
|
+
`aws_secret_access_key = ${creds.secretAccessKey}`
|
|
46563
|
+
];
|
|
46564
|
+
if (creds.sessionToken) lines.push(`aws_session_token = ${creds.sessionToken}`);
|
|
46565
|
+
await writeFile(hostPath, lines.join("\n") + "\n", { mode: 384 });
|
|
46566
|
+
return {
|
|
46567
|
+
hostPath,
|
|
46568
|
+
containerPath: CONTAINER_AWS_CREDENTIALS_PATH,
|
|
46569
|
+
profileName,
|
|
46570
|
+
dispose: async () => {
|
|
46571
|
+
await rm(dir, {
|
|
46572
|
+
recursive: true,
|
|
46573
|
+
force: true
|
|
46574
|
+
});
|
|
46575
|
+
}
|
|
46576
|
+
};
|
|
46577
|
+
}
|
|
46578
|
+
|
|
46513
46579
|
//#endregion
|
|
46514
46580
|
//#region src/local/intrinsic-lambda-arn.ts
|
|
46515
46581
|
/**
|
|
@@ -50500,6 +50566,11 @@ function createContainerPool(specs, options) {
|
|
|
50500
50566
|
containerPath: "/opt",
|
|
50501
50567
|
readOnly: true
|
|
50502
50568
|
}] : [];
|
|
50569
|
+
const extraMounts = spec.profileCredentialsFile ? [...optMount, {
|
|
50570
|
+
hostPath: spec.profileCredentialsFile.hostPath,
|
|
50571
|
+
containerPath: spec.profileCredentialsFile.containerPath,
|
|
50572
|
+
readOnly: true
|
|
50573
|
+
}] : optMount;
|
|
50503
50574
|
const containerCodePath = resolveRuntimeCodeMountPath(spec.lambda.runtime);
|
|
50504
50575
|
containerId = await runDetached({
|
|
50505
50576
|
image: resolveRuntimeImage(spec.lambda.runtime),
|
|
@@ -50508,7 +50579,7 @@ function createContainerPool(specs, options) {
|
|
|
50508
50579
|
containerPath: containerCodePath,
|
|
50509
50580
|
readOnly: true
|
|
50510
50581
|
}],
|
|
50511
|
-
extraMounts
|
|
50582
|
+
extraMounts,
|
|
50512
50583
|
env: spec.env,
|
|
50513
50584
|
cmd: [spec.lambda.handler],
|
|
50514
50585
|
hostPort,
|
|
@@ -50521,6 +50592,11 @@ function createContainerPool(specs, options) {
|
|
|
50521
50592
|
} else containerId = await runDetached({
|
|
50522
50593
|
image: spec.image,
|
|
50523
50594
|
mounts: [],
|
|
50595
|
+
...spec.profileCredentialsFile && { extraMounts: [{
|
|
50596
|
+
hostPath: spec.profileCredentialsFile.hostPath,
|
|
50597
|
+
containerPath: spec.profileCredentialsFile.containerPath,
|
|
50598
|
+
readOnly: true
|
|
50599
|
+
}] },
|
|
50524
50600
|
env: spec.env,
|
|
50525
50601
|
cmd: spec.command,
|
|
50526
50602
|
hostPort,
|
|
@@ -55013,6 +55089,7 @@ async function localStartApiCommand(target, options) {
|
|
|
55013
55089
|
const perLambdaConcurrency = parsePerLambdaConcurrency(options.perLambdaConcurrency);
|
|
55014
55090
|
const inlineTmpDirs = /* @__PURE__ */ new Set();
|
|
55015
55091
|
const layerTmpDirs = /* @__PURE__ */ new Set();
|
|
55092
|
+
let profileCredsFile;
|
|
55016
55093
|
const lastAssetPaths = { value: [] };
|
|
55017
55094
|
const authorizerCache = createAuthorizerCache();
|
|
55018
55095
|
const jwksCache = createJwksCache();
|
|
@@ -55084,6 +55161,7 @@ async function localStartApiCommand(target, options) {
|
|
|
55084
55161
|
}
|
|
55085
55162
|
const stateByStack = options.fromState || isCfnFlagPresent(options) ? await loadStateForRoutedStacks(targetStacks, routes, routesWithAuth, options) : /* @__PURE__ */ new Map();
|
|
55086
55163
|
const profileCredentials = options.profile ? await resolveProfileCredentials(options.profile) : void 0;
|
|
55164
|
+
if (options.profile && profileCredentials && !profileCredsFile) profileCredsFile = await writeProfileCredentialsFile(options.profile, profileCredentials);
|
|
55087
55165
|
const lambdaIds = uniqueLambdaIds(routes, routesWithAuth, webSocketApis);
|
|
55088
55166
|
const specs = /* @__PURE__ */ new Map();
|
|
55089
55167
|
for (let i = 0; i < lambdaIds.length; i++) {
|
|
@@ -55101,7 +55179,8 @@ async function localStartApiCommand(target, options) {
|
|
|
55101
55179
|
stateByStack,
|
|
55102
55180
|
skipPull: options.pull === false,
|
|
55103
55181
|
...options.layerRoleArn !== void 0 && { layerRoleArn: options.layerRoleArn },
|
|
55104
|
-
...profileCredentials && { profileCredentials }
|
|
55182
|
+
...profileCredentials && { profileCredentials },
|
|
55183
|
+
...profileCredsFile && { profileCredsFile }
|
|
55105
55184
|
});
|
|
55106
55185
|
specs.set(logicalId, spec);
|
|
55107
55186
|
}
|
|
@@ -55377,6 +55456,11 @@ async function localStartApiCommand(target, options) {
|
|
|
55377
55456
|
} catch (err) {
|
|
55378
55457
|
logger.warn(`Failed to remove merged-layers tmpdir ${dir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
55379
55458
|
}
|
|
55459
|
+
if (profileCredsFile) try {
|
|
55460
|
+
await profileCredsFile.dispose();
|
|
55461
|
+
} catch (err) {
|
|
55462
|
+
logger.warn(`Failed to remove profile credentials tmpdir ${profileCredsFile.hostPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
55463
|
+
}
|
|
55380
55464
|
});
|
|
55381
55465
|
const shutdown = async (signal, exitCode) => {
|
|
55382
55466
|
if (shutdownStarted) {
|
|
@@ -55535,7 +55619,7 @@ function warnIamRoutes(routesWithAuth) {
|
|
|
55535
55619
|
* missing, runtime not supported).
|
|
55536
55620
|
*/
|
|
55537
55621
|
async function buildContainerSpec(args) {
|
|
55538
|
-
const { logicalId, stacks, overrides, assumeRole, containerHost, debugPort, stsRegion, inlineTmpDirs, layerTmpDirs, stateByStack, skipPull, layerRoleArn, profileCredentials } = args;
|
|
55622
|
+
const { logicalId, stacks, overrides, assumeRole, containerHost, debugPort, stsRegion, inlineTmpDirs, layerTmpDirs, stateByStack, skipPull, layerRoleArn, profileCredentials, profileCredsFile } = args;
|
|
55539
55623
|
const lambda = resolveLambdaByLogicalId(logicalId, stacks);
|
|
55540
55624
|
let codeDir;
|
|
55541
55625
|
let optDir;
|
|
@@ -55589,6 +55673,10 @@ async function buildContainerSpec(args) {
|
|
|
55589
55673
|
if (profileCredentials.sessionToken) dockerEnv["AWS_SESSION_TOKEN"] = profileCredentials.sessionToken;
|
|
55590
55674
|
else delete dockerEnv["AWS_SESSION_TOKEN"];
|
|
55591
55675
|
}
|
|
55676
|
+
if (profileCredsFile) {
|
|
55677
|
+
dockerEnv["AWS_SHARED_CREDENTIALS_FILE"] = profileCredsFile.containerPath;
|
|
55678
|
+
dockerEnv["AWS_PROFILE"] = profileCredsFile.profileName;
|
|
55679
|
+
}
|
|
55592
55680
|
}
|
|
55593
55681
|
if (debugPort !== void 0) dockerEnv["NODE_OPTIONS"] = `--inspect-brk=0.0.0.0:${debugPort}`;
|
|
55594
55682
|
const tmpfs = lambda.ephemeralStorageMb !== void 0 ? {
|
|
@@ -55603,7 +55691,11 @@ async function buildContainerSpec(args) {
|
|
|
55603
55691
|
containerHost,
|
|
55604
55692
|
...optDir !== void 0 && { optDir },
|
|
55605
55693
|
...debugPort !== void 0 && { debugPort },
|
|
55606
|
-
...tmpfs !== void 0 && { tmpfs }
|
|
55694
|
+
...tmpfs !== void 0 && { tmpfs },
|
|
55695
|
+
...profileCredsFile && { profileCredentialsFile: {
|
|
55696
|
+
hostPath: profileCredsFile.hostPath,
|
|
55697
|
+
containerPath: profileCredsFile.containerPath
|
|
55698
|
+
} }
|
|
55607
55699
|
};
|
|
55608
55700
|
return {
|
|
55609
55701
|
kind: "image",
|
|
@@ -55616,7 +55708,11 @@ async function buildContainerSpec(args) {
|
|
|
55616
55708
|
env: dockerEnv,
|
|
55617
55709
|
containerHost,
|
|
55618
55710
|
...debugPort !== void 0 && { debugPort },
|
|
55619
|
-
...tmpfs !== void 0 && { tmpfs }
|
|
55711
|
+
...tmpfs !== void 0 && { tmpfs },
|
|
55712
|
+
...profileCredsFile && { profileCredentialsFile: {
|
|
55713
|
+
hostPath: profileCredsFile.hostPath,
|
|
55714
|
+
containerPath: profileCredsFile.containerPath
|
|
55715
|
+
} }
|
|
55620
55716
|
};
|
|
55621
55717
|
}
|
|
55622
55718
|
/**
|
|
@@ -58918,6 +59014,7 @@ async function localInvokeCommand(target, options) {
|
|
|
58918
59014
|
let containerId;
|
|
58919
59015
|
let stopLogs;
|
|
58920
59016
|
let sigintHandler;
|
|
59017
|
+
let profileCredsFile;
|
|
58921
59018
|
/**
|
|
58922
59019
|
* Unified cleanup for both the success / failure unwind path AND the
|
|
58923
59020
|
* SIGINT handler. Idempotent — every step guards on its own undefined
|
|
@@ -58966,6 +59063,11 @@ async function localInvokeCommand(target, options) {
|
|
|
58966
59063
|
} catch (err) {
|
|
58967
59064
|
getLogger().debug(`Failed to remove ARN-layer tmpdir ${dir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
58968
59065
|
}
|
|
59066
|
+
if (profileCredsFile) try {
|
|
59067
|
+
await profileCredsFile.dispose();
|
|
59068
|
+
} catch (err) {
|
|
59069
|
+
getLogger().debug(`Failed to remove profile credentials tmpdir ${profileCredsFile.hostPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
59070
|
+
}
|
|
58969
59071
|
}, (err) => {
|
|
58970
59072
|
getLogger().debug(`cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
58971
59073
|
});
|
|
@@ -58976,6 +59078,7 @@ async function localInvokeCommand(target, options) {
|
|
|
58976
59078
|
});
|
|
58977
59079
|
await ensureDockerAvailable();
|
|
58978
59080
|
const profileCredentials = options.profile ? await resolveProfileCredentials(options.profile) : void 0;
|
|
59081
|
+
if (options.profile && profileCredentials) profileCredsFile = await writeProfileCredentialsFile(options.profile, profileCredentials);
|
|
58979
59082
|
const appCmd = resolveApp(options.app);
|
|
58980
59083
|
if (!appCmd) throw new Error("No CDK app specified. Pass --app, set CDKD_APP, or add \"app\" to cdk.json.");
|
|
58981
59084
|
logger.info("Synthesizing CDK app...");
|
|
@@ -59076,6 +59179,10 @@ async function localInvokeCommand(target, options) {
|
|
|
59076
59179
|
if (!assumeSucceeded) {
|
|
59077
59180
|
forwardAwsEnv(dockerEnv);
|
|
59078
59181
|
applyProfileCredentialsOverlay(dockerEnv, profileCredentials, false);
|
|
59182
|
+
if (profileCredsFile) {
|
|
59183
|
+
dockerEnv["AWS_SHARED_CREDENTIALS_FILE"] = profileCredsFile.containerPath;
|
|
59184
|
+
dockerEnv["AWS_PROFILE"] = profileCredsFile.profileName;
|
|
59185
|
+
}
|
|
59079
59186
|
}
|
|
59080
59187
|
let debugPort;
|
|
59081
59188
|
if (options.debugPort) {
|
|
@@ -59088,10 +59195,15 @@ async function localInvokeCommand(target, options) {
|
|
|
59088
59195
|
const containerHost = options.containerHost;
|
|
59089
59196
|
if (lambda.layers.length > 0) logger.info(`Mounting ${lambda.layers.length} Lambda layer${lambda.layers.length === 1 ? "" : "s"} at /opt`);
|
|
59090
59197
|
logger.info(`Starting container (image=${imagePlan.image}, port=${hostPort})...`);
|
|
59198
|
+
const extraMountsWithProfile = profileCredsFile ? [...imagePlan.extraMounts ?? [], {
|
|
59199
|
+
hostPath: profileCredsFile.hostPath,
|
|
59200
|
+
containerPath: profileCredsFile.containerPath,
|
|
59201
|
+
readOnly: true
|
|
59202
|
+
}] : imagePlan.extraMounts;
|
|
59091
59203
|
containerId = await runDetached({
|
|
59092
59204
|
image: imagePlan.image,
|
|
59093
59205
|
mounts: imagePlan.mounts,
|
|
59094
|
-
extraMounts:
|
|
59206
|
+
extraMounts: extraMountsWithProfile,
|
|
59095
59207
|
env: dockerEnv,
|
|
59096
59208
|
cmd: imagePlan.cmd,
|
|
59097
59209
|
hostPort,
|
|
@@ -60770,7 +60882,7 @@ function reorderArgs(argv) {
|
|
|
60770
60882
|
*/
|
|
60771
60883
|
async function main() {
|
|
60772
60884
|
const program = new Command();
|
|
60773
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.167.
|
|
60885
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.167.2");
|
|
60774
60886
|
program.addCommand(createBootstrapCommand());
|
|
60775
60887
|
program.addCommand(createSynthCommand());
|
|
60776
60888
|
program.addCommand(createListCommand());
|