Skip to content

feat(disruption): executor Lambda entry + CDK construct — Phase B deployable (ADR-031) [#1419] - #1645

Closed
susumutomita wants to merge 3 commits into
feat/1419-executor-routefrom
feat/1419-executor-construct
Closed

susumutomita wants to merge 3 commits into
feat/1419-executor-routefrom
feat/1419-executor-construct

Conversation

@susumutomita

Copy link
Copy Markdown
Owner

Summary

The #1419 capstone: wires the tested executor modules into a deployable Lambda + its CDK construct. With this, ADR-031 Phase B is code-complete — the only thing left is make deploy + a target-account E2E (yours).

Top of the stack: #1639 → #1640 → #1641 → #1642 → #1643 (+ the execute.ts compose fix and #1644's shared assumeCompetitorRole, carried here so it composes; they dedupe when those merge). Base feat/1419-executor-route.

What it adds

  • handlers/disruption-executor-handler/index.ts — the real-deps entry (DI composition root, exactly like describe-stack-handler/index.ts). Constructs the SDK clients + the shared assumeCompetitorRole, wires claimExecution/resolveDeployment/sendDispatch/scheduleRevert, and exports the Lambda handler over routeDisruptionInvocation. (SDK imports baselined as a composition root, parity with the describe-stack / generic-scoring entries.)
  • disruption-executor-lambda.ts — the construct: NodejsFunction + an EventBridge rule on tenkacloud.disruptions + a scheduler execution role. Least-privilege IAM:
    • sts:AssumeRole only on arn:aws:iam::*:role/TenkaCloud-* (not *),
    • ssm:GetParameter + kms:Decrypt only for the tenant ExternalId (describe-stack pattern),
    • dynamodb:Query (GSI1) + dynamodb:PutItem (EXEC#),
    • scheduler:CreateSchedule + scoped iam:PassRole.
    • The destructive SendCommand/Invoke/UpdateStack are not on the executor's own role — they ride the assumed CompetitorDeployRole — pinned by a Template assertion test.
  • Wired into ProblemDeployBackendStack; the EventBridge-rule-count test goes 7→8.

Security shape

The executor's own IAM is minimal and Template-asserted; the destructive power is the pre-existing competitor-account CompetitorDeployRole (AdministratorAccess, consented at bootstrap), gated by operator-authenticated fire → problem-author action (validated by #1639/#32) → ExternalId-scoped AssumeRole → ADR-029-INV-2 auto-revert. No new IAM danger beyond the describe-stack cross-account pattern.

Test plan

  • 4 Template assertion tests: Lambda + wiring env; sts:AssumeRole scoped to TenkaCloud-*; the executor's own role has no SendCommand/Invoke/UpdateStack; the tenkacloud.disruptions rule + the scheduler-assumable revert role.
  • Full infra suite: 2442 pass (incl. the 7→8 rule-count update).
  • tsc --noEmit, biome, make harness (0 errors), check-no-conflicts, cdk synth exit 0 (the construct synthesizes in the real stack): all green.

Regression analysis

  • The new Lambda + rule are additive; action-less disruptions stay Phase A audit-only (the executor returns no_action), so existing disruption behavior is unchanged.
  • The only existing-resource delta is the EventBridge rule count (7→8, test updated) and the new construct in ProblemDeployBackendStack. cdk synth confirms the rest of the template is unchanged.
  • The composition fix (scheduleRevert(detail, …)) corrects a real defect where the orchestration dep didn't type-compose with the concrete scheduler — now verified end-to-end by the wiring + tsc.
  • The shared assumeCompetitorRole is behavior-preserving (describe-stack's 20 tests unchanged, from refactor(problem-deploy): extract shared assumeCompetitorRole (SOLID/DRY) [#1419] #1644).

Physical impact

CFn: CREATE — one new AWS::Lambda::Function (the executor), one AWS::Events::Rule (tenkacloud.disruptions → executor), two AWS::IAM::Roles (the executor's least-privilege role + the scheduler execution role) in ProblemDeployBackendStack. No table/capacity change (DynamoDbLowCapacity unaffected). NO-OP on all other stacks. The fault-injection path is inert until a problem declares an action and an operator fires it.

Relates #1419

susumutomita and others added 3 commits June 2, 2026 12:16
…mposes [#1419]

Integration fix surfaced while wiring the handler entry: ExecutorDeps.scheduleRevert
omitted `detail`, but the concrete scheduleRevert (#1642) needs it to build the
idempotent schedule name (EXEC# twin = requestId/teamId) and the revert invocation
payload. The dep is built once at module load, so detail must arrive at call time —
executeDisruptionAction now passes it: scheduleRevert(detail, revert, target, afterSeconds).

Without this the inject-time orchestration and the revert scheduler did not type-compose
in the real wiring. execute.test.ts updated to assert detail is forwarded.

Relates #1419

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…DRY) [#1419]

The cross-account AssumeRole-into-CompetitorDeployRole logic (with the #856/#1245
rotation-race ExternalId-mismatch retry + grace-fallback trace) lived inline in
describe-stack-handler and was near-duplicated in competitor-accounts/verify.ts +
participant SSO. Extract the canonical implementation to
handlers/shared/assume-competitor-role.ts so credential-path code has a single
audited home (consolidating security-critical auth = a security improvement, not
just dedup) and the upcoming disruption executor (#1419) can reuse it instead of
copying it.

Behavior-preserving: only caller-cosmetic bits are parameterized —
`sessionNamePrefix` (RoleSessionName) and `graceFallbackTraceEvent` (the operator
alarm key). describe-stack passes its exact prior values, so its trace event name
and session name are byte-identical. Verified by describe-stack's existing 20
tests (incl. the grace-fallback trace-name pin + retry/rethrow cases) passing
UNCHANGED, plus 9 new direct tests of the shared module (undefined/one-sided/
no-value/happy session-name/incomplete-creds/grace-fallback-fires-trace/
non-AccessDenied-rethrow/no-previous-version-rethrow + the retry predicate).

verify.ts / SSO keep their own variants for now (different deps/return shape) —
noted as a follow-up; this PR extracts the describe-stack path that the executor
reuses. Infra suite 2377 pass.

Relates #1419

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…loyable [#1419]

The #1419 capstone: wires the tested executor modules into a deployable Lambda and
its CDK construct. With this, ADR-031 Phase B is code-complete (modulo make deploy
+ a target-account E2E).

- handlers/disruption-executor-handler/index.ts: real-deps entry (DI composition
  root, like describe-stack-handler/index.ts). Constructs the SDK clients + the
  shared assumeCompetitorRole, wires claimExecution/resolveDeployment/sendDispatch/
  scheduleRevert, exports the Lambda handler over routeDisruptionInvocation. The
  SDK imports are baselined as a composition root (parity with describe-stack /
  generic-scoring entries).
- disruption-executor-lambda.ts: the construct. NodejsFunction + an EventBridge
  rule on tenkacloud.disruptions + a scheduler execution role. Least-privilege IAM:
  sts:AssumeRole only on TenkaCloud-* (not *), ssm:GetParameter + kms:Decrypt only
  for the tenant ExternalId (describe-stack pattern), dynamodb Query (GSI1) +
  PutItem (EXEC#), scheduler:CreateSchedule + scoped iam:PassRole. The destructive
  SendCommand/Invoke/UpdateStack are NOT on the executor's own role — they ride the
  assumed CompetitorDeployRole — pinned by a Template assertion test.
- wired into ProblemDeployBackendStack; the EventBridge-rule-count test goes 7→8.
- carries the execute.ts compose fix + the shared assumeCompetitorRole extraction
  (from #1640 / #1644) so the stack composes; they dedupe when those merge.

Verified: 4 Template assertion tests (Lambda+env / sts scope / no-destructive-own-IAM
/ rule+scheduler-role); full infra suite 2442 pass; tsc / biome / make harness
(0 errors) / check-no-conflicts / cdk synth (exit 0) all green.

Relates #1419

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fb28e0c4-3d43-4293-8c5a-47b481f84eeb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/1419-executor-construct

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Jun 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.22642% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.39%. Comparing base (587763b) to head (79265f0).

Files with missing lines Patch % Lines
...e/lib/problem-deploy/disruption-executor-lambda.ts 93.75% 0 Missing and 1 partial ⚠️
...m-deploy/handlers/shared/assume-competitor-role.ts 97.05% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@                    Coverage Diff                    @@
##           feat/1419-executor-route    #1645   +/-   ##
=========================================================
  Coverage                     93.39%   93.39%           
=========================================================
  Files                           397      399    +2     
  Lines                         10867    10885   +18     
  Branches                       3335     3337    +2     
=========================================================
+ Hits                          10149    10166   +17     
  Misses                          222      222           
- Partials                        496      497    +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant