@go-to-k/cdkd 0.158.1 → 0.159.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 +102 -240
- package/dist/cli.js +70 -18
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-CGmdz5WP.js → deploy-engine-BzrECC3i.js} +7 -5
- package/dist/deploy-engine-BzrECC3i.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-CGmdz5WP.js.map +0 -1
package/README.md
CHANGED
|
@@ -13,23 +13,6 @@ Drop-in CDK CLI for existing CDK apps — faster deploys via AWS SDK instead of
|
|
|
13
13
|
> [!IMPORTANT]
|
|
14
14
|
> cdkd is for dev/test workflows only — early in development, not yet production-ready.
|
|
15
15
|
|
|
16
|
-
## Features
|
|
17
|
-
|
|
18
|
-
- **Synthesis orchestration**: CDK app subprocess execution, Cloud Assembly parsing, context provider loop
|
|
19
|
-
- **Asset handling**: Self-implemented asset publisher for S3 file assets (ZIP packaging) and Docker images (ECR)
|
|
20
|
-
- **Context resolution**: Self-implemented context provider loop for Vpc.fromLookup(), AZ, SSM, HostedZone, etc.
|
|
21
|
-
- **Hybrid provisioning**: SDK Providers for fast direct API calls, Cloud Control API fallback for broad resource coverage
|
|
22
|
-
- **Diff calculation**: Self-implemented resource/property-level diff between desired template and current state
|
|
23
|
-
- **S3-based state management**: No DynamoDB required, uses S3 conditional writes for locking
|
|
24
|
-
- **DAG-based parallelization**: Analyze `Ref`/`Fn::GetAtt` dependencies and execute in parallel
|
|
25
|
-
- **Rollback on failure**: When a deploy errors mid-stack, cdkd rolls back the resources it just created so the stack state stays consistent (CloudFormation parity — but cdkd does this without round-tripping through CFn). Pass `cdkd deploy --no-rollback` to skip rollback and keep the partial state for Terraform-style inspection / repair. See [Rollback behavior](#rollback-behavior).
|
|
26
|
-
- **`--no-wait` for async resources**: Skip the multi-minute wait on CloudFront / RDS / ElastiCache / NAT Gateway and return as soon as the create call returns (CloudFormation always blocks)
|
|
27
|
-
- **VPC route DependsOn relaxation (on by default)**: Drop CDK-injected defensive `DependsOn` edges from VPC Lambdas onto private-subnet routes so `CloudFront::Distribution` and `Lambda::Url` start their ~3-min propagation in parallel with NAT Gateway stabilization (~50% faster on VPC + Lambda + CloudFront stacks). Pass `--no-aggressive-vpc-parallel` to opt out.
|
|
28
|
-
- **Local execution** (`cdkd local invoke` / `start-api` / `run-task` / `start-service`): run Lambdas, API Gateway routes, ECS tasks and long-running ECS services from your CDK code via Docker. All AWS Lambda runtimes, container Lambdas, REST v1 / HTTP v2 / Function URL routes, Service Connect / Cloud Map. Works for both `cdkd deploy`-managed (`--from-state`) AND `cdk deploy`-managed (`--from-cfn-stack`) stacks. See [Local execution](#local-execution).
|
|
29
|
-
- **Bidirectional CloudFormation migration**: `cdkd import --migrate-from-cloudformation` adopts existing CFn stacks (including `cdk deploy`-managed) into cdkd state without re-creating resources; `cdkd export` hands a cdkd stack back to CloudFormation when production-ready. See [Importing](#importing-existing-resources) / [Exporting](#exporting-a-stack-back-to-cloudformation).
|
|
30
|
-
|
|
31
|
-
> **Note**: Resource types not covered by either SDK Providers or Cloud Control API cannot be deployed with cdkd. Deployment fails with a clear error message naming the type + a 1-click issue link.
|
|
32
|
-
|
|
33
16
|
## Benchmark
|
|
34
17
|
|
|
35
18
|
**cdkd deploys up to 15x faster than AWS CDK (CloudFormation)** on SDK-Provider-handled stacks; the per-stack speedup widens with size and parallelism, and drops to ~1.5-3x on stacks dominated by Cloud Control API fallback resources.
|
|
@@ -64,6 +47,23 @@ Stack: SSM Document × 3 + Athena WorkGroup × 2 (no SDK provider — CC API fal
|
|
|
64
47
|
|
|
65
48
|
Reproduce the first two with `./tests/benchmark/run-benchmark.sh all`. See [tests/benchmark/README.md](tests/benchmark/README.md) for details.
|
|
66
49
|
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
- **Synthesis orchestration**: CDK app subprocess execution, Cloud Assembly parsing, context provider loop
|
|
53
|
+
- **Asset handling**: Self-implemented asset publisher for S3 file assets (ZIP packaging) and Docker images (ECR)
|
|
54
|
+
- **Context resolution**: Self-implemented context provider loop for Vpc.fromLookup(), AZ, SSM, HostedZone, etc.
|
|
55
|
+
- **Hybrid provisioning**: SDK Providers for fast direct API calls, Cloud Control API fallback for broad resource coverage
|
|
56
|
+
- **Diff calculation**: Self-implemented resource/property-level diff between desired template and current state
|
|
57
|
+
- **S3-based state management**: No DynamoDB required, uses S3 conditional writes for locking
|
|
58
|
+
- **DAG-based parallelization**: Analyze `Ref`/`Fn::GetAtt` dependencies and execute in parallel
|
|
59
|
+
- **Rollback on failure**: When a deploy errors mid-stack, cdkd rolls back the resources it just created so the stack state stays consistent (CloudFormation parity — but cdkd does this without round-tripping through CFn). Pass `cdkd deploy --no-rollback` to skip rollback and keep the partial state for Terraform-style inspection / repair. See [Rollback behavior](#rollback-behavior).
|
|
60
|
+
- **`--no-wait` for async resources**: Skip the multi-minute wait on CloudFront / RDS / ElastiCache / NAT Gateway and return as soon as the create call returns (CloudFormation always blocks)
|
|
61
|
+
- **VPC route DependsOn relaxation (on by default)**: Drop CDK-injected defensive `DependsOn` edges from VPC Lambdas onto private-subnet routes so `CloudFront::Distribution` and `Lambda::Url` start their ~3-min propagation in parallel with NAT Gateway stabilization (~50% faster on VPC + Lambda + CloudFront stacks). Pass `--no-aggressive-vpc-parallel` to opt out.
|
|
62
|
+
- **Local execution** (`cdkd local invoke` / `start-api` / `run-task` / `start-service`): run Lambdas, API Gateway routes, ECS tasks and long-running ECS services from your CDK code via Docker. All AWS Lambda runtimes, container Lambdas, REST v1 / HTTP v2 / Function URL routes, Service Connect / Cloud Map. Works for both `cdkd deploy`-managed (`--from-state`) AND `cdk deploy`-managed (`--from-cfn-stack`) stacks. See [Local execution](#local-execution).
|
|
63
|
+
- **Bidirectional CloudFormation migration**: `cdkd import --migrate-from-cloudformation` adopts existing CFn stacks (including `cdk deploy`-managed) into cdkd state without re-creating resources; `cdkd export` hands a cdkd stack back to CloudFormation when production-ready. See [Importing](#importing-existing-resources) / [Exporting](#exporting-a-stack-back-to-cloudformation).
|
|
64
|
+
|
|
65
|
+
> **Note**: Resource types not covered by either SDK Providers or Cloud Control API cannot be deployed with cdkd. Deployment fails with a clear error message naming the type + a 1-click issue link.
|
|
66
|
+
|
|
67
67
|
## How it works
|
|
68
68
|
|
|
69
69
|
```
|
|
@@ -159,229 +159,57 @@ cdkd has three command families:
|
|
|
159
159
|
use them to inspect / clean up state when the source is gone or
|
|
160
160
|
you don't want to synth. `cdkd state destroy` is the CDK-app-free
|
|
161
161
|
counterpart of `cdkd destroy`.
|
|
162
|
-
- **`cdkd local ...` subcommands** (`local invoke
|
|
163
|
-
`
|
|
164
|
-
|
|
165
|
-
`local
|
|
166
|
-
(
|
|
167
|
-
|
|
168
|
-
Function URL routes to local Lambda invocations. `local run-task` is
|
|
169
|
-
the ECS one-shot counterpart — it locates an
|
|
170
|
-
`AWS::ECS::TaskDefinition` from the synthesized template and stands
|
|
171
|
-
up every container in `dependsOn` order on a per-task docker network
|
|
172
|
-
with the AWS-published metadata endpoints sidecar, so containers see
|
|
173
|
-
`ECS_CONTAINER_METADATA_URI_V4` (and optionally task-role creds via
|
|
174
|
-
`--assume-task-role`) just like they would on Fargate / ECS.
|
|
175
|
-
`local start-service` is the long-running counterpart for
|
|
176
|
-
`AWS::ECS::Service`: it discovers the service, chains into the same
|
|
177
|
-
per-task machinery for each `DesiredCount` replica (clamped by
|
|
178
|
-
`--max-tasks`), and keeps every replica running until `^C` — failed
|
|
179
|
-
replicas restart per `--restart-policy on-failure|always|none`. It
|
|
180
|
-
also accepts multiple service targets in one invocation
|
|
181
|
-
(`cdkd local start-service Stack/Orders Stack/Frontend`); per-service
|
|
182
|
-
`AWS::ServiceDiscovery::PrivateDnsNamespace` / `Service` +
|
|
183
|
-
`ServiceConnectConfiguration` / `ServiceRegistries[]` blocks are
|
|
184
|
-
parsed and each booted replica's container IP is published to a
|
|
185
|
-
shared in-process Cloud Map registry, then injected into the next
|
|
186
|
-
service's containers via docker `--add-host <fqdn>:<ip>` so
|
|
187
|
-
`wget http://orders/` from inside the `frontend` container resolves
|
|
188
|
-
via `/etc/hosts` to the orders replica (boot targets in
|
|
189
|
-
producer-then-consumer order; see [docs/local-emulation.md](docs/local-emulation.md)
|
|
190
|
-
for v1 limitations — first-wins for multi-replica routing, no SRV
|
|
191
|
-
records, no Envoy L7). No AWS API calls beyond optional STS / Secrets
|
|
192
|
-
resolution, no state bucket needed. Local load-balancer emulation and
|
|
193
|
-
`--watch` hot-reload for `start-service` are deferred to follow-up
|
|
194
|
-
PRs.
|
|
162
|
+
- **`cdkd local ...` subcommands** (`local invoke` / `start-api` /
|
|
163
|
+
`run-task` / `start-service`) run synthesized workloads locally
|
|
164
|
+
inside Docker containers — no AWS deploy needed. Modeled on
|
|
165
|
+
`sam local *` but reads CDK state directly via `--from-state`
|
|
166
|
+
(cdkd-managed) or `--from-cfn-stack` (CFn-managed). See
|
|
167
|
+
[Local execution](#local-execution).
|
|
195
168
|
|
|
196
169
|
Options like `--app`, `--state-bucket`, and `--context` can be omitted if configured via `cdk.json` or environment variables (`CDKD_APP`, `CDKD_STATE_BUCKET`).
|
|
197
170
|
|
|
198
171
|
```bash
|
|
199
|
-
#
|
|
200
|
-
cdkd
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
# Synthesize only
|
|
205
|
-
cdkd synth --app "node app.ts"
|
|
206
|
-
|
|
207
|
-
# List all stacks in the CDK app (alias: ls)
|
|
208
|
-
cdkd list
|
|
209
|
-
cdkd ls
|
|
210
|
-
cdkd list --long # YAML records with id/name/environment
|
|
211
|
-
cdkd list --long --json # same, but JSON
|
|
212
|
-
cdkd list --show-dependencies # id + dependency list per stack
|
|
213
|
-
cdkd list 'MyStage/*' # filter by display path (CDK CLI parity)
|
|
214
|
-
|
|
215
|
-
# Deploy from a pre-synthesized cloud assembly directory
|
|
216
|
-
cdkd deploy --app cdk.out
|
|
217
|
-
|
|
218
|
-
# Deploy (single stack auto-detected, reads --app from cdk.json)
|
|
219
|
-
cdkd deploy
|
|
220
|
-
|
|
221
|
-
# Deploy specific stack(s)
|
|
222
|
-
cdkd deploy MyStack
|
|
223
|
-
cdkd deploy Stack1 Stack2
|
|
224
|
-
|
|
225
|
-
# Deploy all stacks
|
|
172
|
+
# Synth + deploy
|
|
173
|
+
cdkd synth
|
|
174
|
+
cdkd deploy # single-stack auto-detected
|
|
175
|
+
cdkd deploy MyStack # by name (or 'MyStage/Api' display path)
|
|
226
176
|
cdkd deploy --all
|
|
177
|
+
cdkd deploy --dry-run # plan only, no changes
|
|
178
|
+
cdkd deploy --no-rollback # Terraform-style: keep partial state on failure
|
|
179
|
+
cdkd deploy --no-wait # skip multi-minute waits (CloudFront / RDS / NAT)
|
|
227
180
|
|
|
228
|
-
#
|
|
229
|
-
cdkd deploy 'My*'
|
|
230
|
-
|
|
231
|
-
# Deploy stacks under a CDK Stage using the hierarchical path (CDK CLI parity)
|
|
232
|
-
# Patterns containing '/' are routed to the CDK display path; both forms work:
|
|
233
|
-
cdkd deploy 'MyStage/*' # all stacks under MyStage
|
|
234
|
-
cdkd deploy MyStage/Api # specific stack by display path
|
|
235
|
-
cdkd deploy MyStage-Api # same stack by physical CloudFormation name
|
|
236
|
-
|
|
237
|
-
# Deploy with context values
|
|
238
|
-
cdkd deploy -c env=staging -c featureFlag=true
|
|
239
|
-
|
|
240
|
-
# Deploy with explicit options
|
|
241
|
-
cdkd deploy MyStack \
|
|
242
|
-
--app "node app.ts" \
|
|
243
|
-
--state-bucket my-cdkd-state \
|
|
244
|
-
--verbose
|
|
245
|
-
|
|
246
|
-
# Show diff (what would change)
|
|
181
|
+
# Inspect what would change
|
|
247
182
|
cdkd diff MyStack
|
|
248
|
-
cdkd diff
|
|
249
|
-
cdkd diff MyParent --recursive --json # nested {stack, changes, children: [...]} JSON
|
|
250
|
-
cdkd diff MyStack --fail # exit 1 when any change is detected (CI gate; matches cdk diff --fail)
|
|
251
|
-
|
|
252
|
-
# Detect drift between cdkd state and AWS reality (state-only; no synth)
|
|
253
|
-
# Exits 0 with no drift, 1 when drift is detected, 2 on partial revert failure.
|
|
254
|
-
cdkd drift MyStack
|
|
255
|
-
cdkd drift --all --json
|
|
183
|
+
cdkd diff MyStack --fail # exit 1 on any change (CI gate)
|
|
256
184
|
|
|
257
|
-
#
|
|
258
|
-
cdkd drift MyStack
|
|
185
|
+
# Drift detection — compare state vs AWS reality (no synth)
|
|
186
|
+
cdkd drift MyStack # exit 1 if drift
|
|
187
|
+
cdkd drift MyStack --accept --yes # state ← AWS
|
|
188
|
+
cdkd drift MyStack --revert --yes # AWS ← state
|
|
259
189
|
|
|
260
|
-
#
|
|
261
|
-
cdkd
|
|
262
|
-
|
|
263
|
-
# Refresh the deploy-time AWS snapshot used as drift baseline.
|
|
264
|
-
# Optional — `cdkd deploy` itself auto-refreshes on the first deploy after
|
|
265
|
-
# upgrading from a pre-v3 cdkd binary (= state schema `version: 2`), in
|
|
266
|
-
# parallel with the deploy at no critical-path cost. This command is the
|
|
267
|
-
# manual / non-deploy path: run it when you want the baseline refreshed
|
|
268
|
-
# without redeploying (e.g. for resources that won't change in any
|
|
269
|
-
# near-future deploy). Idempotent on the same v3 state — see "Drift
|
|
270
|
-
# detection" below for the full upgrade story.
|
|
271
|
-
cdkd state refresh-observed MyStack
|
|
272
|
-
|
|
273
|
-
# Dry run (plan only, no changes)
|
|
274
|
-
cdkd deploy --dry-run
|
|
275
|
-
|
|
276
|
-
# Deploy with no rollback on failure (Terraform-style)
|
|
277
|
-
cdkd deploy --no-rollback
|
|
278
|
-
|
|
279
|
-
# Deploy only the specified stack (skip dependency auto-inclusion)
|
|
280
|
-
cdkd deploy -e MyStack
|
|
281
|
-
|
|
282
|
-
# Skip the multi-minute wait on async resources (CloudFront, RDS, NAT GW, etc.)
|
|
283
|
-
cdkd deploy --no-wait
|
|
284
|
-
|
|
285
|
-
# Synth + build + publish assets only (no deploy) — typical CI split
|
|
286
|
-
cdkd publish-assets
|
|
287
|
-
|
|
288
|
-
# Destroy resources
|
|
190
|
+
# Asset / destroy / unlock
|
|
191
|
+
cdkd publish-assets # synth + upload only (typical CI split)
|
|
289
192
|
cdkd destroy MyStack
|
|
290
|
-
cdkd
|
|
193
|
+
cdkd force-unlock MyStack # clear stale lock from an interrupted deploy
|
|
291
194
|
|
|
292
|
-
#
|
|
293
|
-
cdkd force-unlock MyStack
|
|
294
|
-
|
|
295
|
-
# Adopt already-deployed AWS resources into cdkd state.
|
|
296
|
-
# See docs/import.md for the full guide (auto / selective / hybrid modes,
|
|
297
|
-
# --resource overrides, --resource-mapping CDK CLI compatibility).
|
|
298
|
-
cdkd import MyStack --dry-run
|
|
195
|
+
# Adopt existing AWS resources into cdkd state
|
|
299
196
|
cdkd import MyStack --yes
|
|
300
197
|
|
|
301
|
-
#
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
cdkd state
|
|
305
|
-
cdkd state
|
|
306
|
-
cdkd state
|
|
307
|
-
|
|
308
|
-
#
|
|
309
|
-
cdkd state list
|
|
310
|
-
cdkd state ls --long # include resource count, last-modified, lock status
|
|
311
|
-
cdkd state list --json # JSON output (alone, or combined with --long)
|
|
312
|
-
cdkd state list --tree # parent → child stack tree (nested stacks; #555 A3)
|
|
313
|
-
cdkd state list --tree --json # tree as nested JSON
|
|
314
|
-
|
|
315
|
-
# List resources of a single stack from state
|
|
316
|
-
cdkd state resources MyStack # aligned columns: LogicalID, Type, PhysicalID
|
|
317
|
-
cdkd state resources MyStack --long # per-resource block with dependencies and attributes
|
|
318
|
-
cdkd state resources MyStack --json # full JSON array
|
|
319
|
-
|
|
320
|
-
# Show full state record for a stack (metadata, outputs, all resources incl. properties)
|
|
321
|
-
cdkd state show MyStack
|
|
322
|
-
cdkd state show MyStack --json # raw {state, lock} JSON
|
|
323
|
-
cdkd state show MyParent --show-nested # recursively show every nested-stack child (#555 A4)
|
|
324
|
-
cdkd state show MyParent --show-nested --json # tree as nested {state, lock, children: [...]} JSON
|
|
325
|
-
|
|
326
|
-
# Orphan one or more RESOURCES from cdkd's state (does NOT delete AWS resources).
|
|
327
|
-
# Per-resource, mirrors aws-cdk-cli's `cdk orphan --unstable=orphan`.
|
|
328
|
-
# Synth-driven — needs --app / cdk.json. Construct paths use CDK's L2-style form
|
|
329
|
-
# (`<StackName>/<Path/To/Construct>`); the synthesized `/Resource` suffix is
|
|
330
|
-
# matched implicitly. Passing an L2 wrapper that contains multiple CFn resources
|
|
331
|
-
# orphans every child under it (matches upstream's prefix-match semantics).
|
|
332
|
-
cdkd orphan MyStack/MyTable # confirmation prompt (y/N)
|
|
333
|
-
cdkd orphan MyStack/MyTable --yes
|
|
334
|
-
cdkd orphan MyStack/MyTable MyStack/MyBucket # multiple resources, same stack
|
|
335
|
-
cdkd orphan MyStack/MyTable --dry-run # print rewrite audit, no save
|
|
336
|
-
cdkd orphan MyStack/MyTable --force # also fall back to cached
|
|
337
|
-
# attributes when live fetch fails
|
|
338
|
-
|
|
339
|
-
# State-driven counterpart that orphans a WHOLE STACK's state record
|
|
340
|
-
# (no CDK app needed — works against the bucket).
|
|
341
|
-
cdkd state orphan MyStack # confirmation prompt (y/N)
|
|
342
|
-
cdkd state orphan MyStack --yes # skip confirmation
|
|
343
|
-
cdkd state orphan StackA StackB --force # also bypass the locked-stack refusal
|
|
344
|
-
|
|
345
|
-
# Destroy a stack's AWS resources AND remove its state record, without
|
|
346
|
-
# requiring the CDK app (no synth — works from any working directory).
|
|
347
|
-
cdkd state destroy MyStack # per-stack confirmation prompt
|
|
348
|
-
cdkd state destroy MyStack OtherStack --yes
|
|
349
|
-
cdkd state destroy --all -y # every stack in the bucket
|
|
350
|
-
cdkd state destroy MyStack --region us-east-1
|
|
198
|
+
# State-bucket-only commands (no CDK app needed)
|
|
199
|
+
cdkd state info # bucket name, region, schema version
|
|
200
|
+
cdkd state list # one row per (stackName, region)
|
|
201
|
+
cdkd state list --tree # parent → child nested-stack tree
|
|
202
|
+
cdkd state show MyStack # full state record
|
|
203
|
+
cdkd state resources MyStack # logical id / type / physical id
|
|
204
|
+
cdkd state destroy MyStack # delete AWS resources + state, no CDK app
|
|
205
|
+
cdkd state orphan MyStack # remove state record only (AWS resources stay)
|
|
351
206
|
```
|
|
352
207
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
**[docs/supported-features.md](docs/supported-features.md)** for the
|
|
359
|
-
full reference. For per-resource-type provisioning support (SDK Providers
|
|
360
|
-
vs Cloud Control API fallback), see
|
|
361
|
-
**[docs/supported-resources.md](docs/supported-resources.md)**.
|
|
362
|
-
|
|
363
|
-
**Property-level coverage is incremental.** SDK Providers wire most but not every CFn property of a supported type. cdkd fails fast at pre-flight when a template uses a not-yet-implemented property, with the property name + a 1-click issue link. `--allow-unsupported-properties <Type>:<Prop>,...` is the safety valve when this is too strict (e.g. mid-life update on an existing resource); avoid it on security-meaningful properties (encryption / IAM / TLS). See [docs/cli-reference.md](docs/cli-reference.md#--allow-unsupported-properties-deploy).
|
|
364
|
-
|
|
365
|
-
## Rollback behavior
|
|
366
|
-
|
|
367
|
-
When a deploy fails mid-stack (e.g. a resource hits a validation error
|
|
368
|
-
or AWS rejects the request), cdkd by default **rolls back the
|
|
369
|
-
already-completed resources in the same deploy** so the stack state
|
|
370
|
-
stays consistent — every resource cdkd just created in this run is
|
|
371
|
-
deleted in reverse dependency order, the state record is updated to
|
|
372
|
-
match, and the CLI exits non-zero. Resources that existed before this
|
|
373
|
-
deploy are NOT touched.
|
|
374
|
-
|
|
375
|
-
Pass `cdkd deploy --no-rollback` to skip the rollback (Terraform-style:
|
|
376
|
-
the partial state is preserved so you can `cdkd state show <stack>`,
|
|
377
|
-
inspect what landed, fix the underlying issue, and re-run `cdkd deploy`
|
|
378
|
-
to continue from the half-deployed state). Recommended only when you
|
|
379
|
-
plan to manually inspect / repair; the default is safer for CI.
|
|
380
|
-
|
|
381
|
-
Mid-deploy state is also saved per-resource as work completes, so even
|
|
382
|
-
if cdkd itself crashes between the failure and the rollback, the state
|
|
383
|
-
file accurately reflects what's on AWS and a follow-up `cdkd destroy`
|
|
384
|
-
won't orphan anything.
|
|
208
|
+
See **[docs/cli-reference.md](docs/cli-reference.md)** for the full flag
|
|
209
|
+
matrix (`--concurrency`, `--no-aggressive-vpc-parallel`,
|
|
210
|
+
`--allow-unsupported-properties`, `--role-arn`, etc.), per-command details
|
|
211
|
+
including the synth-driven per-resource `cdkd orphan <constructPath>`
|
|
212
|
+
variant, and stage / wildcard pattern matching.
|
|
385
213
|
|
|
386
214
|
## `--no-wait`: skip async-resource waits
|
|
387
215
|
|
|
@@ -397,20 +225,6 @@ See [docs/cli-reference.md](docs/cli-reference.md#--no-wait-skip-async-resource-
|
|
|
397
225
|
for per-resource caveats (NAT egress, RDS final-snapshot timing,
|
|
398
226
|
etc.).
|
|
399
227
|
|
|
400
|
-
## VPC route DependsOn relaxation (on by default)
|
|
401
|
-
|
|
402
|
-
CDK injects defensive `DependsOn` from VPC Lambdas onto private-subnet
|
|
403
|
-
routes. The dependency is real at runtime but NOT required at deploy
|
|
404
|
-
time. cdkd drops it by default so CloudFront + Lambda::Url propagation
|
|
405
|
-
runs in parallel with NAT stabilization (~50% faster on VPC+Lambda+CloudFront
|
|
406
|
-
stacks; bench-cdk-sample 398s → 181s). Pass
|
|
407
|
-
`cdkd deploy --no-aggressive-vpc-parallel` to opt out (e.g. when a
|
|
408
|
-
Custom Resource synchronously invokes a VPC Lambda outside cdkd's
|
|
409
|
-
Lambda-ServiceToken Active wait).
|
|
410
|
-
|
|
411
|
-
See [docs/cli-reference.md](docs/cli-reference.md) for the full
|
|
412
|
-
type-pair allowlist and trade-off notes.
|
|
413
|
-
|
|
414
228
|
## Local execution
|
|
415
229
|
|
|
416
230
|
The `cdkd local` family runs AWS workloads on the developer's machine
|
|
@@ -455,7 +269,8 @@ cdkd local start-api --from-state # OR --from-cfn-stack
|
|
|
455
269
|
REST v1 + HTTP API v2 + Function URL with all integration kinds
|
|
456
270
|
(AWS_PROXY / MOCK / HTTP_PROXY / HTTP / AWS Lambda non-proxy via
|
|
457
271
|
hand-rolled VTL), authorizers (Lambda / Cognito / HTTP v2 JWT /
|
|
458
|
-
REST v1
|
|
272
|
+
AWS_IAM SigV4 on REST v1 + Function URL), CORS, stage variables,
|
|
273
|
+
`--watch` hot reload.
|
|
459
274
|
|
|
460
275
|
### `local run-task`
|
|
461
276
|
|
|
@@ -484,6 +299,27 @@ full reference — runtimes, target resolution, every flag, integration
|
|
|
484
299
|
and authorizer detail, route precedence, container pool, networking,
|
|
485
300
|
`--from-cfn-stack` semantics, v1 scope.
|
|
486
301
|
|
|
302
|
+
## Rollback behavior
|
|
303
|
+
|
|
304
|
+
When a deploy fails mid-stack (e.g. a resource hits a validation error
|
|
305
|
+
or AWS rejects the request), cdkd by default **rolls back the
|
|
306
|
+
already-completed resources in the same deploy** so the stack state
|
|
307
|
+
stays consistent — every resource cdkd just created in this run is
|
|
308
|
+
deleted in reverse dependency order, the state record is updated to
|
|
309
|
+
match, and the CLI exits non-zero. Resources that existed before this
|
|
310
|
+
deploy are NOT touched.
|
|
311
|
+
|
|
312
|
+
Pass `cdkd deploy --no-rollback` to skip the rollback (Terraform-style:
|
|
313
|
+
the partial state is preserved so you can `cdkd state show <stack>`,
|
|
314
|
+
inspect what landed, fix the underlying issue, and re-run `cdkd deploy`
|
|
315
|
+
to continue from the half-deployed state). Recommended only when you
|
|
316
|
+
plan to manually inspect / repair; the default is safer for CI.
|
|
317
|
+
|
|
318
|
+
Mid-deploy state is also saved per-resource as work completes, so even
|
|
319
|
+
if cdkd itself crashes between the failure and the rollback, the state
|
|
320
|
+
file accurately reflects what's on AWS and a follow-up `cdkd destroy`
|
|
321
|
+
won't orphan anything.
|
|
322
|
+
|
|
487
323
|
## Importing existing resources
|
|
488
324
|
|
|
489
325
|
`cdkd import` adopts AWS resources that are already deployed (via
|
|
@@ -583,6 +419,20 @@ Two `orphan` variants at different granularities:
|
|
|
583
419
|
Both `cdkd destroy` (synth-driven) and `cdkd state destroy`
|
|
584
420
|
(state-driven, no synth) delete AWS resources + state.
|
|
585
421
|
|
|
422
|
+
## VPC route DependsOn relaxation (on by default)
|
|
423
|
+
|
|
424
|
+
CDK injects defensive `DependsOn` from VPC Lambdas onto private-subnet
|
|
425
|
+
routes. The dependency is real at runtime but NOT required at deploy
|
|
426
|
+
time. cdkd drops it by default so CloudFront + Lambda::Url propagation
|
|
427
|
+
runs in parallel with NAT stabilization (~50% faster on VPC+Lambda+CloudFront
|
|
428
|
+
stacks; bench-cdk-sample 398s → 181s). Pass
|
|
429
|
+
`cdkd deploy --no-aggressive-vpc-parallel` to opt out (e.g. when a
|
|
430
|
+
Custom Resource synchronously invokes a VPC Lambda outside cdkd's
|
|
431
|
+
Lambda-ServiceToken Active wait).
|
|
432
|
+
|
|
433
|
+
See [docs/cli-reference.md](docs/cli-reference.md) for the full
|
|
434
|
+
type-pair allowlist and trade-off notes.
|
|
435
|
+
|
|
586
436
|
## `--remove-protection`: one-shot bypass for protected resources
|
|
587
437
|
|
|
588
438
|
`cdkd destroy --remove-protection` (and `cdkd state destroy --remove-protection`)
|
|
@@ -632,6 +482,18 @@ cdkd publish-assets -a cdk.out # skip synth, use pre-synthesized assembly
|
|
|
632
482
|
See [docs/cli-reference.md](docs/cli-reference.md#publish-assets-synth--build--publish-no-deploy)
|
|
633
483
|
for stack-selection rules and concurrency knobs.
|
|
634
484
|
|
|
485
|
+
## Compatibility
|
|
486
|
+
|
|
487
|
+
cdkd supports the standard CloudFormation surface — intrinsic functions,
|
|
488
|
+
pseudo parameters, parameters / conditions, cross-stack / cross-region
|
|
489
|
+
references, asset publishing, custom resources, and so on. See
|
|
490
|
+
**[docs/supported-features.md](docs/supported-features.md)** for the
|
|
491
|
+
full reference. For per-resource-type provisioning support (SDK Providers
|
|
492
|
+
vs Cloud Control API fallback), see
|
|
493
|
+
**[docs/supported-resources.md](docs/supported-resources.md)**.
|
|
494
|
+
|
|
495
|
+
**Property-level coverage is incremental.** SDK Providers wire most but not every CFn property of a supported type. cdkd fails fast at pre-flight when a template uses a not-yet-implemented property, with the property name + a 1-click issue link. `--allow-unsupported-properties <Type>:<Prop>,...` is the safety valve when this is too strict (e.g. mid-life update on an existing resource); avoid it on security-meaningful properties (encryption / IAM / TLS). See [docs/cli-reference.md](docs/cli-reference.md#--allow-unsupported-properties-deploy).
|
|
496
|
+
|
|
635
497
|
## State Management
|
|
636
498
|
|
|
637
499
|
State is stored in S3 with optimistic locking via S3 Conditional Writes
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { _ as withSkipPrefix, a as runDockerStreaming, c as getLogger, d as getLiveRenderer, f as PATTERN_B_NAME_PROPERTIES, g as generateResourceNameWithFallback, h as generateResourceName, i as runDockerForeground, n as formatDockerLoginError, p as PATTERN_B_RESOURCE_TYPES, r as getDockerCmd, u as runStackBuffered, v as withStackName } from "./docker-cmd-iDMcWcre.js";
|
|
3
|
-
import { $ as CdkdError, A as shouldRetainResource, B as resolveSkipPrefix, C as IntrinsicFunctionResolver, D as TemplateParser, E as DagBuilder, F as Synthesizer, G as CFN_TEMPLATE_URL_LIMIT, H as resolveStateBucketWithDefaultAndSource, I as getDefaultStateBucketName, J as uploadCfnTemplate, K as MIGRATE_TMP_PREFIX, L as getLegacyStateBucketName, M as stringifyValue, N as WorkGraph, O as LockManager, P as buildDockerImage, R as resolveApp, S as assertRegionMatch, T as DiffCalculator, U as warnDeprecatedNoPrefixCliFlag, V as resolveStateBucketWithDefault, W as CFN_TEMPLATE_BODY_LIMIT, Y as AssemblyReader, Z as resolveBucketRegion, _ as matchesCdkPath, a as withRetry, b as ProviderRegistry, bt as withErrorHandling, c as bold, ct as PartialFailureError, d as green, dt as ResourceUpdateNotSupportedError, f as red, ft as RouteDiscoveryError, g as CDK_PATH_TAG, h as collectInlinePolicyNamesManagedBySiblings, i as withResourceDeadline, it as LocalStartServiceError, j as AssetPublisher, k as S3StateBackend, l as cyan, lt as ProvisioningError, m as IAMRoleProvider, mt as StackTerminationProtectionError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as LocalInvokeBuildError, o as IMPLICIT_DELETE_DEPENDENCIES, ot as MissingCdkCliError, p as yellow, pt as StackHasActiveImportsError, q as findLargeInlineResources, r as DeployEngine, rt as LocalMigrateError, s as formatResourceLine, st as NestedStackChildDirectDestroyError, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, ut as ResourceTimeoutError, v as normalizeAwsTagsToCfn, w as applyRoleArnIfSet, x as CloudControlProvider, y as resolveExplicitPhysicalId, yt as normalizeAwsError, z as resolveCaptureObservedState } from "./deploy-engine-
|
|
3
|
+
import { $ as CdkdError, A as shouldRetainResource, B as resolveSkipPrefix, C as IntrinsicFunctionResolver, D as TemplateParser, E as DagBuilder, F as Synthesizer, G as CFN_TEMPLATE_URL_LIMIT, H as resolveStateBucketWithDefaultAndSource, I as getDefaultStateBucketName, J as uploadCfnTemplate, K as MIGRATE_TMP_PREFIX, L as getLegacyStateBucketName, M as stringifyValue, N as WorkGraph, O as LockManager, P as buildDockerImage, R as resolveApp, S as assertRegionMatch, T as DiffCalculator, U as warnDeprecatedNoPrefixCliFlag, V as resolveStateBucketWithDefault, W as CFN_TEMPLATE_BODY_LIMIT, Y as AssemblyReader, Z as resolveBucketRegion, _ as matchesCdkPath, a as withRetry, b as ProviderRegistry, bt as withErrorHandling, c as bold, ct as PartialFailureError, d as green, dt as ResourceUpdateNotSupportedError, f as red, ft as RouteDiscoveryError, g as CDK_PATH_TAG, h as collectInlinePolicyNamesManagedBySiblings, i as withResourceDeadline, it as LocalStartServiceError, j as AssetPublisher, k as S3StateBackend, l as cyan, lt as ProvisioningError, m as IAMRoleProvider, mt as StackTerminationProtectionError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as LocalInvokeBuildError, o as IMPLICIT_DELETE_DEPENDENCIES, ot as MissingCdkCliError, p as yellow, pt as StackHasActiveImportsError, q as findLargeInlineResources, r as DeployEngine, rt as LocalMigrateError, s as formatResourceLine, st as NestedStackChildDirectDestroyError, t as DEFAULT_RESOURCE_TIMEOUT_MS, u as gray, ut as ResourceTimeoutError, v as normalizeAwsTagsToCfn, w as applyRoleArnIfSet, x as CloudControlProvider, y as resolveExplicitPhysicalId, yt as normalizeAwsError, z as resolveCaptureObservedState } from "./deploy-engine-BzrECC3i.js";
|
|
4
4
|
import { a as setAwsClients, i as resetAwsClients, r as getAwsClients, t as AwsClients } from "./aws-clients-B15NAPbL.js";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
import { createHash, createHmac, createPublicKey, createVerify, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
@@ -46754,9 +46754,14 @@ function classifyServiceIntegrationRoute(baseRoute, integrationProps, stackName,
|
|
|
46754
46754
|
* JSON prelude — `{statusCode, headers, cookies?}` — followed by 8
|
|
46755
46755
|
* NULL bytes and then the raw body chunks). The HTTP server pipes
|
|
46756
46756
|
* the chunks to the client with `Transfer-Encoding: chunked` (#467).
|
|
46757
|
-
* - `AuthType
|
|
46758
|
-
*
|
|
46759
|
-
*
|
|
46757
|
+
* - `AuthType === 'AWS_IAM'` → normal route. The `IamAuthorizer` is
|
|
46758
|
+
* attached at the authorizer-resolver pass (`detectAuthorizer` in
|
|
46759
|
+
* `authorizer-resolver.ts`) so the HTTP server runs the same SigV4
|
|
46760
|
+
* verification it ships for REST v1 `AuthorizationType: 'AWS_IAM'`
|
|
46761
|
+
* (PR #447). Signature verification only — no IAM policy emulation.
|
|
46762
|
+
* - `AuthType` other than `'NONE'` / `'AWS_IAM'` (defensive — AWS docs
|
|
46763
|
+
* only define those two values) → deferred-error unsupported. Boot
|
|
46764
|
+
* proceeds; HTTP 501 + `reason` at request time.
|
|
46760
46765
|
*
|
|
46761
46766
|
* The Lambda Arn intrinsic resolution still **hard-errors** when it
|
|
46762
46767
|
* cannot pin down a same-template Lambda — Function URLs have no other
|
|
@@ -46781,10 +46786,10 @@ function discoverFunctionUrl(logicalId, resource, template, stackName) {
|
|
|
46781
46786
|
declaredAt: `${stackName}/${logicalId}`
|
|
46782
46787
|
};
|
|
46783
46788
|
const authType = props["AuthType"];
|
|
46784
|
-
if (authType !== "NONE") return [{
|
|
46789
|
+
if (authType !== "NONE" && authType !== "AWS_IAM") return [{
|
|
46785
46790
|
...baseRoute,
|
|
46786
46791
|
lambdaLogicalId,
|
|
46787
|
-
unsupported: { reason: `${stackName}/${logicalId}: AuthType
|
|
46792
|
+
unsupported: { reason: `${stackName}/${logicalId}: AuthType ${shortJson$1(authType)} is not a recognized Function URL auth type (expected 'NONE' or 'AWS_IAM').` }
|
|
46788
46793
|
}];
|
|
46789
46794
|
const invokeModeRaw = props["InvokeMode"];
|
|
46790
46795
|
let invokeMode = "BUFFERED";
|
|
@@ -51087,6 +51092,28 @@ function detectAuthorizer(route, stack) {
|
|
|
51087
51092
|
if (!resource) return void 0;
|
|
51088
51093
|
if (resource.Type === "AWS::ApiGateway::Method") return detectRestV1Authorizer(resource, logicalId, stack);
|
|
51089
51094
|
if (resource.Type === "AWS::ApiGatewayV2::Route") return detectHttpApiAuthorizer(resource, logicalId, stack);
|
|
51095
|
+
if (resource.Type === "AWS::Lambda::Url") return detectFunctionUrlAuthorizer(resource, logicalId, stack);
|
|
51096
|
+
}
|
|
51097
|
+
/**
|
|
51098
|
+
* Function URL (`AWS::Lambda::Url`) authorizer detection (issue #621).
|
|
51099
|
+
*
|
|
51100
|
+
* `AuthType: 'AWS_IAM'` uses the same SigV4 mechanism REST v1 ships
|
|
51101
|
+
* (PR #447), so we route through the same `IamAuthorizer` descriptor and
|
|
51102
|
+
* let the HTTP server's existing `if (authorizer.kind === 'iam')`
|
|
51103
|
+
* request-time branch run `verifySigV4`. Like REST v1 AWS_IAM, no IAM
|
|
51104
|
+
* policy emulation — signature verification only.
|
|
51105
|
+
*
|
|
51106
|
+
* `AuthType: 'NONE'` (and any non-AWS_IAM AuthType that
|
|
51107
|
+
* `route-discovery.ts` already flipped to `unsupported`) returns
|
|
51108
|
+
* `undefined` so the route runs without an authorizer pass.
|
|
51109
|
+
*/
|
|
51110
|
+
function detectFunctionUrlAuthorizer(urlResource, urlLogicalId, stack) {
|
|
51111
|
+
if ((urlResource.Properties ?? {})["AuthType"] !== "AWS_IAM") return void 0;
|
|
51112
|
+
return {
|
|
51113
|
+
kind: "iam",
|
|
51114
|
+
logicalId: "AWS_IAM",
|
|
51115
|
+
declaredAt: `${stack.stackName}/${urlLogicalId}`
|
|
51116
|
+
};
|
|
51090
51117
|
}
|
|
51091
51118
|
function detectRestV1Authorizer(methodResource, methodLogicalId, stack) {
|
|
51092
51119
|
const props = methodResource.Properties ?? {};
|
|
@@ -52548,15 +52575,15 @@ async function handleRequest(req, res, state, opts) {
|
|
|
52548
52575
|
outcome = await runAuthorizerPass(authorizer, snapshot, matchCtx, state, opts, baseEvent["requestContext"]);
|
|
52549
52576
|
} catch (err) {
|
|
52550
52577
|
logger.error(`Authorizer ${authorizer.logicalId} threw for ${match.route.declaredAt}: ${err instanceof Error ? err.message : String(err)}`);
|
|
52551
|
-
writeAuthRejection(res, match.route.apiVersion, "policy-deny");
|
|
52578
|
+
writeAuthRejection(res, match.route.apiVersion, "policy-deny", authorizer.kind);
|
|
52552
52579
|
return;
|
|
52553
52580
|
}
|
|
52554
52581
|
if (!outcome.result.allow) {
|
|
52555
|
-
writeAuthRejection(res, match.route.apiVersion, outcome.denyKind ?? "policy-deny");
|
|
52582
|
+
writeAuthRejection(res, match.route.apiVersion, outcome.denyKind ?? "policy-deny", authorizer.kind);
|
|
52556
52583
|
return;
|
|
52557
52584
|
}
|
|
52558
52585
|
authResult = outcome.result;
|
|
52559
|
-
const overlay = buildOverlay(authorizer, authResult);
|
|
52586
|
+
const overlay = buildOverlay(authorizer, authResult, match.route.apiVersion);
|
|
52560
52587
|
if (overlay) baseEvent = applyAuthorizerOverlay(baseEvent, overlay);
|
|
52561
52588
|
}
|
|
52562
52589
|
if (match.route.serviceIntegration) {
|
|
@@ -52967,7 +52994,7 @@ function pickSourceIp(apiVersion, requestContext, snapshot) {
|
|
|
52967
52994
|
}
|
|
52968
52995
|
return snapshot.sourceIp ?? "127.0.0.1";
|
|
52969
52996
|
}
|
|
52970
|
-
function buildOverlay(authorizer, result) {
|
|
52997
|
+
function buildOverlay(authorizer, result, routeApiVersion) {
|
|
52971
52998
|
if (authorizer.kind === "lambda-token" || authorizer.kind === "lambda-request") return authorizer.kind === "lambda-request" && authorizer.apiVersion === "v2" ? {
|
|
52972
52999
|
kind: "lambda-http-v2",
|
|
52973
53000
|
...result.principalId !== void 0 && { principalId: result.principalId },
|
|
@@ -52981,10 +53008,13 @@ function buildOverlay(authorizer, result) {
|
|
|
52981
53008
|
kind: "cognito-rest-v1",
|
|
52982
53009
|
claims: result.context ?? {}
|
|
52983
53010
|
};
|
|
52984
|
-
if (authorizer.kind === "iam")
|
|
52985
|
-
|
|
52986
|
-
|
|
52987
|
-
|
|
53011
|
+
if (authorizer.kind === "iam") {
|
|
53012
|
+
if (routeApiVersion === "v2") return void 0;
|
|
53013
|
+
return {
|
|
53014
|
+
kind: "lambda-rest-v1",
|
|
53015
|
+
...result.principalId !== void 0 && { principalId: result.principalId }
|
|
53016
|
+
};
|
|
53017
|
+
}
|
|
52988
53018
|
return {
|
|
52989
53019
|
kind: "jwt-http-v2",
|
|
52990
53020
|
claims: result.context ?? {}
|
|
@@ -52992,6 +53022,11 @@ function buildOverlay(authorizer, result) {
|
|
|
52992
53022
|
}
|
|
52993
53023
|
/**
|
|
52994
53024
|
* Map the authorizer rejection to an HTTP status code and body.
|
|
53025
|
+
* - REST v1 with AWS_IAM (issue #625) → 403 for both deny kinds (the
|
|
53026
|
+
* deployed REST v1 SigV4 layer rejects unsigned requests with 403
|
|
53027
|
+
* `{"message":"Missing Authentication Token"}` and signature/policy
|
|
53028
|
+
* failures with 403 `{"message":"Forbidden"}` — lowercase `message`
|
|
53029
|
+
* distinguishes the REST v1 shape from the Function URL shape below).
|
|
52995
53030
|
* - REST v1, missing identity → 401 `{"message":"Unauthorized"}`
|
|
52996
53031
|
* (matches deployed behavior; the route reaches the Method but no
|
|
52997
53032
|
* identity source is present so the authorizer never runs).
|
|
@@ -52999,8 +53034,25 @@ function buildOverlay(authorizer, result) {
|
|
|
52999
53034
|
* authorizer ran and denied; status mirrors AWS API Gateway).
|
|
53000
53035
|
* - HTTP v2, both kinds → 401 `{"message":"Unauthorized"}` (HTTP API
|
|
53001
53036
|
* collapses both into the same response).
|
|
53002
|
-
|
|
53003
|
-
|
|
53037
|
+
* - Function URL with AWS_IAM (issue #621) → 403 `{"Message":"Forbidden"}`
|
|
53038
|
+
* for both deny kinds (matches Lambda's deployed Function URL IAM
|
|
53039
|
+
* behavior — the AWS SigV4 layer rejects with 403, not 401). Note the
|
|
53040
|
+
* capital `Message` — distinct from REST v1 AWS_IAM's lowercase
|
|
53041
|
+
* `message`.
|
|
53042
|
+
*/
|
|
53043
|
+
function writeAuthRejection(res, apiVersion, denyKind, authorizerKind) {
|
|
53044
|
+
if (apiVersion === "v1" && authorizerKind === "iam") {
|
|
53045
|
+
if (denyKind === "missing-identity") {
|
|
53046
|
+
writeError(res, 403, "{\"message\":\"Missing Authentication Token\"}");
|
|
53047
|
+
return;
|
|
53048
|
+
}
|
|
53049
|
+
writeError(res, 403, "{\"message\":\"Forbidden\"}");
|
|
53050
|
+
return;
|
|
53051
|
+
}
|
|
53052
|
+
if (apiVersion === "v2" && authorizerKind === "iam") {
|
|
53053
|
+
writeError(res, 403, "{\"Message\":\"Forbidden\"}");
|
|
53054
|
+
return;
|
|
53055
|
+
}
|
|
53004
53056
|
if (apiVersion === "v2") {
|
|
53005
53057
|
writeError(res, 401, "{\"message\":\"Unauthorized\"}");
|
|
53006
53058
|
return;
|
|
@@ -55097,7 +55149,7 @@ function resolveMtlsConfig(options) {
|
|
|
55097
55149
|
* Builder for the `start-api` subcommand. Wired up by `local.ts`.
|
|
55098
55150
|
*/
|
|
55099
55151
|
function createLocalStartApiCommand() {
|
|
55100
|
-
const startApi = new Command("start-api").description("Run a long-running local HTTP server that maps API Gateway routes (REST v1, HTTP API, Function URL) to Lambda invocations against the AWS Lambda Runtime Interface Emulator (Docker required). Supports Lambda TOKEN/REQUEST authorizers, Cognito User Pool / HTTP v2 JWT authorizers, and REST v1 AWS_IAM
|
|
55152
|
+
const startApi = new Command("start-api").description("Run a long-running local HTTP server that maps API Gateway routes (REST v1, HTTP API, Function URL) to Lambda invocations against the AWS Lambda Runtime Interface Emulator (Docker required). Supports Lambda TOKEN/REQUEST authorizers, Cognito User Pool / HTTP v2 JWT authorizers, and AWS_IAM auth (REST v1 `AuthorizationType: AWS_IAM` and Function URL `AuthType: AWS_IAM` — SigV4 signature verification only; IAM policy evaluation is NOT emulated; see docs/local-emulation.md). When JWKS is unreachable, JWT authorizers fall back to pass-through (every token accepted) with a warn line — local dev fallback. VPC-config Lambdas run locally and surface a warn line at startup; their containers do NOT get attached to the deployed VPC subnets, so calls to private RDS / ElastiCache will fail.").argument("[target]", "Optional API filter. Accepts the bare CDK logical id ('MyHttpApi'; single-stack apps only), stack-qualified logical id ('MyStack:MyHttpApi'), full CDK Construct path ('MyStack/MyHttpApi/Resource'), or an ancestor Construct path that prefix-matches ('MyStack/MyHttpApi'). When omitted, every discovered API gets its own server. Mirrors `cdkd local invoke` / `cdkd local run-task` target syntax.").addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--stack <name>", "Stack to start (single-stack apps auto-detect)")).addOption(new Option("--warm", "Pre-start one container per Lambda at server boot").default(false)).addOption(new Option("--per-lambda-concurrency <n>", "Pool size cap per Lambda (default 2, max 4)").default("2")).addOption(new Option("--no-pull", "Skip docker pull (cached image)")).addOption(new Option("--container-host <host>", "IP the host uses to bind/probe the RIE port (must be a numeric IP — `docker run -p <ip>:<port>:8080` rejects hostnames). Defaults to 127.0.0.1.").default("127.0.0.1")).addOption(new Option("--debug-port-base <port>", "Reserve a contiguous --debug-port range (one per Lambda)")).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}, \"Parameters\": {...}})")).addOption(new Option("--assume-role <arn-or-pair>", "Assume the Lambda's execution role and forward STS-issued temp creds. Bare <arn> = global default; <LogicalId>=<arn> = per-Lambda override (repeatable). Per-Lambda > global > unset (developer creds passed through).").argParser((raw, prev) => parseAssumeRoleToken(raw, prev))).addOption(new Option("--watch", "Hot-reload: re-synth + re-discover routes when cdk.out/ or asset directories change. Off by default; the server keeps the previous version serving when synth fails mid-reload.").default(false)).addOption(new Option("--stage <name>", "Select an API Gateway Stage by its 'StageName'. Default: the first Stage attached to each API. Drives event.stageVariables for both REST v1 and HTTP API v2. NOTE: For HTTP API v2 routes, requestContext.stage is always '$default' regardless of this flag (AWS-side limitation — HTTP API only exposes one stage to the integration event); only event.stageVariables is affected for v2 routes. For REST v1 routes the selected StageName is also threaded into requestContext.stage.")).addOption(new Option("--api <id>", "DEPRECATED — use the positional <target> argument instead. Same accepted forms (bare logical id, stack-qualified, Construct path, ancestor prefix). Will be removed in a future major release.")).addOption(new Option("--layer-role-arn <arn>", "Role to sts:AssumeRole before calling lambda:GetLayerVersion on every literal-ARN entry in Properties.Layers (issue #448). Use only when the dev credentials cannot read the layer — typically cross-account layers. AWS-published public layers (e.g. Lambda Powertools) are readable from every account and need no role.")).addOption(new Option("--from-state", "Read cdkd S3 state for every routed stack and substitute Ref / Fn::GetAtt / Fn::Sub / Fn::Join (and AWS pseudo parameters) in Lambda env vars with the deployed physical IDs / attributes. Off by default — pre-PR warn-and-drop semantics are preserved. Turn on for stacks already deployed via cdkd deploy. Mirrors `cdkd local invoke --from-state` / `cdkd local run-task --from-state`. Re-runs against fresh state on every hot-reload firing (--watch).").default(false)).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via DescribeStackResources and substitute Ref / Fn::ImportValue in Lambda env vars with the deployed physical IDs / exports. Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the cdkd stack name per routed stack; pass an explicit value when a single CFn stack should serve every routed stack. Mutually exclusive with --from-state. Fn::GetAtt is warn-and-dropped in v1 (CFn DescribeStackResources does not return per-attribute values).")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-state when the same stack name has state in multiple regions, and with --from-cfn-stack as the CFn client region (cdkd does not have a separate --cfn-stack-region flag).")).addOption(new Option("--mtls-truststore <path>", "PEM-encoded CA bundle for client-certificate verification (mutual TLS). When set, the local server switches from HTTP to HTTPS and the TLS handshake rejects clients whose certificate doesn't chain to one of these CAs. Verified certs are surfaced on the Lambda event under requestContext.identity.clientCert (REST v1) / requestContext.authentication.clientCert (HTTP API v2). Must be set together with --mtls-cert + --mtls-key; partial flag sets are rejected. Generate a CA + server + client cert for local dev: openssl req -x509 -newkey rsa:2048 -nodes -keyout ca-key.pem -out ca.pem -subj \"/CN=cdkd-local-ca\" -days 365; openssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-csr.pem -subj \"/CN=localhost\"; openssl x509 -req -in server-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365; openssl req -newkey rsa:2048 -nodes -keyout client-key.pem -out client-csr.pem -subj \"/CN=client\"; openssl x509 -req -in client-csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365; curl --cacert ca.pem --cert client-cert.pem --key client-key.pem https://localhost:<port>/...")).addOption(new Option("--mtls-cert <path>", "PEM-encoded server certificate for mutual TLS. Self-signed is fine for local dev. Must be set together with --mtls-truststore + --mtls-key.")).addOption(new Option("--mtls-key <path>", "PEM-encoded server private key matching --mtls-cert. Must be set together with --mtls-truststore + --mtls-cert.")).addOption(new Option("--allow-unverified-sigv4", "Opt-in: allow AWS_IAM SigV4 requests that cannot be cryptographically verified (foreign access-key-id, OR no local AWS credentials configured) to pass through with a placeholder principalId. DEFAULT off — fail-closed so unauthenticated bypass is impossible against `event.requestContext.identity.accessKey`-trusting handler code. Use only in dev loops where you understand the risk.").default(false)).action(withErrorHandling(localStartApiCommand));
|
|
55101
55153
|
[
|
|
55102
55154
|
...commonOptions,
|
|
55103
55155
|
...appOptions,
|
|
@@ -59436,7 +59488,7 @@ function reorderArgs(argv) {
|
|
|
59436
59488
|
*/
|
|
59437
59489
|
async function main() {
|
|
59438
59490
|
const program = new Command();
|
|
59439
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
59491
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.159.1");
|
|
59440
59492
|
program.addCommand(createBootstrapCommand());
|
|
59441
59493
|
program.addCommand(createSynthCommand());
|
|
59442
59494
|
program.addCommand(createListCommand());
|