Skip to content

Commit 3cd5405

Browse files
authored
test(integ): add deployment-events integ for cdkd events / #808 (+ record regression sweep) (#829)
1 parent fae5cb7 commit 3cd5405

16 files changed

Lines changed: 555 additions & 14 deletions

docs/_generated/integ-coverage.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2896,6 +2896,7 @@
28962896
"bench-sdk",
28972897
"cloudwatch",
28982898
"composite-stack",
2899+
"deployment-events",
28992900
"drift-revert",
29002901
"event-driven",
29012902
"export",
@@ -2918,6 +2919,9 @@
29182919
"l2",
29192920
"literal"
29202921
],
2922+
"deployment-events": [
2923+
"l2"
2924+
],
29212925
"drift-revert": [
29222926
"l2"
29232927
],
@@ -3042,6 +3046,7 @@
30423046
"cross-region-state-bucket",
30433047
"cross-stack-references",
30443048
"deletion-policy-retain",
3049+
"deployment-events",
30453050
"export-nested-stack",
30463051
"import-nested-stack",
30473052
"import-value-strong-ref",
@@ -3080,6 +3085,9 @@
30803085
"l2",
30813086
"literal"
30823087
],
3088+
"deployment-events": [
3089+
"l2"
3090+
],
30833091
"export-nested-stack": [
30843092
"l2",
30853093
"literal"

docs/_generated/integ-last-run.tsv

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
dynamodb-streams 2026-06-01T21:12:13Z PASS standard rc ok, orph clean
33
composite-stack 2026-06-01T21:12:13Z PASS standard rc ok, orph clean
44
nested-stack 2026-06-01T21:12:13Z PASS standard rc ok, orph clean
5-
cc-api-fallback 2026-06-01T21:12:13Z PASS verify.sh rc ok, orph clean
65
cc-api-fallback-transitions 2026-06-01T21:12:13Z PASS 122 verify.sh rc ok, orph clean
7-
drift-revert 2026-06-01T21:12:13Z PASS 92 verify.sh rc ok, orph clean
86
recreate-via-sdk-provider 2026-06-01T21:12:13Z PASS 79 verify.sh rc ok, orph clean
97
recreate-via-cc-api 2026-06-01T21:12:13Z PASS 97 verify.sh rc ok, orph clean
108
recreate-mixed-direction 2026-06-01T21:12:13Z PASS 92 verify.sh rc ok, orph clean
@@ -13,11 +11,9 @@ dynamodb-globaltable 2026-06-01T21:12:13Z PASS 159 verify.sh rc ok, orph clean
1311
s3-tables 2026-06-01T21:12:13Z PASS 31 verify.sh rc ok, orph clean
1412
iam-managed-policy 2026-06-01T21:12:13Z PASS 20 standard rc ok, orph clean
1513
eventbridge 2026-06-01T21:12:13Z PASS 67 verify.sh rc ok, orph clean
16-
export 2026-06-01T21:12:13Z PASS 252 verify.sh rc ok, orph clean
1714
migrate-from-cfn 2026-06-01T21:12:13Z PASS 89 standard rc ok, orph clean
1815
nested-stack-deep 2026-06-01T21:12:13Z PASS 48 verify.sh rc ok, orph clean
1916
apigateway 2026-06-01T21:12:13Z PASS 45 verify.sh rc ok, orph clean
20-
multi-stack-deps 2026-06-01T21:31:46Z PASS standard F1 fix verified: deploy/destroy --all clean (cross-stack ordering)
2117
import-value-strong-ref 2026-06-02T02:13:34Z PASS verify.sh F3 fixed: version-agnostic schema assertion (>= 4); deploy+strong-ref+destroy clean
2218
vpc-lambda-cr-race 2026-06-02T07:34:17Z PASS standard coverage batch: VPC+Lambda+CR; withRetry handled role-assume propagation, deploy ok, 9 deleted 0 errors 0 orphans
2319
event-driven 2026-06-02T07:36:47Z PASS standard coverage batch: 19 deleted 0 errors 0 orphans
@@ -108,19 +104,24 @@ dynamodb-ondemand 2026-06-09T17:02:56Z PASS 70 verify.sh #609: ResourcePolicy/Ki
108104
ec2-instance 2026-06-09T17:10:25Z PASS 105 verify.sh #609 security slice: DisableApiTermination/MetadataOptions/Monitoring/EbsOptimized/CreditSpecification asserted; destroy 0 err
109105
rds-dbinstance-backfill 2026-06-09T18:23:15Z PASS 561 verify.sh #609 DBInstance security props (MonitoringRoleArn/Interval/IAMauth/KmsKeyId/MasterUserSecret) asserted; destroy 0 err
110106
rds-aurora 2026-06-10T01:31:45Z PASS 3000 verify.sh #794 verify: MonitoringRoleArn cluster create survived IAM-race via retry; +#609 cluster props; destroy 23/0 err
111-
bench-cdk-sample 2026-06-10T01:42:03Z PASS 480 standard regression net post #609 batch (replacement-rules.ts shared change): 37 deleted/2 RETAIN logGroups/0 err; clean
112-
multi-resource 2026-06-10T03:34:10Z PASS standard regression check post-#796; 17 created/17 deleted 0 errors 0 orphans
113-
remove-protection 2026-06-10T05:14:24Z PASS verify.sh #798 re-verify delegated ASG target; instance terminated 0 orphans
114107
stepfunctions 2026-06-10T10:20:55Z PASS standard coverage spread; 5 deleted 0 errors (SM DELETING self-resolved)
115108
route53 2026-06-10T10:20:55Z PASS verify.sh coverage spread; 6 deleted 0 errors
116-
custom-resource-provider 2026-06-10T10:20:55Z PASS standard coverage spread; 17 deleted 0 errors
117-
cross-stack-references 2026-06-10T10:20:55Z PASS standard coverage spread; 2 stacks 0 errors
118109
kms-encryption 2026-06-10T10:20:55Z PASS standard coverage spread; 3 deleted 0 errors
119110
sns-sqs-event 2026-06-10T10:20:55Z PASS verify.sh coverage spread; 19 deleted 0 errors
120111
vpc-lambda 2026-06-10T10:20:55Z PASS standard coverage spread; 16 deleted 0 errors, VPC/ENI clean
121-
drift-revert-vpc 2026-06-11T06:05:51Z PASS verify.sh order-normalize backport; 21 deleted 0 err 0 orphan
122112
microservices 2026-06-13T06:25:57Z PASS 34 standard #816 SIGINT handler; normal destroy unaffected; 19 deleted 0 err 0 orphan
123113
lambda 2026-06-13T04:41:51Z PASS 76 verify.sh #808 broad integ + cdkd events live-tested (deploy+destroy runs persisted); 9 deleted 0 err
124114
vpc-nat-gateway 2026-06-13T05:15:45Z PASS 328 standard #817 IGW/NAT delete-order; 21 deleted 0 err 0 orphan (NAT before IGW/EIP)
125115
ecs-fargate 2026-06-13T06:22:14Z PASS 369 verify.sh #815 EFS efsVolumeConfiguration camelCase reached AWS; 23 deleted 0 err
126116
cross-region-state-bucket 2026-06-13T07:10:46Z PASS 34 verify.sh #827 shared bucket-region helper; behavior preserved; 1 deleted 0 err, temp bucket cleaned
117+
bench-cdk-sample 2026-06-13T09:16:21Z PASS 529 standard regression sweep; 0 err 0 orphan
118+
multi-resource 2026-06-13T09:16:21Z PASS 75 standard regression sweep; 0 err 0 orphan
119+
multi-stack-deps 2026-06-13T09:16:21Z PASS 63 standard regression sweep 3-stack; 0 err 0 orphan
120+
drift-revert 2026-06-13T09:16:21Z PASS 89 verify.sh regression sweep; 0 err 0 orphan
121+
drift-revert-vpc 2026-06-13T09:16:21Z PASS 228 verify.sh regression sweep; 0 err 0 orphan
122+
remove-protection 2026-06-13T09:16:21Z PASS 1267 verify.sh regression sweep; 0 err 0 orphan
123+
export 2026-06-13T09:16:21Z PASS 248 verify.sh regression sweep; 0 err 0 orphan
124+
cross-stack-references 2026-06-13T09:16:21Z PASS 26 standard regression sweep 2-stack; 0 err 0 orphan
125+
cc-api-fallback 2026-06-13T09:16:21Z PASS 57 verify.sh regression sweep; 0 err 0 orphan
126+
custom-resource-provider 2026-06-13T09:16:21Z PASS 290 standard regression sweep; 0 err 0 orphan
127+
deployment-events 2026-06-13T09:16:21Z PASS 34 verify.sh #808 events sidecar + cdkd events + no-secrets + survives-destroy; 2 deleted 0 err

docs/_generated/scenario-coverage.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
"tag": "deletion-policy-retain",
2929
"description": "DeletionPolicy: Retain skip on destroy (schema v5 recorded value wins over template)."
3030
},
31+
{
32+
"tag": "deployment-events",
33+
"description": "Structured deployment events to S3 + `cdkd events` command (issue #808): per-run `deployments/{runId}.jsonl` + `index.json` (separate key family from state.json, no schema bump), events survive `cdkd destroy`, and carry error + metadata ONLY (no resource properties / secrets)."
34+
},
3135
{
3236
"tag": "drift-revert-roundtrip",
3337
"description": "cdkd drift detection + `--revert` round-trip via each provider.update()."
@@ -323,6 +327,13 @@
323327
"deletion-policy-retain"
324328
]
325329
},
330+
{
331+
"name": "deployment-events",
332+
"annotated": true,
333+
"scenarios": [
334+
"deployment-events"
335+
]
336+
},
326337
{
327338
"name": "diff-intrinsic-target-change",
328339
"annotated": true,
@@ -976,6 +987,13 @@
976987
"deletion-policy-retain"
977988
]
978989
},
990+
{
991+
"scenario": "deployment-events",
992+
"description": "Structured deployment events to S3 + `cdkd events` command (issue #808): per-run `deployments/{runId}.jsonl` + `index.json` (separate key family from state.json, no schema bump), events survive `cdkd destroy`, and carry error + metadata ONLY (no resource properties / secrets).",
993+
"fixtures": [
994+
"deployment-events"
995+
]
996+
},
979997
{
980998
"scenario": "drift-revert-roundtrip",
981999
"description": "cdkd drift detection + `--revert` round-trip via each provider.update().",

docs/changelog-cdkd.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ The CLAUDE.md `## Known Limitations` section retains the load-bearing summary
4545
- **`cdkd events` no longer mislabels a successful run as `FAILED` in the index-fallback** (user-visible correctness fix). When `deployments/index.json` is missing / corrupt, `DeploymentEventsReader.listRuns` rebuilds the run listing by enumerating the `{runId}.jsonl` keys. It previously stamped every fallback row `result: 'FAILED'` — so a run that genuinely SUCCEEDED but whose `index.json` write lost the last-writer-wins race showed as `FAILED`. The fallback now reads each run's JSONL and derives the true terminal result (command / cdkd version / timestamps / event count too) from the run's last `RUN_FINISHED` event; a run with no terminal `RUN_FINISHED` (interrupted, or index write lost) reports the new `result: 'UNKNOWN'` (added to a `DeploymentRunSummaryResult = DeploymentRunResult | 'UNKNOWN'` type used only on the summary; the run-level emitters still only ever produce `SUCCEEDED` / `FAILED`) and is colored neutrally in the run listing rather than red.
4646
- **Run-level bracket extracted to `src/cli/commands/deployment-events-run.ts`** (`startRunRecorder` / `recordRunSucceeded` / `recordRunFailed`) so the `RUN_STARTED` / `RUN_FINISHED` + `--dry-run`-skips-recorder + `extractDeploymentEventError`-on-failure contract is directly unit-testable and shared by both `deploy.ts` and `destroy.ts` (behavior identical to the prior inline code).
4747
- Added tests: `tests/unit/types/deployment-events.test.ts` (`extractDeploymentEventError` deepest-AWS-shaped-error extraction, bounded-depth-10 + cyclic-chain guard, non-Error inputs), `tests/unit/cli/destroy-runner-events.test.ts` (destroy-runner `RESOURCE_STARTED` / `SUCCEEDED` / `FAILED` + `RESOURCE_RETAINED` for a `DeletionPolicy: Retain` skip + no-recorder back-compat), `tests/unit/cli/deployment-events-run.test.ts` (run-level bracket: dry-run = no recorder, `RUN_STARTED` at create, success `RUN_FINISHED` with counts, failure `RUN_FINISHED` with `result: 'FAILED'` + error metadata, no-properties-leak), a `ROLLBACK_RESOURCE_FAILED` case in `deployment-events-emission.test.ts`, the no-FAILED-fabrication + `UNKNOWN`-on-torn cases in `deployment-events-store.test.ts`, and a `listRawKeys` multi-page `ContinuationToken` pagination case in `tests/unit/state/s3-state-backend.test.ts`.
48+
- **Integration coverage (follow-up PR, refs #808)**: new `tests/integration/deployment-events/` fixture — a tiny `CdkdDeploymentEventsExample` stack (an `AWS::SNS::Topic` + an `AWS::SSM::Parameter`, no VPC / NAT, deploy+destroy in well under a minute) with a `verify.sh` that exercises the feature end-to-end against real AWS: deploy writes the `deployments/{runId}.jsonl` + `index.json` sidecar; `cdkd events <stack> --stack-region <r>` lists a `deploy` run as `SUCCEEDED`; `--format json` is valid JSON carrying `RUN_STARTED` / `RUN_FINISHED` + at least one `RESOURCE_*` event for the topic / parameter; the SSM parameter's marker value (`events-integ-secret-value`) does NOT appear anywhere in the events JSON (the no-secrets guarantee); after `cdkd destroy --force`, `state.json` is gone but the `deployments/` sidecar survives (now carrying the destroy run too) and `cdkd events` lists BOTH a deploy and a destroy run; the fixture removes the events sidecar at the end (and on the failure path via an EXIT trap). New scenario tag `deployment-events`.
4849
- ✅ **`LockManager` resolves the state bucket's actual region before lock operations (issue [#803](https://github.com/go-to-k/cdkd/issues/803))** — `src/state/lock-manager.ts`. PR #60 taught `S3StateBackend` to resolve a cross-region state bucket's real region via `GetBucketLocation` and rebuild its S3 client, but `LockManager` was left out: it kept using the raw client pinned to the CLI's base region (`AWS_REGION` / fallback `us-east-1`), so against a bucket in another region every state read/write succeeded while every lock acquisition failed with S3's 301 PermanentRedirect ("must be addressed using the specified endpoint") — contradicting the documented "the state bucket can live in any AWS region" guarantee. `LockManager` now has its own `ensureClientForBucket()` (awaited at the top of `acquireLock` / `getLockInfo` / `releaseLock` / `deleteLock`) mirroring the state backend's pattern with two deliberate differences: the replacement client reuses the original client's resolved credentials provider (so `--profile` / static credentials carry over without threading client options through the 8 `new LockManager(...)` call sites), and the original client is NOT destroyed (it is the shared `AwsClients.s3` instance other components still hold). `resolveBucketRegion` caches per bucket name, so when the state backend already resolved the same bucket the lock path adds no extra `GetBucketLocation` call. The fix is contained entirely inside `LockManager` — none of the 8 call sites changed. Unit tests: region-mismatch rebuild (pre-fix 301 path — the PutObject goes through the rebuilt client), same-region no-rebuild, single resolution across multiple lock ops, and resolver receives the caller's credentials + fallback region. The `cross-region-state-bucket` integ fixture is now AUTOMATED: its new `verify.sh` creates a temporary uniquely-named state bucket in `us-west-2`, runs deploy / state ls / destroy with `AWS_REGION=us-east-1`, asserts state.json written + lock.json released in the cross-region bucket, and deletes the bucket at the end (EXIT trap covers failure paths) — previously the fixture was manual-only and its 2026-06-02 ledger PASS ran against the default same-region bucket, never exercising the scenario it is named after. Docs: `state-management.md` (State Bucket Region + Lock Mechanism), `troubleshooting.md` (lock-path 301 symptom + fix note).
4950

5051
**Recently Implemented** (2026-06-10):

0 commit comments

Comments
 (0)